aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorGreg KH <greg@press.(none)>2005-06-27 22:07:56 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2005-06-27 22:07:56 -0700
commit8644d2a42bdba2d513f71c07eaf1b6f9b718b8eb (patch)
treec43b6c2fdf1b68b66906a2de69446dcec0f9af6b /drivers
parent1cde8a16815bd85c8137d1ea556398983c597c11 (diff)
parent99f95e5286df2f69edab8a04c7080d986ee4233b (diff)
downloadlinux-8644d2a42bdba2d513f71c07eaf1b6f9b718b8eb.tar.gz
Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/as-iosched.c5
-rw-r--r--drivers/block/cciss.c17
-rw-r--r--drivers/block/cfq-iosched.c2081
-rw-r--r--drivers/block/deadline-iosched.c3
-rw-r--r--drivers/block/elevator.c9
-rw-r--r--drivers/block/ll_rw_blk.c59
-rw-r--r--drivers/block/swim3.c10
-rw-r--r--drivers/block/sx8.c7
-rw-r--r--drivers/bluetooth/bluecard_cs.c9
-rw-r--r--drivers/bluetooth/bt3c_cs.c7
-rw-r--r--drivers/bluetooth/btuart_cs.c7
-rw-r--r--drivers/bluetooth/dtl1_cs.c8
-rw-r--r--drivers/char/misc.c3
-rw-r--r--drivers/char/pcmcia/synclink_cs.c9
-rw-r--r--drivers/ide/Kconfig6
-rw-r--r--drivers/ide/ide-disk.c4
-rw-r--r--drivers/ide/ide-dma.c1
-rw-r--r--drivers/ide/ide-iops.c3
-rw-r--r--drivers/ide/legacy/ide-cs.c35
-rw-r--r--drivers/ide/pci/Makefile1
-rw-r--r--drivers/ide/pci/generic.c73
-rw-r--r--drivers/ide/pci/hpt366.c470
-rw-r--r--drivers/ide/pci/it821x.c812
-rw-r--r--drivers/ide/pci/serverworks.c10
-rw-r--r--drivers/ide/ppc/pmac.c8
-rw-r--r--drivers/ieee1394/ohci1394.c10
-rw-r--r--drivers/infiniband/core/packer.c4
-rw-r--r--drivers/infiniband/core/sa_query.c18
-rw-r--r--drivers/infiniband/hw/mthca/mthca_av.c1
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c531
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.h48
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cq.c101
-rw-r--r--drivers/infiniband/hw/mthca/mthca_dev.h12
-rw-r--r--drivers/infiniband/hw/mthca/mthca_doorbell.h1
-rw-r--r--drivers/infiniband/hw/mthca/mthca_eq.c58
-rw-r--r--drivers/infiniband/hw/mthca/mthca_main.c32
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mcg.c63
-rw-r--r--drivers/infiniband/hw/mthca/mthca_memfree.c10
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mr.c367
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c4
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.h14
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c139
-rw-r--r--drivers/input/evdev.c407
-rw-r--r--drivers/input/gameport/Kconfig14
-rw-r--r--drivers/input/gameport/Makefile2
-rw-r--r--drivers/input/gameport/cs461x.c322
-rw-r--r--drivers/input/gameport/gameport.c31
-rw-r--r--drivers/input/gameport/ns558.c12
-rw-r--r--drivers/input/gameport/vortex.c186
-rw-r--r--drivers/input/input.c37
-rw-r--r--drivers/input/joydev.c116
-rw-r--r--drivers/input/joystick/a3d.c2
-rw-r--r--drivers/input/joystick/adi.c4
-rw-r--r--drivers/input/joystick/amijoy.c29
-rw-r--r--drivers/input/joystick/db9.c17
-rw-r--r--drivers/input/joystick/gamecon.c29
-rw-r--r--drivers/input/joystick/gf2k.c2
-rw-r--r--drivers/input/joystick/grip_mp.c2
-rw-r--r--drivers/input/joystick/iforce/iforce-main.c1
-rw-r--r--drivers/input/joystick/iforce/iforce-usb.c1
-rw-r--r--drivers/input/joystick/spaceball.c4
-rw-r--r--drivers/input/joystick/spaceorb.c2
-rw-r--r--drivers/input/joystick/tmdc.c2
-rw-r--r--drivers/input/joystick/turbografx.c35
-rw-r--r--drivers/input/keyboard/atkbd.c6
-rw-r--r--drivers/input/keyboard/corgikbd.c6
-rw-r--r--drivers/input/keyboard/lkkbd.c8
-rw-r--r--drivers/input/keyboard/locomokbd.c28
-rw-r--r--drivers/input/keyboard/maple_keyb.c22
-rw-r--r--drivers/input/misc/uinput.c6
-rw-r--r--drivers/input/mouse/Makefile2
-rw-r--r--drivers/input/mouse/alps.c52
-rw-r--r--drivers/input/mouse/amimouse.c8
-rw-r--r--drivers/input/mouse/inport.c38
-rw-r--r--drivers/input/mouse/lifebook.c134
-rw-r--r--drivers/input/mouse/lifebook.h17
-rw-r--r--drivers/input/mouse/logibm.c17
-rw-r--r--drivers/input/mouse/maplemouse.c75
-rw-r--r--drivers/input/mouse/pc110pad.c21
-rw-r--r--drivers/input/mouse/psmouse-base.c351
-rw-r--r--drivers/input/mouse/psmouse.h4
-rw-r--r--drivers/input/mouse/rpcmouse.c2
-rw-r--r--drivers/input/mouse/vsxxxaa.c4
-rw-r--r--drivers/input/mousedev.c8
-rw-r--r--drivers/input/serio/libps2.c136
-rw-r--r--drivers/input/serio/serio.c89
-rw-r--r--drivers/input/touchscreen/elo.c2
-rw-r--r--drivers/input/touchscreen/h3600_ts_input.c180
-rw-r--r--drivers/input/touchscreen/mk712.c21
-rw-r--r--drivers/isdn/hardware/avm/avm_cs.c9
-rw-r--r--drivers/isdn/hisax/avma1_cs.c8
-rw-r--r--drivers/isdn/hisax/elsa_cs.c8
-rw-r--r--drivers/isdn/hisax/sedlbauer_cs.c13
-rw-r--r--drivers/isdn/hisax/teles_cs.c7
-rw-r--r--drivers/macintosh/Kconfig42
-rw-r--r--drivers/macintosh/Makefile3
-rw-r--r--drivers/macintosh/adb.c10
-rw-r--r--drivers/macintosh/macserial.c3036
-rw-r--r--drivers/macintosh/macserial.h461
-rw-r--r--drivers/macintosh/via-pmu.c78
-rw-r--r--drivers/media/video/Kconfig2
-rw-r--r--drivers/mtd/maps/Kconfig10
-rw-r--r--drivers/mtd/maps/pcmciamtd.c29
-rw-r--r--drivers/net/3c523.c1
-rw-r--r--drivers/net/Kconfig2
-rw-r--r--drivers/net/b44.c3
-rw-r--r--drivers/net/cs89x0.c40
-rw-r--r--drivers/net/cs89x0.h2
-rw-r--r--drivers/net/e100.c25
-rw-r--r--drivers/net/e1000/e1000.h4
-rw-r--r--drivers/net/e1000/e1000_ethtool.c131
-rw-r--r--drivers/net/e1000/e1000_hw.c23
-rw-r--r--drivers/net/e1000/e1000_hw.h1
-rw-r--r--drivers/net/e1000/e1000_main.c111
-rw-r--r--drivers/net/forcedeth.c53
-rw-r--r--drivers/net/gianfar.c652
-rw-r--r--drivers/net/gianfar.h363
-rw-r--r--drivers/net/gianfar_ethtool.c277
-rw-r--r--drivers/net/pcmcia/3c574_cs.c8
-rw-r--r--drivers/net/pcmcia/3c589_cs.c12
-rw-r--r--drivers/net/pcmcia/axnet_cs.c29
-rw-r--r--drivers/net/pcmcia/com20020_cs.c7
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c30
-rw-r--r--drivers/net/pcmcia/ibmtr_cs.c8
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c8
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c203
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c33
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c28
-rw-r--r--drivers/net/pcnet32.c2
-rw-r--r--drivers/net/sb1000.c14
-rw-r--r--drivers/net/skfp/Makefile4
-rw-r--r--drivers/net/skfp/drvfbi.c222
-rw-r--r--drivers/net/skfp/ess.c4
-rw-r--r--drivers/net/skfp/fplustm.c70
-rw-r--r--drivers/net/skfp/h/cmtdef.h7
-rw-r--r--drivers/net/skfp/h/hwmtm.h25
-rw-r--r--drivers/net/skfp/hwmtm.c34
-rw-r--r--drivers/net/skfp/pcmplc.c7
-rw-r--r--drivers/net/skfp/pmf.c11
-rw-r--r--drivers/net/skfp/skfddi.c1
-rw-r--r--drivers/net/skfp/smt.c46
-rw-r--r--drivers/net/skfp/smtdef.c5
-rw-r--r--drivers/net/skfp/smtparse.c467
-rw-r--r--drivers/net/smc91x.c43
-rw-r--r--drivers/net/tokenring/lanstreamer.c6
-rw-r--r--drivers/net/tulip/tulip_core.c44
-rw-r--r--drivers/net/via-rhine.c6
-rw-r--r--drivers/net/wan/farsync.c1
-rw-r--r--drivers/net/wireless/airo.c2
-rw-r--r--drivers/net/wireless/airo_cs.c10
-rw-r--r--drivers/net/wireless/atmel_cs.c22
-rw-r--r--drivers/net/wireless/netwave_cs.c7
-rw-r--r--drivers/net/wireless/orinoco.c2465
-rw-r--r--drivers/net/wireless/orinoco.h30
-rw-r--r--drivers/net/wireless/orinoco_cs.c51
-rw-r--r--drivers/net/wireless/prism54/isl_38xx.c6
-rw-r--r--drivers/net/wireless/ray_cs.c7
-rw-r--r--drivers/net/wireless/wavelan_cs.c10
-rw-r--r--drivers/net/wireless/wl3501_cs.c7
-rw-r--r--drivers/parport/parport_cs.c9
-rw-r--r--drivers/pcmcia/Kconfig43
-rw-r--r--drivers/pcmcia/Makefile3
-rw-r--r--drivers/pcmcia/cistpl.c28
-rw-r--r--drivers/pcmcia/cs.c1164
-rw-r--r--drivers/pcmcia/cs_internal.h13
-rw-r--r--drivers/pcmcia/ds.c1255
-rw-r--r--drivers/pcmcia/ds_internal.h21
-rw-r--r--drivers/pcmcia/i82365.c23
-rw-r--r--drivers/pcmcia/pcmcia_compat.c34
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c786
-rw-r--r--drivers/pcmcia/pcmcia_resource.c998
-rw-r--r--drivers/pcmcia/rsrc_mgr.c11
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c170
-rw-r--r--drivers/pcmcia/socket_sysfs.c166
-rw-r--r--drivers/pcmcia/yenta_socket.c6
-rw-r--r--drivers/scsi/libata-scsi.c16
-rw-r--r--drivers/scsi/pcmcia/aha152x_stub.c11
-rw-r--r--drivers/scsi/pcmcia/fdomain_stub.c10
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c13
-rw-r--r--drivers/scsi/pcmcia/qlogic_stub.c22
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c9
-rw-r--r--drivers/serial/68328serial.c17
-rw-r--r--drivers/serial/8250.c25
-rw-r--r--drivers/serial/8250_accent.c47
-rw-r--r--drivers/serial/8250_boca.c61
-rw-r--r--drivers/serial/8250_fourport.c53
-rw-r--r--drivers/serial/8250_hub6.c58
-rw-r--r--drivers/serial/8250_mca.c64
-rw-r--r--drivers/serial/Kconfig75
-rw-r--r--drivers/serial/Makefile5
-rw-r--r--drivers/serial/serial_cs.c106
-rw-r--r--drivers/telephony/ixj_pcmcia.c7
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/atm/Kconfig50
-rw-r--r--drivers/usb/atm/Makefile7
-rw-r--r--drivers/usb/atm/cxacru.c878
-rw-r--r--drivers/usb/atm/speedtch.c1085
-rw-r--r--drivers/usb/atm/usb_atm.c1188
-rw-r--r--drivers/usb/atm/usb_atm.h176
-rw-r--r--drivers/usb/atm/usbatm.c1230
-rw-r--r--drivers/usb/atm/usbatm.h184
-rw-r--r--drivers/usb/atm/xusbatm.c196
-rw-r--r--drivers/usb/class/cdc-acm.c209
-rw-r--r--drivers/usb/class/cdc-acm.h25
-rw-r--r--drivers/usb/class/usblp.c3
-rw-r--r--drivers/usb/core/devio.c6
-rw-r--r--drivers/usb/core/hcd.c279
-rw-r--r--drivers/usb/core/hcd.h19
-rw-r--r--drivers/usb/core/hub.c19
-rw-r--r--drivers/usb/core/hub.h11
-rw-r--r--drivers/usb/gadget/Kconfig11
-rw-r--r--drivers/usb/gadget/dummy_hcd.c745
-rw-r--r--drivers/usb/gadget/ether.c353
-rw-r--r--drivers/usb/gadget/file_storage.c61
-rw-r--r--drivers/usb/gadget/goku_udc.c28
-rw-r--r--drivers/usb/gadget/inode.c12
-rw-r--r--drivers/usb/gadget/ndis.h14
-rw-r--r--drivers/usb/gadget/net2280.c51
-rw-r--r--drivers/usb/gadget/omap_udc.c301
-rw-r--r--drivers/usb/gadget/omap_udc.h4
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c43
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.h10
-rw-r--r--drivers/usb/gadget/rndis.c515
-rw-r--r--drivers/usb/gadget/rndis.h95
-rw-r--r--drivers/usb/gadget/serial.c36
-rw-r--r--drivers/usb/gadget/zero.c6
-rw-r--r--drivers/usb/host/Kconfig13
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-dbg.c59
-rw-r--r--drivers/usb/host/ehci-hcd.c58
-rw-r--r--drivers/usb/host/ehci-hub.c2
-rw-r--r--drivers/usb/host/ehci-q.c2
-rw-r--r--drivers/usb/host/ehci-sched.c17
-rw-r--r--drivers/usb/host/isp116x-hcd.c1875
-rw-r--r--drivers/usb/host/isp116x.h583
-rw-r--r--drivers/usb/host/ohci-hcd.c58
-rw-r--r--drivers/usb/host/ohci-mem.c1
-rw-r--r--drivers/usb/host/ohci-omap.c4
-rw-r--r--drivers/usb/host/ohci-pci.c13
-rw-r--r--drivers/usb/host/ohci.h2
-rw-r--r--drivers/usb/host/sl811-hcd.c18
-rw-r--r--drivers/usb/host/sl811_cs.c21
-rw-r--r--drivers/usb/host/uhci-debug.c32
-rw-r--r--drivers/usb/host/uhci-hcd.c773
-rw-r--r--drivers/usb/host/uhci-hcd.h59
-rw-r--r--drivers/usb/host/uhci-hub.c83
-rw-r--r--drivers/usb/host/uhci-q.c58
-rw-r--r--drivers/usb/input/Kconfig24
-rw-r--r--drivers/usb/input/Makefile2
-rw-r--r--drivers/usb/input/acecad.c285
-rw-r--r--drivers/usb/input/aiptek.c32
-rw-r--r--drivers/usb/input/ati_remote.c248
-rw-r--r--drivers/usb/input/hid-core.c26
-rw-r--r--drivers/usb/input/hid-debug.h16
-rw-r--r--drivers/usb/input/hid-input.c16
-rw-r--r--drivers/usb/input/hid-lgff.c18
-rw-r--r--drivers/usb/input/hid.h18
-rw-r--r--drivers/usb/input/hiddev.c56
-rw-r--r--drivers/usb/input/itmtouch.c268
-rw-r--r--drivers/usb/input/kbtab.c17
-rw-r--r--drivers/usb/input/mtouchusb.c410
-rw-r--r--drivers/usb/input/powermate.c30
-rw-r--r--drivers/usb/input/touchkitusb.c11
-rw-r--r--drivers/usb/input/usbkbd.c29
-rw-r--r--drivers/usb/input/usbmouse.c31
-rw-r--r--drivers/usb/input/wacom.c398
-rw-r--r--drivers/usb/input/xpad.c75
-rw-r--r--drivers/usb/media/stv680.c8
-rw-r--r--drivers/usb/media/stv680.h5
-rw-r--r--drivers/usb/misc/idmouse.c149
-rw-r--r--drivers/usb/misc/usbtest.c60
-rw-r--r--drivers/usb/net/pegasus.c2
-rw-r--r--drivers/usb/net/pegasus.h2
-rw-r--r--drivers/usb/net/rtl8150.c2
-rw-r--r--drivers/usb/net/usbnet.c2
-rw-r--r--drivers/usb/net/zd1201.c41
-rw-r--r--drivers/usb/net/zd1201.h1
-rw-r--r--drivers/usb/serial/cyberjack.c19
-rw-r--r--drivers/usb/serial/generic.c24
-rw-r--r--drivers/usb/serial/ipaq.c5
-rw-r--r--drivers/usb/serial/ipw.c14
-rw-r--r--drivers/usb/serial/ir-usb.c16
-rw-r--r--drivers/usb/serial/keyspan_pda.c19
-rw-r--r--drivers/usb/serial/omninet.c17
-rw-r--r--drivers/usb/serial/safe_serial.c13
-rw-r--r--drivers/usb/serial/usb-serial.c1
-rw-r--r--drivers/usb/serial/usb-serial.h3
-rw-r--r--drivers/usb/storage/scsiglue.c54
-rw-r--r--drivers/usb/storage/scsiglue.h1
-rw-r--r--drivers/usb/storage/transport.c116
-rw-r--r--drivers/usb/storage/transport.h1
-rw-r--r--drivers/video/aty/aty128fb.c14
-rw-r--r--drivers/video/chipsfb.c176
293 files changed, 21047 insertions, 15611 deletions
diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c
index 3410b4d294b..91aeb678135 100644
--- a/drivers/block/as-iosched.c
+++ b/drivers/block/as-iosched.c
@@ -1806,7 +1806,8 @@ static void as_put_request(request_queue_t *q, struct request *rq)
rq->elevator_private = NULL;
}
-static int as_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+static int as_set_request(request_queue_t *q, struct request *rq,
+ struct bio *bio, int gfp_mask)
{
struct as_data *ad = q->elevator->elevator_data;
struct as_rq *arq = mempool_alloc(ad->arq_pool, gfp_mask);
@@ -1827,7 +1828,7 @@ static int as_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
return 1;
}
-static int as_may_queue(request_queue_t *q, int rw)
+static int as_may_queue(request_queue_t *q, int rw, struct bio *bio)
{
int ret = ELV_MQUEUE_MAY;
struct as_data *ad = q->elevator->elevator_data;
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index abde27027c0..653512b7757 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -1,6 +1,6 @@
/*
* Disk Array driver for HP SA 5xxx and 6xxx Controllers
- * Copyright 2000, 2002 Hewlett-Packard Development Company, L.P.
+ * Copyright 2000, 2005 Hewlett-Packard Development Company, L.P.
*
* 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
@@ -54,7 +54,7 @@
MODULE_AUTHOR("Hewlett-Packard Company");
MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.6");
MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
- " SA6i P600 P800 E400");
+ " SA6i P600 P800 E400 E300");
MODULE_LICENSE("GPL");
#include "cciss_cmd.h"
@@ -85,8 +85,10 @@ static const struct pci_device_id cciss_pci_device_id[] = {
0x103C, 0x3225, 0, 0, 0},
{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
0x103c, 0x3223, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
0x103c, 0x3231, 0, 0, 0},
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
+ 0x103c, 0x3233, 0, 0, 0},
{0,}
};
MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
@@ -110,6 +112,7 @@ static struct board_type products[] = {
{ 0x3225103C, "Smart Array P600", &SA5_access},
{ 0x3223103C, "Smart Array P800", &SA5_access},
{ 0x3231103C, "Smart Array E400", &SA5_access},
+ { 0x3233103C, "Smart Array E300", &SA5_access},
};
/* How long to wait (in millesconds) for board to go into simple mode */
@@ -635,6 +638,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
cciss_pci_info_struct pciinfo;
if (!arg) return -EINVAL;
+ pciinfo.domain = pci_domain_nr(host->pdev->bus);
pciinfo.bus = host->pdev->bus->number;
pciinfo.dev_fn = host->pdev->devfn;
pciinfo.board_id = host->board_id;
@@ -787,13 +791,6 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
luninfo.LunID = drv->LunID;
luninfo.num_opens = drv->usage_count;
luninfo.num_parts = 0;
- /* count partitions 1 to 15 with sizes > 0 */
- for (i = 0; i < MAX_PART - 1; i++) {
- if (!disk->part[i])
- continue;
- if (disk->part[i]->nr_sects != 0)
- luninfo.num_parts++;
- }
if (copy_to_user(argp, &luninfo,
sizeof(LogvolInfo_struct)))
return -EFAULT;
diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c
index 3ac47dde64d..de5746e38af 100644
--- a/drivers/block/cfq-iosched.c
+++ b/drivers/block/cfq-iosched.c
@@ -21,22 +21,34 @@
#include <linux/hash.h>
#include <linux/rbtree.h>
#include <linux/mempool.h>
-
-static unsigned long max_elapsed_crq;
-static unsigned long max_elapsed_dispatch;
+#include <linux/ioprio.h>
+#include <linux/writeback.h>
/*
* tunables
*/
static int cfq_quantum = 4; /* max queue in one round of service */
static int cfq_queued = 8; /* minimum rq allocate limit per-queue*/
-static int cfq_service = HZ; /* period over which service is avg */
-static int cfq_fifo_expire_r = HZ / 2; /* fifo timeout for sync requests */
-static int cfq_fifo_expire_w = 5 * HZ; /* fifo timeout for async requests */
-static int cfq_fifo_rate = HZ / 8; /* fifo expiry rate */
+static int cfq_fifo_expire[2] = { HZ / 4, HZ / 8 };
static int cfq_back_max = 16 * 1024; /* maximum backwards seek, in KiB */
static int cfq_back_penalty = 2; /* penalty of a backwards seek */
+static int cfq_slice_sync = HZ / 10;
+static int cfq_slice_async = HZ / 25;
+static int cfq_slice_async_rq = 2;
+static int cfq_slice_idle = HZ / 100;
+
+#define CFQ_IDLE_GRACE (HZ / 10)
+#define CFQ_SLICE_SCALE (5)
+
+#define CFQ_KEY_ASYNC (0)
+#define CFQ_KEY_ANY (0xffff)
+
+/*
+ * disable queueing at the driver/hardware level
+ */
+static int cfq_max_depth = 1;
+
/*
* for the hash of cfqq inside the cfqd
*/
@@ -55,6 +67,7 @@ static int cfq_back_penalty = 2; /* penalty of a backwards seek */
#define list_entry_hash(ptr) hlist_entry((ptr), struct cfq_rq, hash)
#define list_entry_cfqq(ptr) list_entry((ptr), struct cfq_queue, cfq_list)
+#define list_entry_fifo(ptr) list_entry((ptr), struct request, queuelist)
#define RQ_DATA(rq) (rq)->elevator_private
@@ -75,78 +88,110 @@ static int cfq_back_penalty = 2; /* penalty of a backwards seek */
#define rb_entry_crq(node) rb_entry((node), struct cfq_rq, rb_node)
#define rq_rb_key(rq) (rq)->sector
-/*
- * threshold for switching off non-tag accounting
- */
-#define CFQ_MAX_TAG (4)
-
-/*
- * sort key types and names
- */
-enum {
- CFQ_KEY_PGID,
- CFQ_KEY_TGID,
- CFQ_KEY_UID,
- CFQ_KEY_GID,
- CFQ_KEY_LAST,
-};
-
-static char *cfq_key_types[] = { "pgid", "tgid", "uid", "gid", NULL };
-
static kmem_cache_t *crq_pool;
static kmem_cache_t *cfq_pool;
static kmem_cache_t *cfq_ioc_pool;
+#define CFQ_PRIO_LISTS IOPRIO_BE_NR
+#define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE)
+#define cfq_class_be(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_BE)
+#define cfq_class_rt(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_RT)
+
+#define ASYNC (0)
+#define SYNC (1)
+
+#define cfq_cfqq_dispatched(cfqq) \
+ ((cfqq)->on_dispatch[ASYNC] + (cfqq)->on_dispatch[SYNC])
+
+#define cfq_cfqq_class_sync(cfqq) ((cfqq)->key != CFQ_KEY_ASYNC)
+
+#define cfq_cfqq_sync(cfqq) \
+ (cfq_cfqq_class_sync(cfqq) || (cfqq)->on_dispatch[SYNC])
+
+/*
+ * Per block device queue structure
+ */
struct cfq_data {
- struct list_head rr_list;
+ atomic_t ref;
+ request_queue_t *queue;
+
+ /*
+ * rr list of queues with requests and the count of them
+ */
+ struct list_head rr_list[CFQ_PRIO_LISTS];
+ struct list_head busy_rr;
+ struct list_head cur_rr;
+ struct list_head idle_rr;
+ unsigned int busy_queues;
+
+ /*
+ * non-ordered list of empty cfqq's
+ */
struct list_head empty_list;
+ /*
+ * cfqq lookup hash
+ */
struct hlist_head *cfq_hash;
- struct hlist_head *crq_hash;
- /* queues on rr_list (ie they have pending requests */
- unsigned int busy_queues;
+ /*
+ * global crq hash for all queues
+ */
+ struct hlist_head *crq_hash;
unsigned int max_queued;
- atomic_t ref;
+ mempool_t *crq_pool;
- int key_type;
+ int rq_in_driver;
- mempool_t *crq_pool;
+ /*
+ * schedule slice state info
+ */
+ /*
+ * idle window management
+ */
+ struct timer_list idle_slice_timer;
+ struct work_struct unplug_work;
- request_queue_t *queue;
+ struct cfq_queue *active_queue;
+ struct cfq_io_context *active_cic;
+ int cur_prio, cur_end_prio;
+ unsigned int dispatch_slice;
+
+ struct timer_list idle_class_timer;
sector_t last_sector;
+ unsigned long last_end_request;
- int rq_in_driver;
+ unsigned int rq_starved;
/*
* tunables, see top of file
*/
unsigned int cfq_quantum;
unsigned int cfq_queued;
- unsigned int cfq_fifo_expire_r;
- unsigned int cfq_fifo_expire_w;
- unsigned int cfq_fifo_batch_expire;
+ unsigned int cfq_fifo_expire[2];
unsigned int cfq_back_penalty;
unsigned int cfq_back_max;
- unsigned int find_best_crq;
-
- unsigned int cfq_tagged;
+ unsigned int cfq_slice[2];
+ unsigned int cfq_slice_async_rq;
+ unsigned int cfq_slice_idle;
+ unsigned int cfq_max_depth;
};
+/*
+ * Per process-grouping structure
+ */
struct cfq_queue {
/* reference count */
atomic_t ref;
/* parent cfq_data */
struct cfq_data *cfqd;
- /* hash of mergeable requests */
+ /* cfqq lookup hash */
struct hlist_node cfq_hash;
/* hash key */
- unsigned long key;
- /* whether queue is on rr (or empty) list */
- int on_rr;
+ unsigned int key;
/* on either rr or empty list of cfqd */
struct list_head cfq_list;
/* sorted list of pending requests */
@@ -158,21 +203,22 @@ struct cfq_queue {
/* currently allocated requests */
int allocated[2];
/* fifo list of requests in sort_list */
- struct list_head fifo[2];
- /* last time fifo expired */
- unsigned long last_fifo_expire;
+ struct list_head fifo;
- int key_type;
+ unsigned long slice_start;
+ unsigned long slice_end;
+ unsigned long slice_left;
+ unsigned long service_last;
- unsigned long service_start;
- unsigned long service_used;
+ /* number of requests that are on the dispatch list */
+ int on_dispatch[2];
- unsigned int max_rate;
+ /* io prio of this group */
+ unsigned short ioprio, org_ioprio;
+ unsigned short ioprio_class, org_ioprio_class;
- /* number of requests that have been handed to the driver */
- int in_flight;
- /* number of currently allocated requests */
- int alloc_limit[2];
+ /* various state flags, see below */
+ unsigned int flags;
};
struct cfq_rq {
@@ -184,42 +230,78 @@ struct cfq_rq {
struct cfq_queue *cfq_queue;
struct cfq_io_context *io_context;
- unsigned long service_start;
- unsigned long queue_start;
+ unsigned int crq_flags;
+};
+
+enum cfqq_state_flags {
+ CFQ_CFQQ_FLAG_on_rr = 0,
+ CFQ_CFQQ_FLAG_wait_request,
+ CFQ_CFQQ_FLAG_must_alloc,
+ CFQ_CFQQ_FLAG_must_alloc_slice,
+ CFQ_CFQQ_FLAG_must_dispatch,
+ CFQ_CFQQ_FLAG_fifo_expire,
+ CFQ_CFQQ_FLAG_idle_window,
+ CFQ_CFQQ_FLAG_prio_changed,
+ CFQ_CFQQ_FLAG_expired,
+};
- unsigned int in_flight : 1;
- unsigned int accounted : 1;
- unsigned int is_sync : 1;
- unsigned int is_write : 1;
+#define CFQ_CFQQ_FNS(name) \
+static inline void cfq_mark_cfqq_##name(struct cfq_queue *cfqq) \
+{ \
+ cfqq->flags |= (1 << CFQ_CFQQ_FLAG_##name); \
+} \
+static inline void cfq_clear_cfqq_##name(struct cfq_queue *cfqq) \
+{ \
+ cfqq->flags &= ~(1 << CFQ_CFQQ_FLAG_##name); \
+} \
+static inline int cfq_cfqq_##name(const struct cfq_queue *cfqq) \
+{ \
+ return (cfqq->flags & (1 << CFQ_CFQQ_FLAG_##name)) != 0; \
+}
+
+CFQ_CFQQ_FNS(on_rr);
+CFQ_CFQQ_FNS(wait_request);
+CFQ_CFQQ_FNS(must_alloc);
+CFQ_CFQQ_FNS(must_alloc_slice);
+CFQ_CFQQ_FNS(must_dispatch);
+CFQ_CFQQ_FNS(fifo_expire);
+CFQ_CFQQ_FNS(idle_window);
+CFQ_CFQQ_FNS(prio_changed);
+CFQ_CFQQ_FNS(expired);
+#undef CFQ_CFQQ_FNS
+
+enum cfq_rq_state_flags {
+ CFQ_CRQ_FLAG_in_flight = 0,
+ CFQ_CRQ_FLAG_in_driver,
+ CFQ_CRQ_FLAG_is_sync,
+ CFQ_CRQ_FLAG_requeued,
};
-static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned long);
+#define CFQ_CRQ_FNS(name) \
+static inline void cfq_mark_crq_##name(struct cfq_rq *crq) \
+{ \
+ crq->crq_flags |= (1 << CFQ_CRQ_FLAG_##name); \
+} \
+static inline void cfq_clear_crq_##name(struct cfq_rq *crq) \
+{ \
+ crq->crq_flags &= ~(1 << CFQ_CRQ_FLAG_##name); \
+} \
+static inline int cfq_crq_##name(const struct cfq_rq *crq) \
+{ \
+ return (crq->crq_flags & (1 << CFQ_CRQ_FLAG_##name)) != 0; \
+}
+
+CFQ_CRQ_FNS(in_flight);
+CFQ_CRQ_FNS(in_driver);
+CFQ_CRQ_FNS(is_sync);
+CFQ_CRQ_FNS(requeued);
+#undef CFQ_CRQ_FNS
+
+static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short);
static void cfq_dispatch_sort(request_queue_t *, struct cfq_rq *);
-static void cfq_update_next_crq(struct cfq_rq *);
static void cfq_put_cfqd(struct cfq_data *cfqd);
-/*
- * what the fairness is based on (ie how processes are grouped and
- * differentiated)
- */
-static inline unsigned long
-cfq_hash_key(struct cfq_data *cfqd, struct task_struct *tsk)
-{
- /*
- * optimize this so that ->key_type is the offset into the struct
- */
- switch (cfqd->key_type) {
- case CFQ_KEY_PGID:
- return process_group(tsk);
- default:
- case CFQ_KEY_TGID:
- return tsk->tgid;
- case CFQ_KEY_UID:
- return tsk->uid;
- case CFQ_KEY_GID:
- return tsk->gid;
- }
-}
+#define process_sync(tsk) ((tsk)->flags & PF_SYNCWRITE)
/*
* lots of deadline iosched dupes, can be abstracted later...
@@ -235,16 +317,12 @@ static void cfq_remove_merge_hints(request_queue_t *q, struct cfq_rq *crq)
if (q->last_merge == crq->request)
q->last_merge = NULL;
-
- cfq_update_next_crq(crq);
}
static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq)
{
const int hash_idx = CFQ_MHASH_FN(rq_hash_key(crq->request));
- BUG_ON(!hlist_unhashed(&crq->hash));
-
hlist_add_head(&crq->hash, &cfqd->crq_hash[hash_idx]);
}
@@ -257,8 +335,6 @@ static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset)
struct cfq_rq *crq = list_entry_hash(entry);
struct request *__rq = crq->request;
- BUG_ON(hlist_unhashed(&crq->hash));
-
if (!rq_mergeable(__rq)) {
cfq_del_crq_hash(crq);
continue;
@@ -271,6 +347,28 @@ static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset)
return NULL;
}
+static inline int cfq_pending_requests(struct cfq_data *cfqd)
+{
+ return !list_empty(&cfqd->queue->queue_head) || cfqd->busy_queues;
+}
+
+/*
+ * scheduler run of queue, if there are requests pending and no one in the
+ * driver that will restart queueing
+ */
+static inline void cfq_schedule_dispatch(struct cfq_data *cfqd)
+{
+ if (!cfqd->rq_in_driver && cfq_pending_requests(cfqd))
+ kblockd_schedule_work(&cfqd->unplug_work);
+}
+
+static int cfq_queue_empty(request_queue_t *q)
+{
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+
+ return !cfq_pending_requests(cfqd);
+}
+
/*
* Lifted from AS - choose which of crq1 and crq2 that is best served now.
* We choose the request that is closest to the head right now. Distance
@@ -287,36 +385,16 @@ cfq_choose_req(struct cfq_data *cfqd, struct cfq_rq *crq1, struct cfq_rq *crq2)
return crq2;
if (crq2 == NULL)
return crq1;
+ if (cfq_crq_requeued(crq1))
+ return crq1;
+ if (cfq_crq_requeued(crq2))
+ return crq2;
s1 = crq1->request->sector;
s2 = crq2->request->sector;
last = cfqd->last_sector;
-#if 0
- if (!list_empty(&cfqd->queue->queue_head)) {
- struct list_head *entry = &cfqd->queue->queue_head;
- unsigned long distance = ~0UL;
- struct request *rq;
-
- while ((entry = entry->prev) != &cfqd->queue->queue_head) {
- rq = list_entry_rq(entry);
-
- if (blk_barrier_rq(rq))
- break;
-
- if (distance < abs(s1 - rq->sector + rq->nr_sectors)) {
- distance = abs(s1 - rq->sector +rq->nr_sectors);
- last = rq->sector + rq->nr_sectors;
- }
- if (distance < abs(s2 - rq->sector + rq->nr_sectors)) {
- distance = abs(s2 - rq->sector +rq->nr_sectors);
- last = rq->sector + rq->nr_sectors;
- }
- }
- }
-#endif
-
/*
* by definition, 1KiB is 2 sectors
*/
@@ -377,11 +455,14 @@ cfq_find_next_crq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
struct cfq_rq *crq_next = NULL, *crq_prev = NULL;
struct rb_node *rbnext, *rbprev;
- if (!ON_RB(&last->rb_node))
- return NULL;
-
- if ((rbnext = rb_next(&last->rb_node)) == NULL)
+ rbnext = NULL;
+ if (ON_RB(&last->rb_node))
+ rbnext = rb_next(&last->rb_node);
+ if (!rbnext) {
rbnext = rb_first(&cfqq->sort_list);
+ if (rbnext == &last->rb_node)
+ rbnext = NULL;
+ }
rbprev = rb_prev(&last->rb_node);
@@ -401,67 +482,53 @@ static void cfq_update_next_crq(struct cfq_rq *crq)
cfqq->next_crq = cfq_find_next_crq(cfqq->cfqd, cfqq, crq);
}
-static int cfq_check_sort_rr_list(struct cfq_queue *cfqq)
+static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
{
- struct list_head *head = &cfqq->cfqd->rr_list;
- struct list_head *next, *prev;
-
- /*
- * list might still be ordered
- */
- next = cfqq->cfq_list.next;
- if (next != head) {
- struct cfq_queue *cnext = list_entry_cfqq(next);
+ struct cfq_data *cfqd = cfqq->cfqd;
+ struct list_head *list, *entry;
- if (cfqq->service_used > cnext->service_used)
- return 1;
- }
+ BUG_ON(!cfq_cfqq_on_rr(cfqq));
- prev = cfqq->cfq_list.prev;
- if (prev != head) {
- struct cfq_queue *cprev = list_entry_cfqq(prev);
+ list_del(&cfqq->cfq_list);
- if (cfqq->service_used < cprev->service_used)
- return 1;
+ if (cfq_class_rt(cfqq))
+ list = &cfqd->cur_rr;
+ else if (cfq_class_idle(cfqq))
+ list = &cfqd->idle_rr;
+ else {
+ /*
+ * if cfqq has requests in flight, don't allow it to be
+ * found in cfq_set_active_queue before it has finished them.
+ * this is done to increase fairness between a process that
+ * has lots of io pending vs one that only generates one
+ * sporadically or synchronously
+ */
+ if (cfq_cfqq_dispatched(cfqq))
+ list = &cfqd->busy_rr;
+ else
+ list = &cfqd->rr_list[cfqq->ioprio];
}
- return 0;
-}
-
-static void cfq_sort_rr_list(struct cfq_queue *cfqq, int new_queue)
-{
- struct list_head *entry = &cfqq->cfqd->rr_list;
-
- if (!cfqq->on_rr)
- return;
- if (!new_queue && !cfq_check_sort_rr_list(cfqq))
+ /*
+ * if queue was preempted, just add to front to be fair. busy_rr
+ * isn't sorted.
+ */
+ if (preempted || list == &cfqd->busy_rr) {
+ list_add(&cfqq->cfq_list, list);
return;
-
- list_del(&cfqq->cfq_list);
+ }
/*
- * sort by our mean service_used, sub-sort by in-flight requests
+ * sort by when queue was last serviced
*/
- while ((entry = entry->prev) != &cfqq->cfqd->rr_list) {
+ entry = list;
+ while ((entry = entry->prev) != list) {
struct cfq_queue *__cfqq = list_entry_cfqq(entry);
- if (cfqq->service_used > __cfqq->service_used)
+ if (!__cfqq->service_last)
+ break;
+ if (time_before(__cfqq->service_last, cfqq->service_last))
break;
- else if (cfqq->service_used == __cfqq->service_used) {
- struct list_head *prv;
-
- while ((prv = entry->prev) != &cfqq->cfqd->rr_list) {
- __cfqq = list_entry_cfqq(prv);
-
- WARN_ON(__cfqq->service_used > cfqq->service_used);
- if (cfqq->service_used != __cfqq->service_used)
- break;
- if (cfqq->in_flight > __cfqq->in_flight)
- break;
-
- entry = prv;
- }
- }
}
list_add(&cfqq->cfq_list, entry);
@@ -469,28 +536,24 @@ static void cfq_sort_rr_list(struct cfq_queue *cfqq, int new_queue)
/*
* add to busy list of queues for service, trying to be fair in ordering
- * the pending list according to requests serviced
+ * the pending list according to last request service
*/
static inline void
-cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq, int requeue)
{
- /*
- * it's currently on the empty list
- */
- cfqq->on_rr = 1;
+ BUG_ON(cfq_cfqq_on_rr(cfqq));
+ cfq_mark_cfqq_on_rr(cfqq);
cfqd->busy_queues++;
- if (time_after(jiffies, cfqq->service_start + cfq_service))
- cfqq->service_used >>= 3;
-
- cfq_sort_rr_list(cfqq, 1);
+ cfq_resort_rr_list(cfqq, requeue);
}
static inline void
cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
+ BUG_ON(!cfq_cfqq_on_rr(cfqq));
+ cfq_clear_cfqq_on_rr(cfqq);
list_move(&cfqq->cfq_list, &cfqd->empty_list);
- cfqq->on_rr = 0;
BUG_ON(!cfqd->busy_queues);
cfqd->busy_queues--;
@@ -505,16 +568,17 @@ static inline void cfq_del_crq_rb(struct cfq_rq *crq)
if (ON_RB(&crq->rb_node)) {
struct cfq_data *cfqd = cfqq->cfqd;
+ const int sync = cfq_crq_is_sync(crq);
- BUG_ON(!cfqq->queued[crq->is_sync]);
+ BUG_ON(!cfqq->queued[sync]);
+ cfqq->queued[sync]--;
cfq_update_next_crq(crq);
- cfqq->queued[crq->is_sync]--;
rb_erase(&crq->rb_node, &cfqq->sort_list);
RB_CLEAR_COLOR(&crq->rb_node);
- if (RB_EMPTY(&cfqq->sort_list) && cfqq->on_rr)
+ if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY(&cfqq->sort_list))
cfq_del_cfqq_rr(cfqd, cfqq);
}
}
@@ -550,7 +614,7 @@ static void cfq_add_crq_rb(struct cfq_rq *crq)
struct cfq_rq *__alias;
crq->rb_key = rq_rb_key(rq);
- cfqq->queued[crq->is_sync]++;
+ cfqq->queued[cfq_crq_is_sync(crq)]++;
/*
* looks a little odd, but the first insert might return an alias.
@@ -561,8 +625,8 @@ static void cfq_add_crq_rb(struct cfq_rq *crq)
rb_insert_color(&crq->rb_node, &cfqq->sort_list);
- if (!cfqq->on_rr)
- cfq_add_cfqq_rr(cfqd, cfqq);
+ if (!cfq_cfqq_on_rr(cfqq))
+ cfq_add_cfqq_rr(cfqd, cfqq, cfq_crq_requeued(crq));
/*
* check if this request is a better next-serve candidate
@@ -575,17 +639,16 @@ cfq_reposition_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq)
{
if (ON_RB(&crq->rb_node)) {
rb_erase(&crq->rb_node, &cfqq->sort_list);
- cfqq->queued[crq->is_sync]--;
+ cfqq->queued[cfq_crq_is_sync(crq)]--;
}
cfq_add_crq_rb(crq);
}
-static struct request *
-cfq_find_rq_rb(struct cfq_data *cfqd, sector_t sector)
+static struct request *cfq_find_rq_rb(struct cfq_data *cfqd, sector_t sector)
+
{
- const unsigned long key = cfq_hash_key(cfqd, current);
- struct cfq_queue *cfqq = cfq_find_cfq_hash(cfqd, key);
+ struct cfq_queue *cfqq = cfq_find_cfq_hash(cfqd, current->pid, CFQ_KEY_ANY);
struct rb_node *n;
if (!cfqq)
@@ -609,20 +672,25 @@ out:
static void cfq_deactivate_request(request_queue_t *q, struct request *rq)
{
+ struct cfq_data *cfqd = q->elevator->elevator_data;
struct cfq_rq *crq = RQ_DATA(rq);
if (crq) {
struct cfq_queue *cfqq = crq->cfq_queue;
- if (cfqq->cfqd->cfq_tagged) {
- cfqq->service_used--;
- cfq_sort_rr_list(cfqq, 0);
+ if (cfq_crq_in_driver(crq)) {
+ cfq_clear_crq_in_driver(crq);
+ WARN_ON(!cfqd->rq_in_driver);
+ cfqd->rq_in_driver--;
}
+ if (cfq_crq_in_flight(crq)) {
+ const int sync = cfq_crq_is_sync(crq);
- if (crq->accounted) {
- crq->accounted = 0;
- cfqq->cfqd->rq_in_driver--;
+ cfq_clear_crq_in_flight(crq);
+ WARN_ON(!cfqq->on_dispatch[sync]);
+ cfqq->on_dispatch[sync]--;
}
+ cfq_mark_crq_requeued(crq);
}
}
@@ -640,11 +708,10 @@ static void cfq_remove_request(request_queue_t *q, struct request *rq)
struct cfq_rq *crq = RQ_DATA(rq);
if (crq) {
- cfq_remove_merge_hints(q, crq);
list_del_init(&rq->queuelist);
+ cfq_del_crq_rb(crq);
+ cfq_remove_merge_hints(q, crq);
- if (crq->cfq_queue)
- cfq_del_crq_rb(crq);
}
}
@@ -662,21 +729,15 @@ cfq_merge(request_queue_t *q, struct request **req, struct bio *bio)
}
__rq = cfq_find_rq_hash(cfqd, bio->bi_sector);
- if (__rq) {
- BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector);
-
- if (elv_rq_merge_ok(__rq, bio)) {
- ret = ELEVATOR_BACK_MERGE;
- goto out;
- }
+ if (__rq && elv_rq_merge_ok(__rq, bio)) {
+ ret = ELEVATOR_BACK_MERGE;
+ goto out;
}
__rq = cfq_find_rq_rb(cfqd, bio->bi_sector + bio_sectors(bio));
- if (__rq) {
- if (elv_rq_merge_ok(__rq, bio)) {
- ret = ELEVATOR_FRONT_MERGE;
- goto out;
- }
+ if (__rq && elv_rq_merge_ok(__rq, bio)) {
+ ret = ELEVATOR_FRONT_MERGE;
+ goto out;
}
return ELEVATOR_NO_MERGE;
@@ -709,20 +770,220 @@ static void
cfq_merged_requests(request_queue_t *q, struct request *rq,
struct request *next)
{
- struct cfq_rq *crq = RQ_DATA(rq);
- struct cfq_rq *cnext = RQ_DATA(next);
-
cfq_merged_request(q, rq);
- if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist)) {
- if (time_before(cnext->queue_start, crq->queue_start)) {
- list_move(&rq->queuelist, &next->queuelist);
- crq->queue_start = cnext->queue_start;
+ /*
+ * reposition in fifo if next is older than rq
+ */
+ if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist) &&
+ time_before(next->start_time, rq->start_time))
+ list_move(&rq->queuelist, &next->queuelist);
+
+ cfq_remove_request(q, next);
+}
+
+static inline void
+__cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+ if (cfqq) {
+ /*
+ * stop potential idle class queues waiting service
+ */
+ del_timer(&cfqd->idle_class_timer);
+
+ cfqq->slice_start = jiffies;
+ cfqq->slice_end = 0;
+ cfqq->slice_left = 0;
+ cfq_clear_cfqq_must_alloc_slice(cfqq);
+ cfq_clear_cfqq_fifo_expire(cfqq);
+ cfq_clear_cfqq_expired(cfqq);
+ }
+
+ cfqd->active_queue = cfqq;
+}
+
+/*
+ * 0
+ * 0,1
+ * 0,1,2
+ * 0,1,2,3
+ * 0,1,2,3,4
+ * 0,1,2,3,4,5
+ * 0,1,2,3,4,5,6
+ * 0,1,2,3,4,5,6,7
+ */
+static int cfq_get_next_prio_level(struct cfq_data *cfqd)
+{
+ int prio, wrap;
+
+ prio = -1;
+ wrap = 0;
+ do {
+ int p;
+
+ for (p = cfqd->cur_prio; p <= cfqd->cur_end_prio; p++) {
+ if (!list_empty(&cfqd->rr_list[p])) {
+ prio = p;
+ break;
+ }
+ }
+
+ if (prio != -1)
+ break;
+ cfqd->cur_prio = 0;
+ if (++cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
+ cfqd->cur_end_prio = 0;
+ if (wrap)
+ break;
+ wrap = 1;
}
+ } while (1);
+
+ if (unlikely(prio == -1))
+ return -1;
+
+ BUG_ON(prio >= CFQ_PRIO_LISTS);
+
+ list_splice_init(&cfqd->rr_list[prio], &cfqd->cur_rr);
+
+ cfqd->cur_prio = prio + 1;
+ if (cfqd->cur_prio > cfqd->cur_end_prio) {
+ cfqd->cur_end_prio = cfqd->cur_prio;
+ cfqd->cur_prio = 0;
+ }
+ if (cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
+ cfqd->cur_prio = 0;
+ cfqd->cur_end_prio = 0;
}
- cfq_update_next_crq(cnext);
- cfq_remove_request(q, next);
+ return prio;
+}
+
+static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd)
+{
+ struct cfq_queue *cfqq;
+
+ /*
+ * if current queue is expired but not done with its requests yet,
+ * wait for that to happen
+ */
+ if ((cfqq = cfqd->active_queue) != NULL) {
+ if (cfq_cfqq_expired(cfqq) && cfq_cfqq_dispatched(cfqq))
+ return NULL;
+ }
+
+ /*
+ * if current list is non-empty, grab first entry. if it is empty,
+ * get next prio level and grab first entry then if any are spliced
+ */
+ if (!list_empty(&cfqd->cur_rr) || cfq_get_next_prio_level(cfqd) != -1)
+ cfqq = list_entry_cfqq(cfqd->cur_rr.next);
+
+ /*
+ * if we have idle queues and no rt or be queues had pending
+ * requests, either allow immediate service if the grace period
+ * has passed or arm the idle grace timer
+ */
+ if (!cfqq && !list_empty(&cfqd->idle_rr)) {
+ unsigned long end = cfqd->last_end_request + CFQ_IDLE_GRACE;
+
+ if (time_after_eq(jiffies, end))
+ cfqq = list_entry_cfqq(cfqd->idle_rr.next);
+ else
+ mod_timer(&cfqd->idle_class_timer, end);
+ }
+
+ __cfq_set_active_queue(cfqd, cfqq);
+ return cfqq;
+}
+
+/*
+ * current cfqq expired its slice (or was too idle), select new one
+ */
+static void
+__cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+ int preempted)
+{
+ unsigned long now = jiffies;
+
+ if (cfq_cfqq_wait_request(cfqq))
+ del_timer(&cfqd->idle_slice_timer);
+
+ if (!preempted && !cfq_cfqq_dispatched(cfqq))
+ cfqq->service_last = now;
+
+ cfq_clear_cfqq_must_dispatch(cfqq);
+ cfq_clear_cfqq_wait_request(cfqq);
+
+ /*
+ * store what was left of this slice, if the queue idled out
+ * or was preempted
+ */
+ if (time_after(now, cfqq->slice_end))
+ cfqq->slice_left = now - cfqq->slice_end;
+ else
+ cfqq->slice_left = 0;
+
+ if (cfq_cfqq_on_rr(cfqq))
+ cfq_resort_rr_list(cfqq, preempted);
+
+ if (cfqq == cfqd->active_queue)
+ cfqd->active_queue = NULL;
+
+ if (cfqd->active_cic) {
+ put_io_context(cfqd->active_cic->ioc);
+ cfqd->active_cic = NULL;
+ }
+
+ cfqd->dispatch_slice = 0;
+}
+
+static inline void cfq_slice_expired(struct cfq_data *cfqd, int preempted)
+{
+ struct cfq_queue *cfqq = cfqd->active_queue;
+
+ if (cfqq) {
+ /*
+ * use deferred expiry, if there are requests in progress as
+ * not to disturb the slice of the next queue
+ */
+ if (cfq_cfqq_dispatched(cfqq))
+ cfq_mark_cfqq_expired(cfqq);
+ else
+ __cfq_slice_expired(cfqd, cfqq, preempted);
+ }
+}
+
+static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+
+{
+ WARN_ON(!RB_EMPTY(&cfqq->sort_list));
+ WARN_ON(cfqq != cfqd->active_queue);
+
+ /*
+ * idle is disabled, either manually or by past process history
+ */
+ if (!cfqd->cfq_slice_idle)
+ return 0;
+ if (!cfq_cfqq_idle_window(cfqq))
+ return 0;
+ /*
+ * task has exited, don't wait
+ */
+ if (cfqd->active_cic && !cfqd->active_cic->ioc->task)
+ return 0;
+
+ cfq_mark_cfqq_must_dispatch(cfqq);
+ cfq_mark_cfqq_wait_request(cfqq);
+
+ if (!timer_pending(&cfqd->idle_slice_timer)) {
+ unsigned long slice_left = min(cfqq->slice_end - 1, (unsigned long) cfqd->cfq_slice_idle);
+
+ cfqd->idle_slice_timer.expires = jiffies + slice_left;
+ add_timer(&cfqd->idle_slice_timer);
+ }
+
+ return 1;
}
/*
@@ -738,31 +999,40 @@ static void cfq_dispatch_sort(request_queue_t *q, struct cfq_rq *crq)
struct request *__rq;
sector_t last;
- cfq_del_crq_rb(crq);
- cfq_remove_merge_hints(q, crq);
list_del(&crq->request->queuelist);
last = cfqd->last_sector;
- while ((entry = entry->prev) != head) {
- __rq = list_entry_rq(entry);
+ list_for_each_entry_reverse(__rq, head, queuelist) {
+ struct cfq_rq *__crq = RQ_DATA(__rq);
- if (blk_barrier_rq(crq->request))
+ if (blk_barrier_rq(__rq))
break;
- if (!blk_fs_request(crq->request))
+ if (!blk_fs_request(__rq))
+ break;
+ if (cfq_crq_requeued(__crq))
break;
- if (crq->request->sector > __rq->sector)
+ if (__rq->sector <= crq->request->sector)
break;
if (__rq->sector > last && crq->request->sector < last) {
- last = crq->request->sector;
+ last = crq->request->sector + crq->request->nr_sectors;
break;
}
+ entry = &__rq->queuelist;
}
cfqd->last_sector = last;
- crq->in_flight = 1;
- cfqq->in_flight++;
- list_add(&crq->request->queuelist, entry);
+
+ cfqq->next_crq = cfq_find_next_crq(cfqd, cfqq, crq);
+
+ cfq_del_crq_rb(crq);
+ cfq_remove_merge_hints(q, crq);
+
+ cfq_mark_crq_in_flight(crq);
+ cfq_clear_crq_requeued(crq);
+
+ cfqq->on_dispatch[cfq_crq_is_sync(crq)]++;
+ list_add_tail(&crq->request->queuelist, entry);
}
/*
@@ -771,173 +1041,225 @@ static void cfq_dispatch_sort(request_queue_t *q, struct cfq_rq *crq)
static inline struct cfq_rq *cfq_check_fifo(struct cfq_queue *cfqq)
{
struct cfq_data *cfqd = cfqq->cfqd;
- const int reads = !list_empty(&cfqq->fifo[0]);
- const int writes = !list_empty(&cfqq->fifo[1]);
- unsigned long now = jiffies;
+ struct request *rq;
struct cfq_rq *crq;
- if (time_before(now, cfqq->last_fifo_expire + cfqd->cfq_fifo_batch_expire))
+ if (cfq_cfqq_fifo_expire(cfqq))
return NULL;
- crq = RQ_DATA(list_entry(cfqq->fifo[0].next, struct request, queuelist));
- if (reads && time_after(now, crq->queue_start + cfqd->cfq_fifo_expire_r)) {
- cfqq->last_fifo_expire = now;
- return crq;
- }
+ if (!list_empty(&cfqq->fifo)) {
+ int fifo = cfq_cfqq_class_sync(cfqq);
- crq = RQ_DATA(list_entry(cfqq->fifo[1].next, struct request, queuelist));
- if (writes && time_after(now, crq->queue_start + cfqd->cfq_fifo_expire_w)) {
- cfqq->last_fifo_expire = now;
- return crq;
+ crq = RQ_DATA(list_entry_fifo(cfqq->fifo.next));
+ rq = crq->request;
+ if (time_after(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo])) {
+ cfq_mark_cfqq_fifo_expire(cfqq);
+ return crq;
+ }
}
return NULL;
}
/*
- * dispatch a single request from given queue
+ * Scale schedule slice based on io priority. Use the sync time slice only
+ * if a queue is marked sync and has sync io queued. A sync queue with async
+ * io only, should not get full sync slice length.
*/
+static inline int
+cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+ const int base_slice = cfqd->cfq_slice[cfq_cfqq_sync(cfqq)];
+
+ WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
+
+ return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - cfqq->ioprio));
+}
+
static inline void
-cfq_dispatch_request(request_queue_t *q, struct cfq_data *cfqd,
- struct cfq_queue *cfqq)
+cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
- struct cfq_rq *crq;
+ cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies;
+}
+
+static inline int
+cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+ const int base_rq = cfqd->cfq_slice_async_rq;
+
+ WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
+
+ return 2 * (base_rq + base_rq * (CFQ_PRIO_LISTS - 1 - cfqq->ioprio));
+}
+
+/*
+ * get next queue for service
+ */
+static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd, int force)
+{
+ unsigned long now = jiffies;
+ struct cfq_queue *cfqq;
+
+ cfqq = cfqd->active_queue;
+ if (!cfqq)
+ goto new_queue;
+
+ if (cfq_cfqq_expired(cfqq))
+ goto new_queue;
/*
- * follow expired path, else get first next available
+ * slice has expired
*/
- if ((crq = cfq_check_fifo(cfqq)) == NULL) {
- if (cfqd->find_best_crq)
- crq = cfqq->next_crq;
- else
- crq = rb_entry_crq(rb_first(&cfqq->sort_list));
- }
-
- cfqd->last_sector = crq->request->sector + crq->request->nr_sectors;
+ if (!cfq_cfqq_must_dispatch(cfqq) && time_after(now, cfqq->slice_end))
+ goto expire;
/*
- * finally, insert request into driver list
+ * if queue has requests, dispatch one. if not, check if
+ * enough slice is left to wait for one
*/
- cfq_dispatch_sort(q, crq);
+ if (!RB_EMPTY(&cfqq->sort_list))
+ goto keep_queue;
+ else if (!force && cfq_cfqq_class_sync(cfqq) &&
+ time_before(now, cfqq->slice_end)) {
+ if (cfq_arm_slice_timer(cfqd, cfqq))
+ return NULL;
+ }
+
+expire:
+ cfq_slice_expired(cfqd, 0);
+new_queue:
+ cfqq = cfq_set_active_queue(cfqd);
+keep_queue:
+ return cfqq;
}
-static int cfq_dispatch_requests(request_queue_t *q, int max_dispatch)
+static int
+__cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+ int max_dispatch)
{
- struct cfq_data *cfqd = q->elevator->elevator_data;
- struct cfq_queue *cfqq;
- struct list_head *entry, *tmp;
- int queued, busy_queues, first_round;
+ int dispatched = 0;
- if (list_empty(&cfqd->rr_list))
- return 0;
+ BUG_ON(RB_EMPTY(&cfqq->sort_list));
- queued = 0;
- first_round = 1;
-restart:
- busy_queues = 0;
- list_for_each_safe(entry, tmp, &cfqd->rr_list) {
- cfqq = list_entry_cfqq(entry);
+ do {
+ struct cfq_rq *crq;
- BUG_ON(RB_EMPTY(&cfqq->sort_list));
+ /*
+ * follow expired path, else get first next available
+ */
+ if ((crq = cfq_check_fifo(cfqq)) == NULL)
+ crq = cfqq->next_crq;
/*
- * first round of queueing, only select from queues that
- * don't already have io in-flight
+ * finally, insert request into driver dispatch list
*/
- if (first_round && cfqq->in_flight)
- continue;
+ cfq_dispatch_sort(cfqd->queue, crq);
- cfq_dispatch_request(q, cfqd, cfqq);
+ cfqd->dispatch_slice++;
+ dispatched++;
- if (!RB_EMPTY(&cfqq->sort_list))
- busy_queues++;
+ if (!cfqd->active_cic) {
+ atomic_inc(&crq->io_context->ioc->refcount);
+ cfqd->active_cic = crq->io_context;
+ }
- queued++;
- }
+ if (RB_EMPTY(&cfqq->sort_list))
+ break;
+
+ } while (dispatched < max_dispatch);
+
+ /*
+ * if slice end isn't set yet, set it. if at least one request was
+ * sync, use the sync time slice value
+ */
+ if (!cfqq->slice_end)
+ cfq_set_prio_slice(cfqd, cfqq);
+
+ /*
+ * expire an async queue immediately if it has used up its slice. idle
+ * queue always expire after 1 dispatch round.
+ */
+ if ((!cfq_cfqq_sync(cfqq) &&
+ cfqd->dispatch_slice >= cfq_prio_to_maxrq(cfqd, cfqq)) ||
+ cfq_class_idle(cfqq))
+ cfq_slice_expired(cfqd, 0);
+
+ return dispatched;
+}
+
+static int
+cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force)
+{
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+ struct cfq_queue *cfqq;
+
+ if (!cfqd->busy_queues)
+ return 0;
+
+ cfqq = cfq_select_queue(cfqd, force);
+ if (cfqq) {
+ cfq_clear_cfqq_must_dispatch(cfqq);
+ cfq_clear_cfqq_wait_request(cfqq);
+ del_timer(&cfqd->idle_slice_timer);
- if ((queued < max_dispatch) && (busy_queues || first_round)) {
- first_round = 0;
- goto restart;
+ if (cfq_class_idle(cfqq))
+ max_dispatch = 1;
+
+ return __cfq_dispatch_requests(cfqd, cfqq, max_dispatch);
}
- return queued;
+ return 0;
}
static inline void cfq_account_dispatch(struct cfq_rq *crq)
{
struct cfq_queue *cfqq = crq->cfq_queue;
struct cfq_data *cfqd = cfqq->cfqd;
- unsigned long now, elapsed;
- if (!blk_fs_request(crq->request))
+ if (unlikely(!blk_fs_request(crq->request)))
return;
/*
* accounted bit is necessary since some drivers will call
* elv_next_request() many times for the same request (eg ide)
*/
- if (crq->accounted)
+ if (cfq_crq_in_driver(crq))
return;
- now = jiffies;
- if (cfqq->service_start == ~0UL)
- cfqq->service_start = now;
-
- /*
- * on drives with tagged command queueing, command turn-around time
- * doesn't necessarily reflect the time spent processing this very
- * command inside the drive. so do the accounting differently there,
- * by just sorting on the number of requests
- */
- if (cfqd->cfq_tagged) {
- if (time_after(now, cfqq->service_start + cfq_service)) {
- cfqq->service_start = now;
- cfqq->service_used /= 10;
- }
-
- cfqq->service_used++;
- cfq_sort_rr_list(cfqq, 0);
- }
-
- elapsed = now - crq->queue_start;
- if (elapsed > max_elapsed_dispatch)
- max_elapsed_dispatch = elapsed;
-
- crq->accounted = 1;
- crq->service_start = now;
-
- if (++cfqd->rq_in_driver >= CFQ_MAX_TAG && !cfqd->cfq_tagged) {
- cfqq->cfqd->cfq_tagged = 1;
- printk("cfq: depth %d reached, tagging now on\n", CFQ_MAX_TAG);
- }
+ cfq_mark_crq_in_driver(crq);
+ cfqd->rq_in_driver++;
}
static inline void
cfq_account_completion(struct cfq_queue *cfqq, struct cfq_rq *crq)
{
struct cfq_data *cfqd = cfqq->cfqd;
+ unsigned long now;
- if (!crq->accounted)
+ if (!cfq_crq_in_driver(crq))
return;
+ now = jiffies;
+
WARN_ON(!cfqd->rq_in_driver);
cfqd->rq_in_driver--;
- if (!cfqd->cfq_tagged) {
- unsigned long now = jiffies;
- unsigned long duration = now - crq->service_start;
+ if (!cfq_class_idle(cfqq))
+ cfqd->last_end_request = now;
- if (time_after(now, cfqq->service_start + cfq_service)) {
- cfqq->service_start = now;
- cfqq->service_used >>= 3;
+ if (!cfq_cfqq_dispatched(cfqq)) {
+ if (cfq_cfqq_on_rr(cfqq)) {
+ cfqq->service_last = now;
+ cfq_resort_rr_list(cfqq, 0);
+ }
+ if (cfq_cfqq_expired(cfqq)) {
+ __cfq_slice_expired(cfqd, cfqq, 0);
+ cfq_schedule_dispatch(cfqd);
}
-
- cfqq->service_used += duration;
- cfq_sort_rr_list(cfqq, 0);
-
- if (duration > max_elapsed_crq)
- max_elapsed_crq = duration;
}
+
+ if (cfq_crq_is_sync(crq))
+ crq->io_context->last_end_request = now;
}
static struct request *cfq_next_request(request_queue_t *q)
@@ -950,7 +1272,18 @@ static struct request *cfq_next_request(request_queue_t *q)
dispatch:
rq = list_entry_rq(q->queue_head.next);
- if ((crq = RQ_DATA(rq)) != NULL) {
+ crq = RQ_DATA(rq);
+ if (crq) {
+ struct cfq_queue *cfqq = crq->cfq_queue;
+
+ /*
+ * if idle window is disabled, allow queue buildup
+ */
+ if (!cfq_crq_in_driver(crq) &&
+ !cfq_cfqq_idle_window(cfqq) &&
+ cfqd->rq_in_driver >= cfqd->cfq_max_depth)
+ return NULL;
+
cfq_remove_merge_hints(q, crq);
cfq_account_dispatch(crq);
}
@@ -958,7 +1291,7 @@ dispatch:
return rq;
}
- if (cfq_dispatch_requests(q, cfqd->cfq_quantum))
+ if (cfq_dispatch_requests(q, cfqd->cfq_quantum, 0))
goto dispatch;
return NULL;
@@ -972,13 +1305,21 @@ dispatch:
*/
static void cfq_put_queue(struct cfq_queue *cfqq)
{
- BUG_ON(!atomic_read(&cfqq->ref));
+ struct cfq_data *cfqd = cfqq->cfqd;
+
+ BUG_ON(atomic_read(&cfqq->ref) <= 0);
if (!atomic_dec_and_test(&cfqq->ref))
return;
BUG_ON(rb_first(&cfqq->sort_list));
- BUG_ON(cfqq->on_rr);
+ BUG_ON(cfqq->allocated[READ] + cfqq->allocated[WRITE]);
+ BUG_ON(cfq_cfqq_on_rr(cfqq));
+
+ if (unlikely(cfqd->active_queue == cfqq)) {
+ __cfq_slice_expired(cfqd, cfqq, 0);
+ cfq_schedule_dispatch(cfqd);
+ }
cfq_put_cfqd(cfqq->cfqd);
@@ -991,15 +1332,17 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
}
static inline struct cfq_queue *
-__cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned long key, const int hashval)
+__cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned int prio,
+ const int hashval)
{
struct hlist_head *hash_list = &cfqd->cfq_hash[hashval];
struct hlist_node *entry, *next;
hlist_for_each_safe(entry, next, hash_list) {
struct cfq_queue *__cfqq = list_entry_qhash(entry);
+ const unsigned short __p = IOPRIO_PRIO_VALUE(__cfqq->ioprio_class, __cfqq->ioprio);
- if (__cfqq->key == key)
+ if (__cfqq->key == key && (__p == prio || prio == CFQ_KEY_ANY))
return __cfqq;
}
@@ -1007,94 +1350,220 @@ __cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned long key, const int hashval)
}
static struct cfq_queue *
-cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned long key)
+cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned short prio)
{
- return __cfq_find_cfq_hash(cfqd, key, hash_long(key, CFQ_QHASH_SHIFT));
+ return __cfq_find_cfq_hash(cfqd, key, prio, hash_long(key, CFQ_QHASH_SHIFT));
}
-static inline void
-cfq_rehash_cfqq(struct cfq_data *cfqd, struct cfq_queue **cfqq,
- struct cfq_io_context *cic)
+static void cfq_free_io_context(struct cfq_io_context *cic)
{
- unsigned long hashkey = cfq_hash_key(cfqd, current);
- unsigned long hashval = hash_long(hashkey, CFQ_QHASH_SHIFT);
- struct cfq_queue *__cfqq;
- unsigned long flags;
-
- spin_lock_irqsave(cfqd->queue->queue_lock, flags);
+ struct cfq_io_context *__cic;
+ struct list_head *entry, *next;
- hlist_del(&(*cfqq)->cfq_hash);
-
- __cfqq = __cfq_find_cfq_hash(cfqd, hashkey, hashval);
- if (!__cfqq || __cfqq == *cfqq) {
- __cfqq = *cfqq;
- hlist_add_head(&__cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
- __cfqq->key_type = cfqd->key_type;
- } else {
- atomic_inc(&__cfqq->ref);
- cic->cfqq = __cfqq;
- cfq_put_queue(*cfqq);
- *cfqq = __cfqq;
+ list_for_each_safe(entry, next, &cic->list) {
+ __cic = list_entry(entry, struct cfq_io_context, list);
+ kmem_cache_free(cfq_ioc_pool, __cic);
}
- cic->cfqq = __cfqq;
- spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
+ kmem_cache_free(cfq_ioc_pool, cic);
}
-static void cfq_free_io_context(struct cfq_io_context *cic)
+/*
+ * Called with interrupts disabled
+ */
+static void cfq_exit_single_io_context(struct cfq_io_context *cic)
{
- kmem_cache_free(cfq_ioc_pool, cic);
+ struct cfq_data *cfqd = cic->cfqq->cfqd;
+ request_queue_t *q = cfqd->queue;
+
+ WARN_ON(!irqs_disabled());
+
+ spin_lock(q->queue_lock);
+
+ if (unlikely(cic->cfqq == cfqd->active_queue)) {
+ __cfq_slice_expired(cfqd, cic->cfqq, 0);
+ cfq_schedule_dispatch(cfqd);
+ }
+
+ cfq_put_queue(cic->cfqq);
+ cic->cfqq = NULL;
+ spin_unlock(q->queue_lock);
}
/*
- * locking hierarchy is: io_context lock -> queue locks
+ * Another task may update the task cic list, if it is doing a queue lookup
+ * on its behalf. cfq_cic_lock excludes such concurrent updates
*/
static void cfq_exit_io_context(struct cfq_io_context *cic)
{
- struct cfq_queue *cfqq = cic->cfqq;
- struct list_head *entry = &cic->list;
- request_queue_t *q;
+ struct cfq_io_context *__cic;
+ struct list_head *entry;
unsigned long flags;
+ local_irq_save(flags);
+
/*
* put the reference this task is holding to the various queues
*/
- spin_lock_irqsave(&cic->ioc->lock, flags);
- while ((entry = cic->list.next) != &cic->list) {
- struct cfq_io_context *__cic;
-
+ list_for_each(entry, &cic->list) {
__cic = list_entry(entry, struct cfq_io_context, list);
- list_del(entry);
-
- q = __cic->cfqq->cfqd->queue;
- spin_lock(q->queue_lock);
- cfq_put_queue(__cic->cfqq);
- spin_unlock(q->queue_lock);
+ cfq_exit_single_io_context(__cic);
}
- q = cfqq->cfqd->queue;
- spin_lock(q->queue_lock);
- cfq_put_queue(cfqq);
- spin_unlock(q->queue_lock);
-
- cic->cfqq = NULL;
- spin_unlock_irqrestore(&cic->ioc->lock, flags);
+ cfq_exit_single_io_context(cic);
+ local_irq_restore(flags);
}
-static struct cfq_io_context *cfq_alloc_io_context(int gfp_flags)
+static struct cfq_io_context *
+cfq_alloc_io_context(struct cfq_data *cfqd, int gfp_mask)
{
- struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_flags);
+ struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask);
if (cic) {
- cic->dtor = cfq_free_io_context;
- cic->exit = cfq_exit_io_context;
INIT_LIST_HEAD(&cic->list);
cic->cfqq = NULL;
+ cic->key = NULL;
+ cic->last_end_request = jiffies;
+ cic->ttime_total = 0;
+ cic->ttime_samples = 0;
+ cic->ttime_mean = 0;
+ cic->dtor = cfq_free_io_context;
+ cic->exit = cfq_exit_io_context;
}
return cic;
}
+static void cfq_init_prio_data(struct cfq_queue *cfqq)
+{
+ struct task_struct *tsk = current;
+ int ioprio_class;
+
+ if (!cfq_cfqq_prio_changed(cfqq))
+ return;
+
+ ioprio_class = IOPRIO_PRIO_CLASS(tsk->ioprio);
+ switch (ioprio_class) {
+ default:
+ printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class);
+ case IOPRIO_CLASS_NONE:
+ /*
+ * no prio set, place us in the middle of the BE classes
+ */
+ cfqq->ioprio = task_nice_ioprio(tsk);
+ cfqq->ioprio_class = IOPRIO_CLASS_BE;
+ break;
+ case IOPRIO_CLASS_RT:
+ cfqq->ioprio = task_ioprio(tsk);
+ cfqq->ioprio_class = IOPRIO_CLASS_RT;
+ break;
+ case IOPRIO_CLASS_BE:
+ cfqq->ioprio = task_ioprio(tsk);
+ cfqq->ioprio_class = IOPRIO_CLASS_BE;
+ break;
+ case IOPRIO_CLASS_IDLE:
+ cfqq->ioprio_class = IOPRIO_CLASS_IDLE;
+ cfqq->ioprio = 7;
+ cfq_clear_cfqq_idle_window(cfqq);
+ break;
+ }
+
+ /*
+ * keep track of original prio settings in case we have to temporarily
+ * elevate the priority of this queue
+ */
+ cfqq->org_ioprio = cfqq->ioprio;
+ cfqq->org_ioprio_class = cfqq->ioprio_class;
+
+ if (cfq_cfqq_on_rr(cfqq))
+ cfq_resort_rr_list(cfqq, 0);
+
+ cfq_clear_cfqq_prio_changed(cfqq);
+}
+
+static inline void changed_ioprio(struct cfq_queue *cfqq)
+{
+ if (cfqq) {
+ struct cfq_data *cfqd = cfqq->cfqd;
+
+ spin_lock(cfqd->queue->queue_lock);
+ cfq_mark_cfqq_prio_changed(cfqq);
+ cfq_init_prio_data(cfqq);
+ spin_unlock(cfqd->queue->queue_lock);
+ }
+}
+
+/*
+ * callback from sys_ioprio_set, irqs are disabled
+ */
+static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio)
+{
+ struct cfq_io_context *cic = ioc->cic;
+
+ changed_ioprio(cic->cfqq);
+
+ list_for_each_entry(cic, &cic->list, list)
+ changed_ioprio(cic->cfqq);
+
+ return 0;
+}
+
+static struct cfq_queue *
+cfq_get_queue(struct cfq_data *cfqd, unsigned int key, unsigned short ioprio,
+ int gfp_mask)
+{
+ const int hashval = hash_long(key, CFQ_QHASH_SHIFT);
+ struct cfq_queue *cfqq, *new_cfqq = NULL;
+
+retry:
+ cfqq = __cfq_find_cfq_hash(cfqd, key, ioprio, hashval);
+
+ if (!cfqq) {
+ if (new_cfqq) {
+ cfqq = new_cfqq;
+ new_cfqq = NULL;
+ } else if (gfp_mask & __GFP_WAIT) {
+ spin_unlock_irq(cfqd->queue->queue_lock);
+ new_cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
+ spin_lock_irq(cfqd->queue->queue_lock);
+ goto retry;
+ } else {
+ cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
+ if (!cfqq)
+ goto out;
+ }
+
+ memset(cfqq, 0, sizeof(*cfqq));
+
+ INIT_HLIST_NODE(&cfqq->cfq_hash);
+ INIT_LIST_HEAD(&cfqq->cfq_list);
+ RB_CLEAR_ROOT(&cfqq->sort_list);
+ INIT_LIST_HEAD(&cfqq->fifo);
+
+ cfqq->key = key;
+ hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
+ atomic_set(&cfqq->ref, 0);
+ cfqq->cfqd = cfqd;
+ atomic_inc(&cfqd->ref);
+ cfqq->service_last = 0;
+ /*
+ * set ->slice_left to allow preemption for a new process
+ */
+ cfqq->slice_left = 2 * cfqd->cfq_slice_idle;
+ cfq_mark_cfqq_idle_window(cfqq);
+ cfq_mark_cfqq_prio_changed(cfqq);
+ cfq_init_prio_data(cfqq);
+ }
+
+ if (new_cfqq)
+ kmem_cache_free(cfq_pool, new_cfqq);
+
+ atomic_inc(&cfqq->ref);
+out:
+ WARN_ON((gfp_mask & __GFP_WAIT) && !cfqq);
+ return cfqq;
+}
+
/*
* Setup general io context and cfq io context. There can be several cfq
* io contexts per general io context, if this process is doing io to more
@@ -1102,39 +1571,39 @@ static struct cfq_io_context *cfq_alloc_io_context(int gfp_flags)
* cfqq, so we don't need to worry about it disappearing
*/
static struct cfq_io_context *
-cfq_get_io_context(struct cfq_queue **cfqq, int gfp_flags)
+cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, int gfp_mask)
{
- struct cfq_data *cfqd = (*cfqq)->cfqd;
- struct cfq_queue *__cfqq = *cfqq;
+ struct io_context *ioc = NULL;
struct cfq_io_context *cic;
- struct io_context *ioc;
- might_sleep_if(gfp_flags & __GFP_WAIT);
+ might_sleep_if(gfp_mask & __GFP_WAIT);
- ioc = get_io_context(gfp_flags);
+ ioc = get_io_context(gfp_mask);
if (!ioc)
return NULL;
if ((cic = ioc->cic) == NULL) {
- cic = cfq_alloc_io_context(gfp_flags);
+ cic = cfq_alloc_io_context(cfqd, gfp_mask);
if (cic == NULL)
goto err;
+ /*
+ * manually increment generic io_context usage count, it
+ * cannot go away since we are already holding one ref to it
+ */
ioc->cic = cic;
+ ioc->set_ioprio = cfq_ioc_set_ioprio;
cic->ioc = ioc;
- cic->cfqq = __cfqq;
- atomic_inc(&__cfqq->ref);
+ cic->key = cfqd;
+ atomic_inc(&cfqd->ref);
} else {
struct cfq_io_context *__cic;
- unsigned long flags;
/*
- * since the first cic on the list is actually the head
- * itself, need to check this here or we'll duplicate an
- * cic per ioc for no reason
+ * the first cic on the list is actually the head itself
*/
- if (cic->cfqq == __cfqq)
+ if (cic->key == cfqd)
goto out;
/*
@@ -1142,152 +1611,250 @@ cfq_get_io_context(struct cfq_queue **cfqq, int gfp_flags)
* should be ok here, the list will usually not be more than
* 1 or a few entries long
*/
- spin_lock_irqsave(&ioc->lock, flags);
list_for_each_entry(__cic, &cic->list, list) {
/*
* this process is already holding a reference to
* this queue, so no need to get one more
*/
- if (__cic->cfqq == __cfqq) {
+ if (__cic->key == cfqd) {
cic = __cic;
- spin_unlock_irqrestore(&ioc->lock, flags);
goto out;
}
}
- spin_unlock_irqrestore(&ioc->lock, flags);
/*
* nope, process doesn't have a cic assoicated with this
* cfqq yet. get a new one and add to list
*/
- __cic = cfq_alloc_io_context(gfp_flags);
+ __cic = cfq_alloc_io_context(cfqd, gfp_mask);
if (__cic == NULL)
goto err;
__cic->ioc = ioc;
- __cic->cfqq = __cfqq;
- atomic_inc(&__cfqq->ref);
- spin_lock_irqsave(&ioc->lock, flags);
+ __cic->key = cfqd;
+ atomic_inc(&cfqd->ref);
list_add(&__cic->list, &cic->list);
- spin_unlock_irqrestore(&ioc->lock, flags);
-
cic = __cic;
- *cfqq = __cfqq;
}
out:
- /*
- * if key_type has been changed on the fly, we lazily rehash
- * each queue at lookup time
- */
- if ((*cfqq)->key_type != cfqd->key_type)
- cfq_rehash_cfqq(cfqd, cfqq, cic);
-
return cic;
err:
put_io_context(ioc);
return NULL;
}
-static struct cfq_queue *
-__cfq_get_queue(struct cfq_data *cfqd, unsigned long key, int gfp_mask)
+static void
+cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_io_context *cic)
{
- const int hashval = hash_long(key, CFQ_QHASH_SHIFT);
- struct cfq_queue *cfqq, *new_cfqq = NULL;
-
-retry:
- cfqq = __cfq_find_cfq_hash(cfqd, key, hashval);
+ unsigned long elapsed, ttime;
- if (!cfqq) {
- if (new_cfqq) {
- cfqq = new_cfqq;
- new_cfqq = NULL;
- } else {
- spin_unlock_irq(cfqd->queue->queue_lock);
- new_cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
- spin_lock_irq(cfqd->queue->queue_lock);
+ /*
+ * if this context already has stuff queued, thinktime is from
+ * last queue not last end
+ */
+#if 0
+ if (time_after(cic->last_end_request, cic->last_queue))
+ elapsed = jiffies - cic->last_end_request;
+ else
+ elapsed = jiffies - cic->last_queue;
+#else
+ elapsed = jiffies - cic->last_end_request;
+#endif
- if (!new_cfqq && !(gfp_mask & __GFP_WAIT))
- goto out;
+ ttime = min(elapsed, 2UL * cfqd->cfq_slice_idle);
- goto retry;
- }
+ cic->ttime_samples = (7*cic->ttime_samples + 256) / 8;
+ cic->ttime_total = (7*cic->ttime_total + 256*ttime) / 8;
+ cic->ttime_mean = (cic->ttime_total + 128) / cic->ttime_samples;
+}
- memset(cfqq, 0, sizeof(*cfqq));
+#define sample_valid(samples) ((samples) > 80)
- INIT_HLIST_NODE(&cfqq->cfq_hash);
- INIT_LIST_HEAD(&cfqq->cfq_list);
- RB_CLEAR_ROOT(&cfqq->sort_list);
- INIT_LIST_HEAD(&cfqq->fifo[0]);
- INIT_LIST_HEAD(&cfqq->fifo[1]);
+/*
+ * Disable idle window if the process thinks too long or seeks so much that
+ * it doesn't matter
+ */
+static void
+cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+ struct cfq_io_context *cic)
+{
+ int enable_idle = cfq_cfqq_idle_window(cfqq);
- cfqq->key = key;
- hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
- atomic_set(&cfqq->ref, 0);
- cfqq->cfqd = cfqd;
- atomic_inc(&cfqd->ref);
- cfqq->key_type = cfqd->key_type;
- cfqq->service_start = ~0UL;
+ if (!cic->ioc->task || !cfqd->cfq_slice_idle)
+ enable_idle = 0;
+ else if (sample_valid(cic->ttime_samples)) {
+ if (cic->ttime_mean > cfqd->cfq_slice_idle)
+ enable_idle = 0;
+ else
+ enable_idle = 1;
}
- if (new_cfqq)
- kmem_cache_free(cfq_pool, new_cfqq);
+ if (enable_idle)
+ cfq_mark_cfqq_idle_window(cfqq);
+ else
+ cfq_clear_cfqq_idle_window(cfqq);
+}
- atomic_inc(&cfqq->ref);
-out:
- WARN_ON((gfp_mask & __GFP_WAIT) && !cfqq);
- return cfqq;
+
+/*
+ * Check if new_cfqq should preempt the currently active queue. Return 0 for
+ * no or if we aren't sure, a 1 will cause a preempt.
+ */
+static int
+cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
+ struct cfq_rq *crq)
+{
+ struct cfq_queue *cfqq = cfqd->active_queue;
+
+ if (cfq_class_idle(new_cfqq))
+ return 0;
+
+ if (!cfqq)
+ return 1;
+
+ if (cfq_class_idle(cfqq))
+ return 1;
+ if (!cfq_cfqq_wait_request(new_cfqq))
+ return 0;
+ /*
+ * if it doesn't have slice left, forget it
+ */
+ if (new_cfqq->slice_left < cfqd->cfq_slice_idle)
+ return 0;
+ if (cfq_crq_is_sync(crq) && !cfq_cfqq_sync(cfqq))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * cfqq preempts the active queue. if we allowed preempt with no slice left,
+ * let it have half of its nominal slice.
+ */
+static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+ struct cfq_queue *__cfqq, *next;
+
+ list_for_each_entry_safe(__cfqq, next, &cfqd->cur_rr, cfq_list)
+ cfq_resort_rr_list(__cfqq, 1);
+
+ if (!cfqq->slice_left)
+ cfqq->slice_left = cfq_prio_to_slice(cfqd, cfqq) / 2;
+
+ cfqq->slice_end = cfqq->slice_left + jiffies;
+ __cfq_slice_expired(cfqd, cfqq, 1);
+ __cfq_set_active_queue(cfqd, cfqq);
}
-static void cfq_enqueue(struct cfq_data *cfqd, struct cfq_rq *crq)
+/*
+ * should really be a ll_rw_blk.c helper
+ */
+static void cfq_start_queueing(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+ request_queue_t *q = cfqd->queue;
+
+ if (!blk_queue_plugged(q))
+ q->request_fn(q);
+ else
+ __generic_unplug_device(q);
+}
+
+/*
+ * Called when a new fs request (crq) is added (to cfqq). Check if there's
+ * something we should do about it
+ */
+static void
+cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+ struct cfq_rq *crq)
{
- crq->is_sync = 0;
- if (rq_data_dir(crq->request) == READ || current->flags & PF_SYNCWRITE)
- crq->is_sync = 1;
+ const int sync = cfq_crq_is_sync(crq);
+
+ cfqq->next_crq = cfq_choose_req(cfqd, cfqq->next_crq, crq);
+
+ if (sync) {
+ struct cfq_io_context *cic = crq->io_context;
+
+ cfq_update_io_thinktime(cfqd, cic);
+ cfq_update_idle_window(cfqd, cfqq, cic);
+
+ cic->last_queue = jiffies;
+ }
+
+ if (cfqq == cfqd->active_queue) {
+ /*
+ * if we are waiting for a request for this queue, let it rip
+ * immediately and flag that we must not expire this queue
+ * just now
+ */
+ if (cfq_cfqq_wait_request(cfqq)) {
+ cfq_mark_cfqq_must_dispatch(cfqq);
+ del_timer(&cfqd->idle_slice_timer);
+ cfq_start_queueing(cfqd, cfqq);
+ }
+ } else if (cfq_should_preempt(cfqd, cfqq, crq)) {
+ /*
+ * not the active queue - expire current slice if it is
+ * idle and has expired it's mean thinktime or this new queue
+ * has some old slice time left and is of higher priority
+ */
+ cfq_preempt_queue(cfqd, cfqq);
+ cfq_mark_cfqq_must_dispatch(cfqq);
+ cfq_start_queueing(cfqd, cfqq);
+ }
+}
+
+static void cfq_enqueue(struct cfq_data *cfqd, struct request *rq)
+{
+ struct cfq_rq *crq = RQ_DATA(rq);
+ struct cfq_queue *cfqq = crq->cfq_queue;
+
+ cfq_init_prio_data(cfqq);
cfq_add_crq_rb(crq);
- crq->queue_start = jiffies;
- list_add_tail(&crq->request->queuelist, &crq->cfq_queue->fifo[crq->is_sync]);
+ list_add_tail(&rq->queuelist, &cfqq->fifo);
+
+ if (rq_mergeable(rq)) {
+ cfq_add_crq_hash(cfqd, crq);
+
+ if (!cfqd->queue->last_merge)
+ cfqd->queue->last_merge = rq;
+ }
+
+ cfq_crq_enqueued(cfqd, cfqq, crq);
}
static void
cfq_insert_request(request_queue_t *q, struct request *rq, int where)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
- struct cfq_rq *crq = RQ_DATA(rq);
switch (where) {
case ELEVATOR_INSERT_BACK:
- while (cfq_dispatch_requests(q, cfqd->cfq_quantum))
+ while (cfq_dispatch_requests(q, INT_MAX, 1))
;
list_add_tail(&rq->queuelist, &q->queue_head);
+ /*
+ * If we were idling with pending requests on
+ * inactive cfqqs, force dispatching will
+ * remove the idle timer and the queue won't
+ * be kicked by __make_request() afterward.
+ * Kick it here.
+ */
+ cfq_schedule_dispatch(cfqd);
break;
case ELEVATOR_INSERT_FRONT:
list_add(&rq->queuelist, &q->queue_head);
break;
case ELEVATOR_INSERT_SORT:
BUG_ON(!blk_fs_request(rq));
- cfq_enqueue(cfqd, crq);
+ cfq_enqueue(cfqd, rq);
break;
default:
printk("%s: bad insert point %d\n", __FUNCTION__,where);
return;
}
-
- if (rq_mergeable(rq)) {
- cfq_add_crq_hash(cfqd, crq);
-
- if (!q->last_merge)
- q->last_merge = rq;
- }
-}
-
-static int cfq_queue_empty(request_queue_t *q)
-{
- struct cfq_data *cfqd = q->elevator->elevator_data;
-
- return list_empty(&q->queue_head) && list_empty(&cfqd->rr_list);
}
static void cfq_completed_request(request_queue_t *q, struct request *rq)
@@ -1300,9 +1867,11 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
cfqq = crq->cfq_queue;
- if (crq->in_flight) {
- WARN_ON(!cfqq->in_flight);
- cfqq->in_flight--;
+ if (cfq_crq_in_flight(crq)) {
+ const int sync = cfq_crq_is_sync(crq);
+
+ WARN_ON(!cfqq->on_dispatch[sync]);
+ cfqq->on_dispatch[sync]--;
}
cfq_account_completion(cfqq, crq);
@@ -1332,51 +1901,136 @@ cfq_latter_request(request_queue_t *q, struct request *rq)
return NULL;
}
-static int cfq_may_queue(request_queue_t *q, int rw)
+/*
+ * we temporarily boost lower priority queues if they are holding fs exclusive
+ * resources. they are boosted to normal prio (CLASS_BE/4)
+ */
+static void cfq_prio_boost(struct cfq_queue *cfqq)
{
- struct cfq_data *cfqd = q->elevator->elevator_data;
- struct cfq_queue *cfqq;
- int ret = ELV_MQUEUE_MAY;
+ const int ioprio_class = cfqq->ioprio_class;
+ const int ioprio = cfqq->ioprio;
- if (current->flags & PF_MEMALLOC)
- return ELV_MQUEUE_MAY;
+ if (has_fs_excl()) {
+ /*
+ * boost idle prio on transactions that would lock out other
+ * users of the filesystem
+ */
+ if (cfq_class_idle(cfqq))
+ cfqq->ioprio_class = IOPRIO_CLASS_BE;
+ if (cfqq->ioprio > IOPRIO_NORM)
+ cfqq->ioprio = IOPRIO_NORM;
+ } else {
+ /*
+ * check if we need to unboost the queue
+ */
+ if (cfqq->ioprio_class != cfqq->org_ioprio_class)
+ cfqq->ioprio_class = cfqq->org_ioprio_class;
+ if (cfqq->ioprio != cfqq->org_ioprio)
+ cfqq->ioprio = cfqq->org_ioprio;
+ }
- cfqq = cfq_find_cfq_hash(cfqd, cfq_hash_key(cfqd, current));
- if (cfqq) {
- int limit = cfqd->max_queued;
+ /*
+ * refile between round-robin lists if we moved the priority class
+ */
+ if ((ioprio_class != cfqq->ioprio_class || ioprio != cfqq->ioprio) &&
+ cfq_cfqq_on_rr(cfqq))
+ cfq_resort_rr_list(cfqq, 0);
+}
- if (cfqq->allocated[rw] < cfqd->cfq_queued)
- return ELV_MQUEUE_MUST;
+static inline pid_t cfq_queue_pid(struct task_struct *task, int rw)
+{
+ if (rw == READ || process_sync(task))
+ return task->pid;
- if (cfqd->busy_queues)
- limit = q->nr_requests / cfqd->busy_queues;
+ return CFQ_KEY_ASYNC;
+}
- if (limit < cfqd->cfq_queued)
- limit = cfqd->cfq_queued;
- else if (limit > cfqd->max_queued)
- limit = cfqd->max_queued;
+static inline int
+__cfq_may_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+ struct task_struct *task, int rw)
+{
+#if 1
+ if ((cfq_cfqq_wait_request(cfqq) || cfq_cfqq_must_alloc(cfqq)) &&
+ !cfq_cfqq_must_alloc_slice(cfqq)) {
+ cfq_mark_cfqq_must_alloc_slice(cfqq);
+ return ELV_MQUEUE_MUST;
+ }
- if (cfqq->allocated[rw] >= limit) {
- if (limit > cfqq->alloc_limit[rw])
- cfqq->alloc_limit[rw] = limit;
+ return ELV_MQUEUE_MAY;
+#else
+ if (!cfqq || task->flags & PF_MEMALLOC)
+ return ELV_MQUEUE_MAY;
+ if (!cfqq->allocated[rw] || cfq_cfqq_must_alloc(cfqq)) {
+ if (cfq_cfqq_wait_request(cfqq))
+ return ELV_MQUEUE_MUST;
- ret = ELV_MQUEUE_NO;
+ /*
+ * only allow 1 ELV_MQUEUE_MUST per slice, otherwise we
+ * can quickly flood the queue with writes from a single task
+ */
+ if (rw == READ || !cfq_cfqq_must_alloc_slice(cfqq)) {
+ cfq_mark_cfqq_must_alloc_slice(cfqq);
+ return ELV_MQUEUE_MUST;
}
+
+ return ELV_MQUEUE_MAY;
}
+ if (cfq_class_idle(cfqq))
+ return ELV_MQUEUE_NO;
+ if (cfqq->allocated[rw] >= cfqd->max_queued) {
+ struct io_context *ioc = get_io_context(GFP_ATOMIC);
+ int ret = ELV_MQUEUE_NO;
- return ret;
+ if (ioc && ioc->nr_batch_requests)
+ ret = ELV_MQUEUE_MAY;
+
+ put_io_context(ioc);
+ return ret;
+ }
+
+ return ELV_MQUEUE_MAY;
+#endif
+}
+
+static int cfq_may_queue(request_queue_t *q, int rw, struct bio *bio)
+{
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+ struct task_struct *tsk = current;
+ struct cfq_queue *cfqq;
+
+ /*
+ * don't force setup of a queue from here, as a call to may_queue
+ * does not necessarily imply that a request actually will be queued.
+ * so just lookup a possibly existing queue, or return 'may queue'
+ * if that fails
+ */
+ cfqq = cfq_find_cfq_hash(cfqd, cfq_queue_pid(tsk, rw), tsk->ioprio);
+ if (cfqq) {
+ cfq_init_prio_data(cfqq);
+ cfq_prio_boost(cfqq);
+
+ return __cfq_may_queue(cfqd, cfqq, tsk, rw);
+ }
+
+ return ELV_MQUEUE_MAY;
}
static void cfq_check_waiters(request_queue_t *q, struct cfq_queue *cfqq)
{
+ struct cfq_data *cfqd = q->elevator->elevator_data;
struct request_list *rl = &q->rq;
- const int write = waitqueue_active(&rl->wait[WRITE]);
- const int read = waitqueue_active(&rl->wait[READ]);
- if (read && cfqq->allocated[READ] < cfqq->alloc_limit[READ])
- wake_up(&rl->wait[READ]);
- if (write && cfqq->allocated[WRITE] < cfqq->alloc_limit[WRITE])
- wake_up(&rl->wait[WRITE]);
+ if (cfqq->allocated[READ] <= cfqd->max_queued || cfqd->rq_starved) {
+ smp_mb();
+ if (waitqueue_active(&rl->wait[READ]))
+ wake_up(&rl->wait[READ]);
+ }
+
+ if (cfqq->allocated[WRITE] <= cfqd->max_queued || cfqd->rq_starved) {
+ smp_mb();
+ if (waitqueue_active(&rl->wait[WRITE]))
+ wake_up(&rl->wait[WRITE]);
+ }
}
/*
@@ -1389,69 +2043,61 @@ static void cfq_put_request(request_queue_t *q, struct request *rq)
if (crq) {
struct cfq_queue *cfqq = crq->cfq_queue;
+ const int rw = rq_data_dir(rq);
- BUG_ON(q->last_merge == rq);
- BUG_ON(!hlist_unhashed(&crq->hash));
+ BUG_ON(!cfqq->allocated[rw]);
+ cfqq->allocated[rw]--;
- if (crq->io_context)
- put_io_context(crq->io_context->ioc);
-
- BUG_ON(!cfqq->allocated[crq->is_write]);
- cfqq->allocated[crq->is_write]--;
+ put_io_context(crq->io_context->ioc);
mempool_free(crq, cfqd->crq_pool);
rq->elevator_private = NULL;
- smp_mb();
cfq_check_waiters(q, cfqq);
cfq_put_queue(cfqq);
}
}
/*
- * Allocate cfq data structures associated with this request. A queue and
+ * Allocate cfq data structures associated with this request.
*/
-static int cfq_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+static int
+cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
+ int gfp_mask)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
+ struct task_struct *tsk = current;
struct cfq_io_context *cic;
const int rw = rq_data_dir(rq);
- struct cfq_queue *cfqq, *saved_cfqq;
+ pid_t key = cfq_queue_pid(tsk, rw);
+ struct cfq_queue *cfqq;
struct cfq_rq *crq;
unsigned long flags;
might_sleep_if(gfp_mask & __GFP_WAIT);
+ cic = cfq_get_io_context(cfqd, key, gfp_mask);
+
spin_lock_irqsave(q->queue_lock, flags);
- cfqq = __cfq_get_queue(cfqd, cfq_hash_key(cfqd, current), gfp_mask);
- if (!cfqq)
- goto out_lock;
+ if (!cic)
+ goto queue_fail;
+
+ if (!cic->cfqq) {
+ cfqq = cfq_get_queue(cfqd, key, tsk->ioprio, gfp_mask);
+ if (!cfqq)
+ goto queue_fail;
-repeat:
- if (cfqq->allocated[rw] >= cfqd->max_queued)
- goto out_lock;
+ cic->cfqq = cfqq;
+ } else
+ cfqq = cic->cfqq;
cfqq->allocated[rw]++;
+ cfq_clear_cfqq_must_alloc(cfqq);
+ cfqd->rq_starved = 0;
+ atomic_inc(&cfqq->ref);
spin_unlock_irqrestore(q->queue_lock, flags);
- /*
- * if hashing type has changed, the cfq_queue might change here.
- */
- saved_cfqq = cfqq;
- cic = cfq_get_io_context(&cfqq, gfp_mask);
- if (!cic)
- goto err;
-
- /*
- * repeat allocation checks on queue change
- */
- if (unlikely(saved_cfqq != cfqq)) {
- spin_lock_irqsave(q->queue_lock, flags);
- saved_cfqq->allocated[rw]--;
- goto repeat;
- }
-
crq = mempool_alloc(cfqd->crq_pool, gfp_mask);
if (crq) {
RB_CLEAR(&crq->rb_node);
@@ -1460,24 +2106,141 @@ repeat:
INIT_HLIST_NODE(&crq->hash);
crq->cfq_queue = cfqq;
crq->io_context = cic;
- crq->service_start = crq->queue_start = 0;
- crq->in_flight = crq->accounted = crq->is_sync = 0;
- crq->is_write = rw;
+ cfq_clear_crq_in_flight(crq);
+ cfq_clear_crq_in_driver(crq);
+ cfq_clear_crq_requeued(crq);
+
+ if (rw == READ || process_sync(tsk))
+ cfq_mark_crq_is_sync(crq);
+ else
+ cfq_clear_crq_is_sync(crq);
+
rq->elevator_private = crq;
- cfqq->alloc_limit[rw] = 0;
return 0;
}
- put_io_context(cic->ioc);
-err:
spin_lock_irqsave(q->queue_lock, flags);
cfqq->allocated[rw]--;
+ if (!(cfqq->allocated[0] + cfqq->allocated[1]))
+ cfq_mark_cfqq_must_alloc(cfqq);
cfq_put_queue(cfqq);
-out_lock:
+queue_fail:
+ if (cic)
+ put_io_context(cic->ioc);
+ /*
+ * mark us rq allocation starved. we need to kickstart the process
+ * ourselves if there are no pending requests that can do it for us.
+ * that would be an extremely rare OOM situation
+ */
+ cfqd->rq_starved = 1;
+ cfq_schedule_dispatch(cfqd);
spin_unlock_irqrestore(q->queue_lock, flags);
return 1;
}
+static void cfq_kick_queue(void *data)
+{
+ request_queue_t *q = data;
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+
+ if (cfqd->rq_starved) {
+ struct request_list *rl = &q->rq;
+
+ /*
+ * we aren't guaranteed to get a request after this, but we
+ * have to be opportunistic
+ */
+ smp_mb();
+ if (waitqueue_active(&rl->wait[READ]))
+ wake_up(&rl->wait[READ]);
+ if (waitqueue_active(&rl->wait[WRITE]))
+ wake_up(&rl->wait[WRITE]);
+ }
+
+ blk_remove_plug(q);
+ q->request_fn(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+}
+
+/*
+ * Timer running if the active_queue is currently idling inside its time slice
+ */
+static void cfq_idle_slice_timer(unsigned long data)
+{
+ struct cfq_data *cfqd = (struct cfq_data *) data;
+ struct cfq_queue *cfqq;
+ unsigned long flags;
+
+ spin_lock_irqsave(cfqd->queue->queue_lock, flags);
+
+ if ((cfqq = cfqd->active_queue) != NULL) {
+ unsigned long now = jiffies;
+
+ /*
+ * expired
+ */
+ if (time_after(now, cfqq->slice_end))
+ goto expire;
+
+ /*
+ * only expire and reinvoke request handler, if there are
+ * other queues with pending requests
+ */
+ if (!cfq_pending_requests(cfqd)) {
+ cfqd->idle_slice_timer.expires = min(now + cfqd->cfq_slice_idle, cfqq->slice_end);
+ add_timer(&cfqd->idle_slice_timer);
+ goto out_cont;
+ }
+
+ /*
+ * not expired and it has a request pending, let it dispatch
+ */
+ if (!RB_EMPTY(&cfqq->sort_list)) {
+ cfq_mark_cfqq_must_dispatch(cfqq);
+ goto out_kick;
+ }
+ }
+expire:
+ cfq_slice_expired(cfqd, 0);
+out_kick:
+ cfq_schedule_dispatch(cfqd);
+out_cont:
+ spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
+}
+
+/*
+ * Timer running if an idle class queue is waiting for service
+ */
+static void cfq_idle_class_timer(unsigned long data)
+{
+ struct cfq_data *cfqd = (struct cfq_data *) data;
+ unsigned long flags, end;
+
+ spin_lock_irqsave(cfqd->queue->queue_lock, flags);
+
+ /*
+ * race with a non-idle queue, reset timer
+ */
+ end = cfqd->last_end_request + CFQ_IDLE_GRACE;
+ if (!time_after_eq(jiffies, end)) {
+ cfqd->idle_class_timer.expires = end;
+ add_timer(&cfqd->idle_class_timer);
+ } else
+ cfq_schedule_dispatch(cfqd);
+
+ spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
+}
+
+static void cfq_shutdown_timer_wq(struct cfq_data *cfqd)
+{
+ del_timer_sync(&cfqd->idle_slice_timer);
+ del_timer_sync(&cfqd->idle_class_timer);
+ blk_sync_queue(cfqd->queue);
+}
+
static void cfq_put_cfqd(struct cfq_data *cfqd)
{
request_queue_t *q = cfqd->queue;
@@ -1487,6 +2250,9 @@ static void cfq_put_cfqd(struct cfq_data *cfqd)
blk_put_queue(q);
+ cfq_shutdown_timer_wq(cfqd);
+ q->elevator->elevator_data = NULL;
+
mempool_destroy(cfqd->crq_pool);
kfree(cfqd->crq_hash);
kfree(cfqd->cfq_hash);
@@ -1495,7 +2261,10 @@ static void cfq_put_cfqd(struct cfq_data *cfqd)
static void cfq_exit_queue(elevator_t *e)
{
- cfq_put_cfqd(e->elevator_data);
+ struct cfq_data *cfqd = e->elevator_data;
+
+ cfq_shutdown_timer_wq(cfqd);
+ cfq_put_cfqd(cfqd);
}
static int cfq_init_queue(request_queue_t *q, elevator_t *e)
@@ -1508,7 +2277,13 @@ static int cfq_init_queue(request_queue_t *q, elevator_t *e)
return -ENOMEM;
memset(cfqd, 0, sizeof(*cfqd));
- INIT_LIST_HEAD(&cfqd->rr_list);
+
+ for (i = 0; i < CFQ_PRIO_LISTS; i++)
+ INIT_LIST_HEAD(&cfqd->rr_list[i]);
+
+ INIT_LIST_HEAD(&cfqd->busy_rr);
+ INIT_LIST_HEAD(&cfqd->cur_rr);
+ INIT_LIST_HEAD(&cfqd->idle_rr);
INIT_LIST_HEAD(&cfqd->empty_list);
cfqd->crq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_MHASH_ENTRIES, GFP_KERNEL);
@@ -1533,24 +2308,32 @@ static int cfq_init_queue(request_queue_t *q, elevator_t *e)
cfqd->queue = q;
atomic_inc(&q->refcnt);
- /*
- * just set it to some high value, we want anyone to be able to queue
- * some requests. fairness is handled differently
- */
- q->nr_requests = 1024;
- cfqd->max_queued = q->nr_requests / 16;
+ cfqd->max_queued = q->nr_requests / 4;
q->nr_batching = cfq_queued;
- cfqd->key_type = CFQ_KEY_TGID;
- cfqd->find_best_crq = 1;
+
+ init_timer(&cfqd->idle_slice_timer);
+ cfqd->idle_slice_timer.function = cfq_idle_slice_timer;
+ cfqd->idle_slice_timer.data = (unsigned long) cfqd;
+
+ init_timer(&cfqd->idle_class_timer);
+ cfqd->idle_class_timer.function = cfq_idle_class_timer;
+ cfqd->idle_class_timer.data = (unsigned long) cfqd;
+
+ INIT_WORK(&cfqd->unplug_work, cfq_kick_queue, q);
+
atomic_set(&cfqd->ref, 1);
cfqd->cfq_queued = cfq_queued;
cfqd->cfq_quantum = cfq_quantum;
- cfqd->cfq_fifo_expire_r = cfq_fifo_expire_r;
- cfqd->cfq_fifo_expire_w = cfq_fifo_expire_w;
- cfqd->cfq_fifo_batch_expire = cfq_fifo_rate;
+ cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0];
+ cfqd->cfq_fifo_expire[1] = cfq_fifo_expire[1];
cfqd->cfq_back_max = cfq_back_max;
cfqd->cfq_back_penalty = cfq_back_penalty;
+ cfqd->cfq_slice[0] = cfq_slice_async;
+ cfqd->cfq_slice[1] = cfq_slice_sync;
+ cfqd->cfq_slice_async_rq = cfq_slice_async_rq;
+ cfqd->cfq_slice_idle = cfq_slice_idle;
+ cfqd->cfq_max_depth = cfq_max_depth;
return 0;
out_crqpool:
@@ -1595,7 +2378,6 @@ fail:
return -ENOMEM;
}
-
/*
* sysfs parts below -->
*/
@@ -1620,45 +2402,6 @@ cfq_var_store(unsigned int *var, const char *page, size_t count)
return count;
}
-static ssize_t
-cfq_clear_elapsed(struct cfq_data *cfqd, const char *page, size_t count)
-{
- max_elapsed_dispatch = max_elapsed_crq = 0;
- return count;
-}
-
-static ssize_t
-cfq_set_key_type(struct cfq_data *cfqd, const char *page, size_t count)
-{
- spin_lock_irq(cfqd->queue->queue_lock);
- if (!strncmp(page, "pgid", 4))
- cfqd->key_type = CFQ_KEY_PGID;
- else if (!strncmp(page, "tgid", 4))
- cfqd->key_type = CFQ_KEY_TGID;
- else if (!strncmp(page, "uid", 3))
- cfqd->key_type = CFQ_KEY_UID;
- else if (!strncmp(page, "gid", 3))
- cfqd->key_type = CFQ_KEY_GID;
- spin_unlock_irq(cfqd->queue->queue_lock);
- return count;
-}
-
-static ssize_t
-cfq_read_key_type(struct cfq_data *cfqd, char *page)
-{
- ssize_t len = 0;
- int i;
-
- for (i = CFQ_KEY_PGID; i < CFQ_KEY_LAST; i++) {
- if (cfqd->key_type == i)
- len += sprintf(page+len, "[%s] ", cfq_key_types[i]);
- else
- len += sprintf(page+len, "%s ", cfq_key_types[i]);
- }
- len += sprintf(page+len, "\n");
- return len;
-}
-
#define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \
static ssize_t __FUNC(struct cfq_data *cfqd, char *page) \
{ \
@@ -1669,12 +2412,15 @@ static ssize_t __FUNC(struct cfq_data *cfqd, char *page) \
}
SHOW_FUNCTION(cfq_quantum_show, cfqd->cfq_quantum, 0);
SHOW_FUNCTION(cfq_queued_show, cfqd->cfq_queued, 0);
-SHOW_FUNCTION(cfq_fifo_expire_r_show, cfqd->cfq_fifo_expire_r, 1);
-SHOW_FUNCTION(cfq_fifo_expire_w_show, cfqd->cfq_fifo_expire_w, 1);
-SHOW_FUNCTION(cfq_fifo_batch_expire_show, cfqd->cfq_fifo_batch_expire, 1);
-SHOW_FUNCTION(cfq_find_best_show, cfqd->find_best_crq, 0);
+SHOW_FUNCTION(cfq_fifo_expire_sync_show, cfqd->cfq_fifo_expire[1], 1);
+SHOW_FUNCTION(cfq_fifo_expire_async_show, cfqd->cfq_fifo_expire[0], 1);
SHOW_FUNCTION(cfq_back_max_show, cfqd->cfq_back_max, 0);
SHOW_FUNCTION(cfq_back_penalty_show, cfqd->cfq_back_penalty, 0);
+SHOW_FUNCTION(cfq_slice_idle_show, cfqd->cfq_slice_idle, 1);
+SHOW_FUNCTION(cfq_slice_sync_show, cfqd->cfq_slice[1], 1);
+SHOW_FUNCTION(cfq_slice_async_show, cfqd->cfq_slice[0], 1);
+SHOW_FUNCTION(cfq_slice_async_rq_show, cfqd->cfq_slice_async_rq, 0);
+SHOW_FUNCTION(cfq_max_depth_show, cfqd->cfq_max_depth, 0);
#undef SHOW_FUNCTION
#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \
@@ -1694,12 +2440,15 @@ static ssize_t __FUNC(struct cfq_data *cfqd, const char *page, size_t count) \
}
STORE_FUNCTION(cfq_quantum_store, &cfqd->cfq_quantum, 1, UINT_MAX, 0);
STORE_FUNCTION(cfq_queued_store, &cfqd->cfq_queued, 1, UINT_MAX, 0);
-STORE_FUNCTION(cfq_fifo_expire_r_store, &cfqd->cfq_fifo_expire_r, 1, UINT_MAX, 1);
-STORE_FUNCTION(cfq_fifo_expire_w_store, &cfqd->cfq_fifo_expire_w, 1, UINT_MAX, 1);
-STORE_FUNCTION(cfq_fifo_batch_expire_store, &cfqd->cfq_fifo_batch_expire, 0, UINT_MAX, 1);
-STORE_FUNCTION(cfq_find_best_store, &cfqd->find_best_crq, 0, 1, 0);
+STORE_FUNCTION(cfq_fifo_expire_sync_store, &cfqd->cfq_fifo_expire[1], 1, UINT_MAX, 1);
+STORE_FUNCTION(cfq_fifo_expire_async_store, &cfqd->cfq_fifo_expire[0], 1, UINT_MAX, 1);
STORE_FUNCTION(cfq_back_max_store, &cfqd->cfq_back_max, 0, UINT_MAX, 0);
STORE_FUNCTION(cfq_back_penalty_store, &cfqd->cfq_back_penalty, 1, UINT_MAX, 0);
+STORE_FUNCTION(cfq_slice_idle_store, &cfqd->cfq_slice_idle, 0, UINT_MAX, 1);
+STORE_FUNCTION(cfq_slice_sync_store, &cfqd->cfq_slice[1], 1, UINT_MAX, 1);
+STORE_FUNCTION(cfq_slice_async_store, &cfqd->cfq_slice[0], 1, UINT_MAX, 1);
+STORE_FUNCTION(cfq_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1, UINT_MAX, 0);
+STORE_FUNCTION(cfq_max_depth_store, &cfqd->cfq_max_depth, 1, UINT_MAX, 0);
#undef STORE_FUNCTION
static struct cfq_fs_entry cfq_quantum_entry = {
@@ -1712,25 +2461,15 @@ static struct cfq_fs_entry cfq_queued_entry = {
.show = cfq_queued_show,
.store = cfq_queued_store,
};
-static struct cfq_fs_entry cfq_fifo_expire_r_entry = {
+static struct cfq_fs_entry cfq_fifo_expire_sync_entry = {
.attr = {.name = "fifo_expire_sync", .mode = S_IRUGO | S_IWUSR },
- .show = cfq_fifo_expire_r_show,
- .store = cfq_fifo_expire_r_store,
+ .show = cfq_fifo_expire_sync_show,
+ .store = cfq_fifo_expire_sync_store,
};
-static struct cfq_fs_entry cfq_fifo_expire_w_entry = {
+static struct cfq_fs_entry cfq_fifo_expire_async_entry = {
.attr = {.name = "fifo_expire_async", .mode = S_IRUGO | S_IWUSR },
- .show = cfq_fifo_expire_w_show,
- .store = cfq_fifo_expire_w_store,
-};
-static struct cfq_fs_entry cfq_fifo_batch_expire_entry = {
- .attr = {.name = "fifo_batch_expire", .mode = S_IRUGO | S_IWUSR },
- .show = cfq_fifo_batch_expire_show,
- .store = cfq_fifo_batch_expire_store,
-};
-static struct cfq_fs_entry cfq_find_best_entry = {
- .attr = {.name = "find_best_crq", .mode = S_IRUGO | S_IWUSR },
- .show = cfq_find_best_show,
- .store = cfq_find_best_store,
+ .show = cfq_fifo_expire_async_show,
+ .store = cfq_fifo_expire_async_store,
};
static struct cfq_fs_entry cfq_back_max_entry = {
.attr = {.name = "back_seek_max", .mode = S_IRUGO | S_IWUSR },
@@ -1742,27 +2481,44 @@ static struct cfq_fs_entry cfq_back_penalty_entry = {
.show = cfq_back_penalty_show,
.store = cfq_back_penalty_store,
};
-static struct cfq_fs_entry cfq_clear_elapsed_entry = {
- .attr = {.name = "clear_elapsed", .mode = S_IWUSR },
- .store = cfq_clear_elapsed,
+static struct cfq_fs_entry cfq_slice_sync_entry = {
+ .attr = {.name = "slice_sync", .mode = S_IRUGO | S_IWUSR },
+ .show = cfq_slice_sync_show,
+ .store = cfq_slice_sync_store,
+};
+static struct cfq_fs_entry cfq_slice_async_entry = {
+ .attr = {.name = "slice_async", .mode = S_IRUGO | S_IWUSR },
+ .show = cfq_slice_async_show,
+ .store = cfq_slice_async_store,
};
-static struct cfq_fs_entry cfq_key_type_entry = {
- .attr = {.name = "key_type", .mode = S_IRUGO | S_IWUSR },
- .show = cfq_read_key_type,
- .store = cfq_set_key_type,
+static struct cfq_fs_entry cfq_slice_async_rq_entry = {
+ .attr = {.name = "slice_async_rq", .mode = S_IRUGO | S_IWUSR },
+ .show = cfq_slice_async_rq_show,
+ .store = cfq_slice_async_rq_store,
+};
+static struct cfq_fs_entry cfq_slice_idle_entry = {
+ .attr = {.name = "slice_idle", .mode = S_IRUGO | S_IWUSR },
+ .show = cfq_slice_idle_show,
+ .store = cfq_slice_idle_store,
+};
+static struct cfq_fs_entry cfq_max_depth_entry = {
+ .attr = {.name = "max_depth", .mode = S_IRUGO | S_IWUSR },
+ .show = cfq_max_depth_show,
+ .store = cfq_max_depth_store,
};
static struct attribute *default_attrs[] = {
&cfq_quantum_entry.attr,
&cfq_queued_entry.attr,
- &cfq_fifo_expire_r_entry.attr,
- &cfq_fifo_expire_w_entry.attr,
- &cfq_fifo_batch_expire_entry.attr,
- &cfq_key_type_entry.attr,
- &cfq_find_best_entry.attr,
+ &cfq_fifo_expire_sync_entry.attr,
+ &cfq_fifo_expire_async_entry.attr,
&cfq_back_max_entry.attr,
&cfq_back_penalty_entry.attr,
- &cfq_clear_elapsed_entry.attr,
+ &cfq_slice_sync_entry.attr,
+ &cfq_slice_async_entry.attr,
+ &cfq_slice_async_rq_entry.attr,
+ &cfq_slice_idle_entry.attr,
+ &cfq_max_depth_entry.attr,
NULL,
};
@@ -1832,21 +2588,46 @@ static int __init cfq_init(void)
{
int ret;
+ /*
+ * could be 0 on HZ < 1000 setups
+ */
+ if (!cfq_slice_async)
+ cfq_slice_async = 1;
+ if (!cfq_slice_idle)
+ cfq_slice_idle = 1;
+
if (cfq_slab_setup())
return -ENOMEM;
ret = elv_register(&iosched_cfq);
- if (!ret) {
- __module_get(THIS_MODULE);
- return 0;
- }
+ if (ret)
+ cfq_slab_kill();
- cfq_slab_kill();
return ret;
}
static void __exit cfq_exit(void)
{
+ struct task_struct *g, *p;
+ unsigned long flags;
+
+ read_lock_irqsave(&tasklist_lock, flags);
+
+ /*
+ * iterate each process in the system, removing our io_context
+ */
+ do_each_thread(g, p) {
+ struct io_context *ioc = p->io_context;
+
+ if (ioc && ioc->cic) {
+ ioc->cic->exit(ioc->cic);
+ cfq_free_io_context(ioc->cic);
+ ioc->cic = NULL;
+ }
+ } while_each_thread(g, p);
+
+ read_unlock_irqrestore(&tasklist_lock, flags);
+
cfq_slab_kill();
elv_unregister(&iosched_cfq);
}
diff --git a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c
index 4bc2fea7327..ff5201e0215 100644
--- a/drivers/block/deadline-iosched.c
+++ b/drivers/block/deadline-iosched.c
@@ -760,7 +760,8 @@ static void deadline_put_request(request_queue_t *q, struct request *rq)
}
static int
-deadline_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+deadline_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
+ int gfp_mask)
{
struct deadline_data *dd = q->elevator->elevator_data;
struct deadline_rq *drq;
diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c
index f831f08f839..98f0126a2de 100644
--- a/drivers/block/elevator.c
+++ b/drivers/block/elevator.c
@@ -486,12 +486,13 @@ struct request *elv_former_request(request_queue_t *q, struct request *rq)
return NULL;
}
-int elv_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+int elv_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
+ int gfp_mask)
{
elevator_t *e = q->elevator;
if (e->ops->elevator_set_req_fn)
- return e->ops->elevator_set_req_fn(q, rq, gfp_mask);
+ return e->ops->elevator_set_req_fn(q, rq, bio, gfp_mask);
rq->elevator_private = NULL;
return 0;
@@ -505,12 +506,12 @@ void elv_put_request(request_queue_t *q, struct request *rq)
e->ops->elevator_put_req_fn(q, rq);
}
-int elv_may_queue(request_queue_t *q, int rw)
+int elv_may_queue(request_queue_t *q, int rw, struct bio *bio)
{
elevator_t *e = q->elevator;
if (e->ops->elevator_may_queue_fn)
- return e->ops->elevator_may_queue_fn(q, rw);
+ return e->ops->elevator_may_queue_fn(q, rw, bio);
return ELV_MQUEUE_MAY;
}
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 60e64091de1..234fdcfbdf0 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -276,6 +276,7 @@ static inline void rq_init(request_queue_t *q, struct request *rq)
rq->errors = 0;
rq->rq_status = RQ_ACTIVE;
rq->bio = rq->biotail = NULL;
+ rq->ioprio = 0;
rq->buffer = NULL;
rq->ref_count = 1;
rq->q = q;
@@ -1442,11 +1443,7 @@ void __generic_unplug_device(request_queue_t *q)
if (!blk_remove_plug(q))
return;
- /*
- * was plugged, fire request_fn if queue has stuff to do
- */
- if (elv_next_request(q))
- q->request_fn(q);
+ q->request_fn(q);
}
EXPORT_SYMBOL(__generic_unplug_device);
@@ -1776,8 +1773,8 @@ static inline void blk_free_request(request_queue_t *q, struct request *rq)
mempool_free(rq, q->rq.rq_pool);
}
-static inline struct request *blk_alloc_request(request_queue_t *q, int rw,
- int gfp_mask)
+static inline struct request *
+blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, int gfp_mask)
{
struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask);
@@ -1790,7 +1787,7 @@ static inline struct request *blk_alloc_request(request_queue_t *q, int rw,
*/
rq->flags = rw;
- if (!elv_set_request(q, rq, gfp_mask))
+ if (!elv_set_request(q, rq, bio, gfp_mask))
return rq;
mempool_free(rq, q->rq.rq_pool);
@@ -1872,7 +1869,8 @@ static void freed_request(request_queue_t *q, int rw)
/*
* Get a free request, queue_lock must not be held
*/
-static struct request *get_request(request_queue_t *q, int rw, int gfp_mask)
+static struct request *get_request(request_queue_t *q, int rw, struct bio *bio,
+ int gfp_mask)
{
struct request *rq = NULL;
struct request_list *rl = &q->rq;
@@ -1895,7 +1893,7 @@ static struct request *get_request(request_queue_t *q, int rw, int gfp_mask)
}
}
- switch (elv_may_queue(q, rw)) {
+ switch (elv_may_queue(q, rw, bio)) {
case ELV_MQUEUE_NO:
goto rq_starved;
case ELV_MQUEUE_MAY:
@@ -1920,7 +1918,7 @@ get_rq:
set_queue_congested(q, rw);
spin_unlock_irq(q->queue_lock);
- rq = blk_alloc_request(q, rw, gfp_mask);
+ rq = blk_alloc_request(q, rw, bio, gfp_mask);
if (!rq) {
/*
* Allocation failed presumably due to memory. Undo anything
@@ -1961,7 +1959,8 @@ out:
* No available requests for this queue, unplug the device and wait for some
* requests to become available.
*/
-static struct request *get_request_wait(request_queue_t *q, int rw)
+static struct request *get_request_wait(request_queue_t *q, int rw,
+ struct bio *bio)
{
DEFINE_WAIT(wait);
struct request *rq;
@@ -1972,7 +1971,7 @@ static struct request *get_request_wait(request_queue_t *q, int rw)
prepare_to_wait_exclusive(&rl->wait[rw], &wait,
TASK_UNINTERRUPTIBLE);
- rq = get_request(q, rw, GFP_NOIO);
+ rq = get_request(q, rw, bio, GFP_NOIO);
if (!rq) {
struct io_context *ioc;
@@ -2003,9 +2002,9 @@ struct request *blk_get_request(request_queue_t *q, int rw, int gfp_mask)
BUG_ON(rw != READ && rw != WRITE);
if (gfp_mask & __GFP_WAIT)
- rq = get_request_wait(q, rw);
+ rq = get_request_wait(q, rw, NULL);
else
- rq = get_request(q, rw, gfp_mask);
+ rq = get_request(q, rw, NULL, gfp_mask);
return rq;
}
@@ -2333,7 +2332,6 @@ static void __blk_put_request(request_queue_t *q, struct request *req)
return;
req->rq_status = RQ_INACTIVE;
- req->q = NULL;
req->rl = NULL;
/*
@@ -2462,6 +2460,8 @@ static int attempt_merge(request_queue_t *q, struct request *req,
req->rq_disk->in_flight--;
}
+ req->ioprio = ioprio_best(req->ioprio, next->ioprio);
+
__blk_put_request(q, next);
return 1;
}
@@ -2514,11 +2514,13 @@ static int __make_request(request_queue_t *q, struct bio *bio)
{
struct request *req, *freereq = NULL;
int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err, sync;
+ unsigned short prio;
sector_t sector;
sector = bio->bi_sector;
nr_sectors = bio_sectors(bio);
cur_nr_sectors = bio_cur_sectors(bio);
+ prio = bio_prio(bio);
rw = bio_data_dir(bio);
sync = bio_sync(bio);
@@ -2559,6 +2561,7 @@ again:
req->biotail->bi_next = bio;
req->biotail = bio;
req->nr_sectors = req->hard_nr_sectors += nr_sectors;
+ req->ioprio = ioprio_best(req->ioprio, prio);
drive_stat_acct(req, nr_sectors, 0);
if (!attempt_back_merge(q, req))
elv_merged_request(q, req);
@@ -2583,6 +2586,7 @@ again:
req->hard_cur_sectors = cur_nr_sectors;
req->sector = req->hard_sector = sector;
req->nr_sectors = req->hard_nr_sectors += nr_sectors;
+ req->ioprio = ioprio_best(req->ioprio, prio);
drive_stat_acct(req, nr_sectors, 0);
if (!attempt_front_merge(q, req))
elv_merged_request(q, req);
@@ -2610,7 +2614,7 @@ get_rq:
freereq = NULL;
} else {
spin_unlock_irq(q->queue_lock);
- if ((freereq = get_request(q, rw, GFP_ATOMIC)) == NULL) {
+ if ((freereq = get_request(q, rw, bio, GFP_ATOMIC)) == NULL) {
/*
* READA bit set
*/
@@ -2618,7 +2622,7 @@ get_rq:
if (bio_rw_ahead(bio))
goto end_io;
- freereq = get_request_wait(q, rw);
+ freereq = get_request_wait(q, rw, bio);
}
goto again;
}
@@ -2646,6 +2650,7 @@ get_rq:
req->buffer = bio_data(bio); /* see ->buffer comment above */
req->waiting = NULL;
req->bio = req->biotail = bio;
+ req->ioprio = prio;
req->rq_disk = bio->bi_bdev->bd_disk;
req->start_time = jiffies;
@@ -2674,7 +2679,7 @@ static inline void blk_partition_remap(struct bio *bio)
if (bdev != bdev->bd_contains) {
struct hd_struct *p = bdev->bd_part;
- switch (bio->bi_rw) {
+ switch (bio_data_dir(bio)) {
case READ:
p->read_sectors += bio_sectors(bio);
p->reads++;
@@ -2693,6 +2698,7 @@ void blk_finish_queue_drain(request_queue_t *q)
{
struct request_list *rl = &q->rq;
struct request *rq;
+ int requeued = 0;
spin_lock_irq(q->queue_lock);
clear_bit(QUEUE_FLAG_DRAIN, &q->queue_flags);
@@ -2701,9 +2707,13 @@ void blk_finish_queue_drain(request_queue_t *q)
rq = list_entry_rq(q->drain_list.next);
list_del_init(&rq->queuelist);
- __elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
+ elv_requeue_request(q, rq);
+ requeued++;
}
+ if (requeued)
+ q->request_fn(q);
+
spin_unlock_irq(q->queue_lock);
wake_up(&rl->wait[0]);
@@ -2900,7 +2910,7 @@ void submit_bio(int rw, struct bio *bio)
BIO_BUG_ON(!bio->bi_size);
BIO_BUG_ON(!bio->bi_io_vec);
- bio->bi_rw = rw;
+ bio->bi_rw |= rw;
if (rw & WRITE)
mod_page_state(pgpgout, count);
else
@@ -3257,8 +3267,11 @@ void exit_io_context(void)
struct io_context *ioc;
local_irq_save(flags);
+ task_lock(current);
ioc = current->io_context;
current->io_context = NULL;
+ ioc->task = NULL;
+ task_unlock(current);
local_irq_restore(flags);
if (ioc->aic && ioc->aic->exit)
@@ -3293,12 +3306,12 @@ struct io_context *get_io_context(int gfp_flags)
ret = kmem_cache_alloc(iocontext_cachep, gfp_flags);
if (ret) {
atomic_set(&ret->refcount, 1);
- ret->pid = tsk->pid;
+ ret->task = current;
+ ret->set_ioprio = NULL;
ret->last_waited = jiffies; /* doesn't matter... */
ret->nr_batch_requests = 0; /* because this is 0 */
ret->aic = NULL;
ret->cic = NULL;
- spin_lock_init(&ret->lock);
local_irq_save(flags);
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index 5b09cf154ac..e5f7494c00e 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -253,7 +253,7 @@ static int floppy_revalidate(struct gendisk *disk);
static int swim3_add_device(struct device_node *swims);
int swim3_init(void);
-#ifndef CONFIG_PMAC_PBOOK
+#ifndef CONFIG_PMAC_MEDIABAY
#define check_media_bay(which, what) 1
#endif
@@ -297,9 +297,11 @@ static void do_fd_request(request_queue_t * q)
int i;
for(i=0;i<floppy_count;i++)
{
+#ifdef CONFIG_PMAC_MEDIABAY
if (floppy_states[i].media_bay &&
check_media_bay(floppy_states[i].media_bay, MB_FD))
continue;
+#endif /* CONFIG_PMAC_MEDIABAY */
start_request(&floppy_states[i]);
}
sti();
@@ -856,8 +858,10 @@ static int floppy_ioctl(struct inode *inode, struct file *filp,
if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
return -EPERM;
+#ifdef CONFIG_PMAC_MEDIABAY
if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
return -ENXIO;
+#endif
switch (cmd) {
case FDEJECT:
@@ -881,8 +885,10 @@ static int floppy_open(struct inode *inode, struct file *filp)
int n, err = 0;
if (fs->ref_count == 0) {
+#ifdef CONFIG_PMAC_MEDIABAY
if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
return -ENXIO;
+#endif
out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2);
out_8(&sw->control_bic, 0xff);
out_8(&sw->mode, 0x95);
@@ -967,8 +973,10 @@ static int floppy_revalidate(struct gendisk *disk)
struct swim3 __iomem *sw;
int ret, n;
+#ifdef CONFIG_PMAC_MEDIABAY
if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
return -ENXIO;
+#endif
sw = fs->swim3;
grab_drive(fs, revalidating, 0);
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 5ed3a637945..9db0a9e3e59 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/time.h>
#include <linux/hdreg.h>
+#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
@@ -1582,9 +1583,9 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out;
#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */
- rc = pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
+ rc = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
if (!rc) {
- rc = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
if (rc) {
printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n",
pci_name(pdev));
@@ -1593,7 +1594,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pci_dac = 1;
} else {
#endif
- rc = pci_set_dma_mask(pdev, 0xffffffffULL);
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (rc) {
printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n",
pci_name(pdev));
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index e481cc411b5..5ef9adb9fe7 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -1089,6 +1089,14 @@ static int bluecard_event(event_t event, int priority, event_callback_args_t *ar
return 0;
}
+static struct pcmcia_device_id bluecard_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("BlueCard", "LSE041", 0xbaf16fbf, 0x657cc15e),
+ PCMCIA_DEVICE_PROD_ID12("BTCFCARD", "LSE139", 0xe3987764, 0x2524b59c),
+ PCMCIA_DEVICE_PROD_ID12("WSS", "LSE039", 0x0a0736ec, 0x24e6dfab),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, bluecard_ids);
+
static struct pcmcia_driver bluecard_driver = {
.owner = THIS_MODULE,
.drv = {
@@ -1096,6 +1104,7 @@ static struct pcmcia_driver bluecard_driver = {
},
.attach = bluecard_attach,
.detach = bluecard_detach,
+ .id_table = bluecard_ids,
};
static int __init init_bluecard_cs(void)
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index f71e5c76963..9013cd759af 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -935,6 +935,12 @@ static int bt3c_event(event_t event, int priority, event_callback_args_t *args)
return 0;
}
+static struct pcmcia_device_id bt3c_ids[] = {
+ PCMCIA_DEVICE_PROD_ID13("3COM", "Bluetooth PC Card", 0xefce0a31, 0xd4ce9b02),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, bt3c_ids);
+
static struct pcmcia_driver bt3c_driver = {
.owner = THIS_MODULE,
.drv = {
@@ -942,6 +948,7 @@ static struct pcmcia_driver bt3c_driver = {
},
.attach = bt3c_attach,
.detach = bt3c_detach,
+ .id_table = bt3c_ids,
};
static int __init init_bt3c_cs(void)
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index ad8d972444a..c479484a1f7 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -855,6 +855,12 @@ static int btuart_event(event_t event, int priority, event_callback_args_t *args
return 0;
}
+static struct pcmcia_device_id btuart_ids[] = {
+ /* don't use this driver. Use serial_cs + hci_uart instead */
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, btuart_ids);
+
static struct pcmcia_driver btuart_driver = {
.owner = THIS_MODULE,
.drv = {
@@ -862,6 +868,7 @@ static struct pcmcia_driver btuart_driver = {
},
.attach = btuart_attach,
.detach = btuart_detach,
+ .id_table = btuart_ids,
};
static int __init init_btuart_cs(void)
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index fe954e5d9a1..bb12f7daeb9 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -807,6 +807,13 @@ static int dtl1_event(event_t event, int priority, event_callback_args_t *args)
return 0;
}
+static struct pcmcia_device_id dtl1_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
+ PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, dtl1_ids);
+
static struct pcmcia_driver dtl1_driver = {
.owner = THIS_MODULE,
.drv = {
@@ -814,6 +821,7 @@ static struct pcmcia_driver dtl1_driver = {
},
.attach = dtl1_attach,
.detach = dtl1_detach,
+ .id_table = dtl1_ids,
};
static int __init init_dtl1_cs(void)
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 31cf84d6902..931efd58f87 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -309,9 +309,6 @@ static int __init misc_init(void)
#ifdef CONFIG_BVME6000
rtc_DP8570A_init();
#endif
-#ifdef CONFIG_PMAC_PBOOK
- pmu_device_init();
-#endif
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
printk("unable to get major %d for misc devices\n",
MISC_MAJOR);
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 1c8d866a49d..8f36b1758eb 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -581,7 +581,7 @@ static dev_link_t *mgslpc_attach(void)
/* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
- link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+ link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = NULL;
link->conf.Attributes = 0;
@@ -3081,6 +3081,12 @@ void mgslpc_remove_device(MGSLPC_INFO *remove_info)
}
}
+static struct pcmcia_device_id mgslpc_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x02c5, 0x0050),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, mgslpc_ids);
+
static struct pcmcia_driver mgslpc_driver = {
.owner = THIS_MODULE,
.drv = {
@@ -3088,6 +3094,7 @@ static struct pcmcia_driver mgslpc_driver = {
},
.attach = mgslpc_attach,
.detach = mgslpc_detach,
+ .id_table = mgslpc_ids,
};
static struct tty_operations mgslpc_ops = {
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 0273f124a4f..5f33df47aa7 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -606,6 +606,12 @@ config BLK_DEV_IT8172
<http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the
board at <http://www.mvista.com/partners/semiconductor/ite.html>.
+config BLK_DEV_IT821X
+ tristate "IT821X IDE support"
+ help
+ This driver adds support for the ITE 8211 IDE controller and the
+ IT 8212 IDE RAID controller in both RAID and pass-through mode.
+
config BLK_DEV_NS87415
tristate "NS87415 chipset support"
help
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index d6f934886b0..f9c1acb4ed6 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -119,6 +119,10 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
{
unsigned long lba_sects, chs_sects, head, tail;
+ /* No non-LBA info .. so valid! */
+ if (id->cyls == 0)
+ return 1;
+
/*
* The ATA spec tells large drives to return
* C/H/S = 16383/16/63 independent of their size.
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 2d2eefb610d..1e1531334c2 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -132,7 +132,6 @@ static const struct drive_list_entry drive_blacklist [] = {
{ "SAMSUNG CD-ROM SC-148C", "ALL" },
{ "SAMSUNG CD-ROM SC", "ALL" },
{ "SanDisk SDP3B-64" , "ALL" },
- { "SAMSUNG CD-ROM SN-124", "ALL" },
{ "ATAPI CD-ROM DRIVE 40X MAXIMUM", "ALL" },
{ "_NEC DV5800A", "ALL" },
{ NULL , NULL }
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 53024942a7e..b443b04a4c5 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -1181,7 +1181,8 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
pre_reset(drive);
SELECT_DRIVE(drive);
udelay (20);
- hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
+ hwif->OUTBSYNC(drive, WIN_SRST, IDE_COMMAND_REG);
+ ndelay(400);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
hwgroup->polling = 1;
__ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index e20327e54b1..978d27d6452 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -457,6 +457,40 @@ int ide_event(event_t event, int priority,
return 0;
} /* ide_event */
+static struct pcmcia_device_id ide_ids[] = {
+ PCMCIA_DEVICE_FUNC_ID(4),
+ PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
+ PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
+ PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001),
+ PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),
+ PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0),
+ PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74),
+ PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9),
+ PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591),
+ PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728),
+ PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591),
+ PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4),
+ PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde),
+ PCMCIA_DEVICE_PROD_ID12("EXP", "CD", 0x6f58c983, 0xaae5994f),
+ PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591),
+ PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
+ PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
+ PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b),
+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
+ PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2 ", 0xe37be2b5, 0x8671043b),
+ PCMCIA_DEVICE_PROD_ID12(" ", "NinjaATA-", 0x3b6e20c8, 0xebe0bd79),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728),
+ PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1),
+ PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
+ PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
+ PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, ide_ids);
+
static struct pcmcia_driver ide_cs_driver = {
.owner = THIS_MODULE,
.drv = {
@@ -464,6 +498,7 @@ static struct pcmcia_driver ide_cs_driver = {
},
.attach = ide_attach,
.detach = ide_detach,
+ .id_table = ide_ids,
};
static int __init init_ide_cs(void)
diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
index 55e6e553e49..af46226c179 100644
--- a/drivers/ide/pci/Makefile
+++ b/drivers/ide/pci/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o
obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o
#obj-$(CONFIG_BLK_DEV_HPT37X) += hpt37x.o
obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o
+obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o
obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o
obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o
obj-$(CONFIG_BLK_DEV_PDC202XX_OLD) += pdc202xx_old.o
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
index 4565cc311ff..da46577380f 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/pci/generic.c
@@ -39,6 +39,17 @@
#include <asm/io.h>
+static int ide_generic_all; /* Set to claim all devices */
+
+static int __init ide_generic_all_on(char *unused)
+{
+ ide_generic_all = 1;
+ printk(KERN_INFO "IDE generic will claim all unknown PCI IDE storage controllers.\n");
+ return 1;
+}
+
+__setup("all-generic-ide", ide_generic_all_on);
+
static void __devinit init_hwif_generic (ide_hwif_t *hwif)
{
switch(hwif->pci_dev->device) {
@@ -78,79 +89,85 @@ static void __devinit init_hwif_generic (ide_hwif_t *hwif)
static ide_pci_device_t generic_chipsets[] __devinitdata = {
{ /* 0 */
+ .name = "Unknown",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+ },{ /* 1 */
.name = "NS87410",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
.bootable = ON_BOARD,
- },{ /* 1 */
+ },{ /* 2 */
.name = "SAMURAI",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
- },{ /* 2 */
+ },{ /* 3 */
.name = "HT6565",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
- },{ /* 3 */
+ },{ /* 4 */
.name = "UM8673F",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = NODMA,
.bootable = ON_BOARD,
- },{ /* 4 */
+ },{ /* 5 */
.name = "UM8886A",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = NODMA,
.bootable = ON_BOARD,
- },{ /* 5 */
+ },{ /* 6 */
.name = "UM8886BF",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = NODMA,
.bootable = ON_BOARD,
- },{ /* 6 */
+ },{ /* 7 */
.name = "HINT_IDE",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
- },{ /* 7 */
+ },{ /* 8 */
.name = "VIA_IDE",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
- },{ /* 8 */
+ },{ /* 9 */
.name = "OPTI621V",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
- },{ /* 9 */
+ },{ /* 10 */
.name = "VIA8237SATA",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
- },{ /* 10 */
+ },{ /* 11 */
.name = "Piccolo0102",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
- },{ /* 11 */
+ },{ /* 12 */
.name = "Piccolo0103",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
- },{ /* 12 */
+ },{ /* 13 */
.name = "Piccolo0105",
.init_hwif = init_hwif_generic,
.channels = 2,
@@ -174,6 +191,10 @@ static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_devi
u16 command;
int ret = -ENODEV;
+ /* Don't use the generic entry unless instructed to do so */
+ if (id->driver_data == 0 && ide_generic_all == 0)
+ goto out;
+
if (dev->vendor == PCI_VENDOR_ID_UMC &&
dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
(!(PCI_FUNC(dev->devfn) & 1)))
@@ -195,21 +216,23 @@ out:
}
static struct pci_device_id generic_pci_tbl[] = {
- { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
- { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
- { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
- { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
- { PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
- { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
- { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+ { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+ { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+ { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+ { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+ { PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
+ { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+ { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
#ifdef CONFIG_BLK_DEV_IDE_SATA
- { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
+ { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10},
#endif
- { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10},
- { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11},
- { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
+ { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11},
+ { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
+ { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13},
+ /* Must come last. If you add entries adjust this table appropriately and the init_one code */
+ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0},
{ 0, },
};
MODULE_DEVICE_TABLE(pci, generic_pci_tbl);
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index c8ee0b8c029..7b64db10d1b 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -10,6 +10,11 @@
* donation of an ABit BP6 mainboard, processor, and memory acellerated
* development and support.
*
+ *
+ * Highpoint have their own driver (source except for the raid part)
+ * available from http://www.highpoint-tech.com/hpt3xx-opensource-v131.tgz
+ * This may be useful to anyone wanting to work on the mainstream hpt IDE.
+ *
* Note that final HPT370 support was done by force extraction of GPL.
*
* - add function for getting/setting power status of drive
@@ -446,44 +451,29 @@ static struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = {
#define F_LOW_PCI_50 0x2d
#define F_LOW_PCI_66 0x42
-/* FIXME: compare with driver's code before removing */
-#if 0
- if (hpt_minimum_revision(dev, 3)) {
- u8 cbl;
- cbl = inb(iobase + 0x7b);
- outb(cbl | 1, iobase + 0x7b);
- outb(cbl & ~1, iobase + 0x7b);
- cbl = inb(iobase + 0x7a);
- p += sprintf(p, "Cable: ATA-%d"
- " ATA-%d\n",
- (cbl & 0x02) ? 33 : 66,
- (cbl & 0x01) ? 33 : 66);
- p += sprintf(p, "\n");
- }
- {
- u8 c2, c3;
- /* older revs don't have these registers mapped
- * into io space */
- pci_read_config_byte(dev, 0x43, &c0);
- pci_read_config_byte(dev, 0x47, &c1);
- pci_read_config_byte(dev, 0x4b, &c2);
- pci_read_config_byte(dev, 0x4f, &c3);
-
- p += sprintf(p, "Mode: %s %s"
- " %s %s\n",
- (c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " :
- (c0 & 0x80) ? "PIO " : "off ",
- (c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
- (c1 & 0x80) ? "PIO " : "off ",
- (c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
- (c2 & 0x80) ? "PIO " : "off ",
- (c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
- (c3 & 0x80) ? "PIO " : "off ");
- }
- }
-#endif
+/*
+ * Hold all the highpoint quirks and revision information in one
+ * place.
+ */
-static u32 hpt_revision (struct pci_dev *dev)
+struct hpt_info
+{
+ u8 max_mode; /* Speeds allowed */
+ int revision; /* Chipset revision */
+ int flags; /* Chipset properties */
+#define PLL_MODE 1
+#define IS_372N 2
+ /* Speed table */
+ struct chipset_bus_clock_list_entry *speed;
+};
+
+/*
+ * This wants fixing so that we do everything not by classrev
+ * (which breaks on the newest chips) but by creating an
+ * enumeration of chip variants and using that
+ */
+
+static __devinit u32 hpt_revision (struct pci_dev *dev)
{
u32 class_rev;
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
@@ -507,37 +497,33 @@ static u32 hpt_revision (struct pci_dev *dev)
return class_rev;
}
-static u32 hpt_minimum_revision (struct pci_dev *dev, int revision)
-{
- unsigned int class_rev = hpt_revision(dev);
- revision--;
- return ((int) (class_rev > revision) ? 1 : 0);
-}
-
static int check_in_drive_lists(ide_drive_t *drive, const char **list);
static u8 hpt3xx_ratemask (ide_drive_t *drive)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ ide_hwif_t *hwif = drive->hwif;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
u8 mode = 0;
- if (hpt_minimum_revision(dev, 8)) { /* HPT374 */
+ /* FIXME: TODO - move this to set info->mode once at boot */
+
+ if (info->revision >= 8) { /* HPT374 */
mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3;
- } else if (hpt_minimum_revision(dev, 7)) { /* HPT371 */
+ } else if (info->revision >= 7) { /* HPT371 */
mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3;
- } else if (hpt_minimum_revision(dev, 6)) { /* HPT302 */
+ } else if (info->revision >= 6) { /* HPT302 */
mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3;
- } else if (hpt_minimum_revision(dev, 5)) { /* HPT372 */
+ } else if (info->revision >= 5) { /* HPT372 */
mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3;
- } else if (hpt_minimum_revision(dev, 4)) { /* HPT370A */
+ } else if (info->revision >= 4) { /* HPT370A */
mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
- } else if (hpt_minimum_revision(dev, 3)) { /* HPT370 */
+ } else if (info->revision >= 3) { /* HPT370 */
mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
} else { /* HPT366 and HPT368 */
mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2;
}
- if (!eighty_ninty_three(drive) && (mode))
+ if (!eighty_ninty_three(drive) && mode)
mode = min(mode, (u8)1);
return mode;
}
@@ -549,7 +535,8 @@ static u8 hpt3xx_ratemask (ide_drive_t *drive)
static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ ide_hwif_t *hwif = drive->hwif;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
u8 mode = hpt3xx_ratemask(drive);
if (drive->media != ide_disk)
@@ -561,7 +548,7 @@ static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
break;
case 0x03:
speed = min(speed, (u8)XFER_UDMA_5);
- if (hpt_minimum_revision(dev, 5))
+ if (info->revision >= 5)
break;
if (check_in_drive_lists(drive, bad_ata100_5))
speed = min(speed, (u8)XFER_UDMA_4);
@@ -571,7 +558,7 @@ static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
/*
* CHECK ME, Does this need to be set to 5 ??
*/
- if (hpt_minimum_revision(dev, 3))
+ if (info->revision >= 3)
break;
if ((check_in_drive_lists(drive, bad_ata66_4)) ||
(!(HPT366_ALLOW_ATA66_4)))
@@ -585,7 +572,7 @@ static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
/*
* CHECK ME, Does this need to be set to 5 ??
*/
- if (hpt_minimum_revision(dev, 3))
+ if (info->revision >= 3)
break;
if (check_in_drive_lists(drive, bad_ata33))
speed = min(speed, (u8)XFER_MW_DMA_2);
@@ -624,11 +611,12 @@ static unsigned int pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_
static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
u8 speed = hpt3xx_ratefilter(drive, xferspeed);
-// u8 speed = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
u8 regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
- u8 regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
+ u8 regfast = (hwif->channel) ? 0x55 : 0x51;
u8 drive_fast = 0;
u32 reg1 = 0, reg2 = 0;
@@ -636,16 +624,11 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
* Disable the "fast interrupt" prediction.
*/
pci_read_config_byte(dev, regfast, &drive_fast);
-#if 0
- if (drive_fast & 0x02)
- pci_write_config_byte(dev, regfast, drive_fast & ~0x20);
-#else
if (drive_fast & 0x80)
pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
-#endif
- reg2 = pci_bus_clock_list(speed,
- (struct chipset_bus_clock_list_entry *) pci_get_drvdata(dev));
+ reg2 = pci_bus_clock_list(speed, info->speed);
+
/*
* Disable on-chip PIO FIFO/buffer
* (to avoid problems handling I/O errors later)
@@ -665,10 +648,11 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
u8 speed = hpt3xx_ratefilter(drive, xferspeed);
-// u8 speed = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
- u8 regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
+ u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51;
u8 drive_pci = 0x40 + (drive->dn * 4);
u8 new_fast = 0, drive_fast = 0;
u32 list_conf = 0, drive_conf = 0;
@@ -693,17 +677,13 @@ static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
if (new_fast != drive_fast)
pci_write_config_byte(dev, regfast, new_fast);
- list_conf = pci_bus_clock_list(speed,
- (struct chipset_bus_clock_list_entry *)
- pci_get_drvdata(dev));
+ list_conf = pci_bus_clock_list(speed, info->speed);
pci_read_config_dword(dev, drive_pci, &drive_conf);
list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
- if (speed < XFER_MW_DMA_0) {
+ if (speed < XFER_MW_DMA_0)
list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
- }
-
pci_write_config_dword(dev, drive_pci, list_conf);
return ide_config_drive_speed(drive, speed);
@@ -711,10 +691,11 @@ static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
u8 speed = hpt3xx_ratefilter(drive, xferspeed);
-// u8 speed = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
- u8 regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
+ u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51;
u8 drive_fast = 0, drive_pci = 0x40 + (drive->dn * 4);
u32 list_conf = 0, drive_conf = 0;
u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
@@ -726,10 +707,8 @@ static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
pci_read_config_byte(dev, regfast, &drive_fast);
drive_fast &= ~0x07;
pci_write_config_byte(dev, regfast, drive_fast);
-
- list_conf = pci_bus_clock_list(speed,
- (struct chipset_bus_clock_list_entry *)
- pci_get_drvdata(dev));
+
+ list_conf = pci_bus_clock_list(speed, info->speed);
pci_read_config_dword(dev, drive_pci, &drive_conf);
list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
if (speed < XFER_MW_DMA_0)
@@ -741,19 +720,14 @@ static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ ide_hwif_t *hwif = drive->hwif;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
- if (hpt_minimum_revision(dev, 8))
+ if (info->revision >= 8)
return hpt372_tune_chipset(drive, speed); /* not a typo */
-#if 0
- else if (hpt_minimum_revision(dev, 7))
- hpt371_tune_chipset(drive, speed);
- else if (hpt_minimum_revision(dev, 6))
- hpt302_tune_chipset(drive, speed);
-#endif
- else if (hpt_minimum_revision(dev, 5))
+ else if (info->revision >= 5)
return hpt372_tune_chipset(drive, speed);
- else if (hpt_minimum_revision(dev, 3))
+ else if (info->revision >= 3)
return hpt370_tune_chipset(drive, speed);
else /* hpt368: hpt_minimum_revision(dev, 2) */
return hpt36x_tune_chipset(drive, speed);
@@ -779,8 +753,14 @@ static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio)
static int config_chipset_for_dma (ide_drive_t *drive)
{
u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
+ ide_hwif_t *hwif = drive->hwif;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
- if (!(speed))
+ if (!speed)
+ return 0;
+
+ /* If we don't have any timings we can't do a lot */
+ if (info->speed == NULL)
return 0;
(void) hpt3xx_tune_chipset(drive, speed);
@@ -794,7 +774,7 @@ static int hpt3xx_quirkproc (ide_drive_t *drive)
static void hpt3xx_intrproc (ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ ide_hwif_t *hwif = drive->hwif;
if (drive->quirk_list)
return;
@@ -804,24 +784,26 @@ static void hpt3xx_intrproc (ide_drive_t *drive)
static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ ide_hwif_t *hwif = drive->hwif;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
+ struct pci_dev *dev = hwif->pci_dev;
if (drive->quirk_list) {
- if (hpt_minimum_revision(dev,3)) {
+ if (info->revision >= 3) {
u8 reg5a = 0;
pci_read_config_byte(dev, 0x5a, &reg5a);
if (((reg5a & 0x10) >> 4) != mask)
pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
} else {
if (mask) {
- disable_irq(HWIF(drive)->irq);
+ disable_irq(hwif->irq);
} else {
- enable_irq(HWIF(drive)->irq);
+ enable_irq(hwif->irq);
}
}
} else {
if (IDE_CONTROL_REG)
- HWIF(drive)->OUTB(mask ? (drive->ctl | 2) :
+ hwif->OUTB(mask ? (drive->ctl | 2) :
(drive->ctl & ~2),
IDE_CONTROL_REG);
}
@@ -829,12 +811,12 @@ static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
static int hpt366_config_drive_xfer_rate (ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ ide_hwif_t *hwif = drive->hwif;
struct hd_driveid *id = drive->id;
drive->init_speed = 0;
- if (id && (id->capability & 1) && drive->autodma) {
+ if ((id->capability & 1) && drive->autodma) {
if (ide_use_dma(drive)) {
if (config_chipset_for_dma(drive))
@@ -868,15 +850,6 @@ static int hpt366_ide_dma_lostirq (ide_drive_t *drive)
drive->name, __FUNCTION__, reg50h, reg52h, reg5ah);
if (reg5ah & 0x10)
pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
-#if 0
- /* how about we flush and reset, mmmkay? */
- pci_write_config_byte(dev, 0x51, 0x1F);
- /* fall through to a reset */
- case dma_start:
- case ide_dma_end:
- /* reset the chips state over and over.. */
- pci_write_config_byte(dev, 0x51, 0x13);
-#endif
return __ide_dma_lostirq(drive);
}
@@ -919,7 +892,7 @@ static void hpt370_lostirq_timeout (ide_drive_t *drive)
u8 dma_stat = 0, dma_cmd = 0;
pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo);
- printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
+ printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo);
hpt370_clear_engine(drive);
/* get dma command mode */
dma_cmd = hwif->INB(hwif->dma_command);
@@ -1047,15 +1020,6 @@ static void hpt372n_rw_disk(ide_drive_t *drive, struct request *rq)
static void hpt3xx_reset (ide_drive_t *drive)
{
-#if 0
- unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4);
- u8 reset = (HWIF(drive)->channel) ? 0x80 : 0x40;
- u8 reg59h = 0;
-
- pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
-#endif
}
static int hpt3xx_tristate (ide_drive_t * drive, int state)
@@ -1065,8 +1029,6 @@ static int hpt3xx_tristate (ide_drive_t * drive, int state)
u8 reg59h = 0, reset = (hwif->channel) ? 0x80 : 0x40;
u8 regXXh = 0, state_reg= (hwif->channel) ? 0x57 : 0x53;
-// hwif->bus_state = state;
-
pci_read_config_byte(dev, 0x59, &reg59h);
pci_read_config_byte(dev, state_reg, &regXXh);
@@ -1093,7 +1055,7 @@ static int hpt3xx_tristate (ide_drive_t * drive, int state)
#define TRISTATE_BIT 0x8000
static int hpt370_busproc(ide_drive_t * drive, int state)
{
- ide_hwif_t *hwif = HWIF(drive);
+ ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = hwif->pci_dev;
u8 tristate = 0, resetmask = 0, bus_reg = 0;
u16 tri_reg;
@@ -1148,33 +1110,44 @@ static int hpt370_busproc(ide_drive_t * drive, int state)
return 0;
}
-static int __devinit init_hpt37x(struct pci_dev *dev)
+static void __devinit hpt366_clocking(ide_hwif_t *hwif)
{
+ u32 reg1 = 0;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
+
+ pci_read_config_dword(hwif->pci_dev, 0x40, &reg1);
+
+ /* detect bus speed by looking at control reg timing: */
+ switch((reg1 >> 8) & 7) {
+ case 5:
+ info->speed = forty_base_hpt366;
+ break;
+ case 9:
+ info->speed = twenty_five_base_hpt366;
+ break;
+ case 7:
+ default:
+ info->speed = thirty_three_base_hpt366;
+ break;
+ }
+}
+
+static void __devinit hpt37x_clocking(ide_hwif_t *hwif)
+{
+ struct hpt_info *info = ide_get_hwifdata(hwif);
+ struct pci_dev *dev = hwif->pci_dev;
int adjust, i;
u16 freq;
u32 pll;
u8 reg5bh;
- u8 reg5ah = 0;
- unsigned long dmabase = pci_resource_start(dev, 4);
- u8 did, rid;
- int is_372n = 0;
- pci_read_config_byte(dev, 0x5a, &reg5ah);
- /* interrupt force enable */
- pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
-
- if(dmabase)
- {
- did = inb(dmabase + 0x22);
- rid = inb(dmabase + 0x28);
-
- if((did == 4 && rid == 6) || (did == 5 && rid > 1))
- is_372n = 1;
- }
-
/*
* default to pci clock. make sure MA15/16 are set to output
- * to prevent drives having problems with 40-pin cables.
+ * to prevent drives having problems with 40-pin cables. Needed
+ * for some drives such as IBM-DTLA which will not enter ready
+ * state on reset when PDIAG is a input.
+ *
+ * ToDo: should we set 0x21 when using PLL mode ?
*/
pci_write_config_byte(dev, 0x5b, 0x23);
@@ -1197,9 +1170,7 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
* Currently we always set up the PLL for the 372N
*/
- pci_set_drvdata(dev, NULL);
-
- if(is_372n)
+ if(info->flags & IS_372N)
{
printk(KERN_INFO "hpt: HPT372N detected, using 372N timing.\n");
if(freq < 0x55)
@@ -1227,39 +1198,38 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
pll = F_LOW_PCI_66;
if (pll == F_LOW_PCI_33) {
- if (hpt_minimum_revision(dev,8))
- pci_set_drvdata(dev, (void *) thirty_three_base_hpt374);
- else if (hpt_minimum_revision(dev,5))
- pci_set_drvdata(dev, (void *) thirty_three_base_hpt372);
- else if (hpt_minimum_revision(dev,4))
- pci_set_drvdata(dev, (void *) thirty_three_base_hpt370a);
+ if (info->revision >= 8)
+ info->speed = thirty_three_base_hpt374;
+ else if (info->revision >= 5)
+ info->speed = thirty_three_base_hpt372;
+ else if (info->revision >= 4)
+ info->speed = thirty_three_base_hpt370a;
else
- pci_set_drvdata(dev, (void *) thirty_three_base_hpt370);
- printk("HPT37X: using 33MHz PCI clock\n");
+ info->speed = thirty_three_base_hpt370;
+ printk(KERN_DEBUG "HPT37X: using 33MHz PCI clock\n");
} else if (pll == F_LOW_PCI_40) {
/* Unsupported */
} else if (pll == F_LOW_PCI_50) {
- if (hpt_minimum_revision(dev,8))
- pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
- else if (hpt_minimum_revision(dev,5))
- pci_set_drvdata(dev, (void *) fifty_base_hpt372);
- else if (hpt_minimum_revision(dev,4))
- pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+ if (info->revision >= 8)
+ info->speed = fifty_base_hpt370a;
+ else if (info->revision >= 5)
+ info->speed = fifty_base_hpt372;
+ else if (info->revision >= 4)
+ info->speed = fifty_base_hpt370a;
else
- pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
- printk("HPT37X: using 50MHz PCI clock\n");
+ info->speed = fifty_base_hpt370a;
+ printk(KERN_DEBUG "HPT37X: using 50MHz PCI clock\n");
} else {
- if (hpt_minimum_revision(dev,8))
- {
+ if (info->revision >= 8) {
printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n");
}
- else if (hpt_minimum_revision(dev,5))
- pci_set_drvdata(dev, (void *) sixty_six_base_hpt372);
- else if (hpt_minimum_revision(dev,4))
- pci_set_drvdata(dev, (void *) sixty_six_base_hpt370a);
+ else if (info->revision >= 5)
+ info->speed = sixty_six_base_hpt372;
+ else if (info->revision >= 4)
+ info->speed = sixty_six_base_hpt370a;
else
- pci_set_drvdata(dev, (void *) sixty_six_base_hpt370);
- printk("HPT37X: using 66MHz PCI clock\n");
+ info->speed = sixty_six_base_hpt370;
+ printk(KERN_DEBUG "HPT37X: using 66MHz PCI clock\n");
}
}
@@ -1269,11 +1239,19 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
* result in slow reads when using a 33MHz PCI clock. we also
* don't like to use the PLL because it will cause glitches
* on PRST/SRST when the HPT state engine gets reset.
+ *
+ * ToDo: Use 66MHz PLL when ATA133 devices are present on a
+ * 372 device so we can get ATA133 support
*/
- if (pci_get_drvdata(dev))
+ if (info->speed)
goto init_hpt37X_done;
+
+ info->flags |= PLL_MODE;
/*
+ * FIXME: make this work correctly, esp with 372N as per
+ * reference driver code.
+ *
* adjust PLL based upon PCI clock, enable it, and wait for
* stabilization.
*/
@@ -1298,14 +1276,14 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
pci_write_config_dword(dev, 0x5c,
pll & ~0x100);
pci_write_config_byte(dev, 0x5b, 0x21);
- if (hpt_minimum_revision(dev,8))
- pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
- else if (hpt_minimum_revision(dev,5))
- pci_set_drvdata(dev, (void *) fifty_base_hpt372);
- else if (hpt_minimum_revision(dev,4))
- pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+ if (info->revision >= 8)
+ info->speed = fifty_base_hpt370a;
+ else if (info->revision >= 5)
+ info->speed = fifty_base_hpt372;
+ else if (info->revision >= 4)
+ info->speed = fifty_base_hpt370a;
else
- pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+ info->speed = fifty_base_hpt370a;
printk("HPT37X: using 50MHz internal PLL\n");
goto init_hpt37X_done;
}
@@ -1318,10 +1296,22 @@ pll_recal:
}
init_hpt37X_done:
+ if (!info->speed)
+ printk(KERN_ERR "HPT37X%s: unknown bus timing [%d %d].\n",
+ (info->flags & IS_372N)?"N":"", pll, freq);
/* reset state engine */
pci_write_config_byte(dev, 0x50, 0x37);
pci_write_config_byte(dev, 0x54, 0x37);
udelay(100);
+}
+
+static int __devinit init_hpt37x(struct pci_dev *dev)
+{
+ u8 reg5ah;
+
+ pci_read_config_byte(dev, 0x5a, &reg5ah);
+ /* interrupt force enable */
+ pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
return 0;
}
@@ -1338,59 +1328,27 @@ static int __devinit init_hpt366(struct pci_dev *dev)
pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
pci_read_config_dword(dev, 0x40, &reg1);
- /* detect bus speed by looking at control reg timing: */
- switch((reg1 >> 8) & 7) {
- case 5:
- pci_set_drvdata(dev, (void *) forty_base_hpt366);
- break;
- case 9:
- pci_set_drvdata(dev, (void *) twenty_five_base_hpt366);
- break;
- case 7:
- default:
- pci_set_drvdata(dev, (void *) thirty_three_base_hpt366);
- break;
- }
-
- if (!pci_get_drvdata(dev))
- {
- printk(KERN_ERR "hpt366: unknown bus timing.\n");
- pci_set_drvdata(dev, NULL);
- }
return 0;
}
static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
{
int ret = 0;
- u8 test = 0;
-
+ /* FIXME: Not portable */
if (dev->resource[PCI_ROM_RESOURCE].start)
pci_write_config_byte(dev, PCI_ROM_ADDRESS,
dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
- pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
- if (test != (L1_CACHE_BYTES / 4))
- pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
- (L1_CACHE_BYTES / 4));
-
- pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
- if (test != 0x78)
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+ pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+ pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
- pci_read_config_byte(dev, PCI_MIN_GNT, &test);
- if (test != 0x08)
- pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
-
- pci_read_config_byte(dev, PCI_MAX_LAT, &test);
- if (test != 0x08)
- pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
-
- if (hpt_minimum_revision(dev, 3)) {
+ if (hpt_revision(dev) >= 3)
ret = init_hpt37x(dev);
- } else {
- ret =init_hpt366(dev);
- }
+ else
+ ret = init_hpt366(dev);
+
if (ret)
return ret;
@@ -1400,27 +1358,16 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
u8 ata66 = 0, regmask = (hwif->channel) ? 0x01 : 0x02;
- u8 did, rid;
- unsigned long dmabase = hwif->dma_base;
- int is_372n = 0;
- if(dmabase)
- {
- did = inb(dmabase + 0x22);
- rid = inb(dmabase + 0x28);
-
- if((did == 4 && rid == 6) || (did == 5 && rid > 1))
- is_372n = 1;
- }
-
hwif->tuneproc = &hpt3xx_tune_drive;
hwif->speedproc = &hpt3xx_tune_chipset;
hwif->quirkproc = &hpt3xx_quirkproc;
hwif->intrproc = &hpt3xx_intrproc;
hwif->maskproc = &hpt3xx_maskproc;
- if(is_372n)
+ if(info->flags & IS_372N)
hwif->rw_disk = &hpt372n_rw_disk;
/*
@@ -1428,7 +1375,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
* address lines to access an external eeprom. To read valid
* cable detect state the pins must be enabled as inputs.
*/
- if (hpt_minimum_revision(dev, 8) && PCI_FUNC(dev->devfn) & 1) {
+ if (info->revision >= 8 && (PCI_FUNC(dev->devfn) & 1)) {
/*
* HPT374 PCI function 1
* - set bit 15 of reg 0x52 to enable TCBLID as input
@@ -1443,7 +1390,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
pci_read_config_byte(dev, 0x5a, &ata66);
pci_write_config_word(dev, 0x52, mcr3);
pci_write_config_word(dev, 0x56, mcr6);
- } else if (hpt_minimum_revision(dev, 3)) {
+ } else if (info->revision >= 3) {
/*
* HPT370/372 and 374 pcifn 0
* - clear bit 0 of 0x5b to enable P/SCBLID as inputs
@@ -1470,7 +1417,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
hwif->serialized = hwif->mate->serialized = 1;
#endif
- if (hpt_minimum_revision(dev,3)) {
+ if (info->revision >= 3) {
u8 reg5ah = 0;
pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
/*
@@ -1480,8 +1427,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
*/
hwif->resetproc = &hpt3xx_reset;
hwif->busproc = &hpt370_busproc;
-// hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
- } else if (hpt_minimum_revision(dev,2)) {
+ } else if (info->revision >= 2) {
hwif->resetproc = &hpt3xx_reset;
hwif->busproc = &hpt3xx_tristate;
} else {
@@ -1502,18 +1448,18 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
- if (hpt_minimum_revision(dev,8)) {
+ if (info->revision >= 8) {
hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
hwif->ide_dma_end = &hpt374_ide_dma_end;
- } else if (hpt_minimum_revision(dev,5)) {
+ } else if (info->revision >= 5) {
hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
hwif->ide_dma_end = &hpt374_ide_dma_end;
- } else if (hpt_minimum_revision(dev,3)) {
+ } else if (info->revision >= 3) {
hwif->dma_start = &hpt370_ide_dma_start;
hwif->ide_dma_end = &hpt370_ide_dma_end;
hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq;
- } else if (hpt_minimum_revision(dev,2))
+ } else if (info->revision >= 2)
hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
else
hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
@@ -1526,6 +1472,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
{
+ struct hpt_info *info = ide_get_hwifdata(hwif);
u8 masterdma = 0, slavedma = 0;
u8 dma_new = 0, dma_old = 0;
u8 primary = hwif->channel ? 0x4b : 0x43;
@@ -1535,8 +1482,7 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
if (!dmabase)
return;
- if(pci_get_drvdata(hwif->pci_dev) == NULL)
- {
+ if(info->speed == NULL) {
printk(KERN_WARNING "hpt: no known IDE timings, disabling DMA.\n");
return;
}
@@ -1559,6 +1505,40 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
ide_setup_dma(hwif, dmabase, 8);
}
+/*
+ * We "borrow" this hook in order to set the data structures
+ * up early enough before dma or init_hwif calls are made.
+ */
+
+static void __devinit init_iops_hpt366(ide_hwif_t *hwif)
+{
+ struct hpt_info *info = kmalloc(sizeof(struct hpt_info), GFP_KERNEL);
+ unsigned long dmabase = pci_resource_start(hwif->pci_dev, 4);
+ u8 did, rid;
+
+ if(info == NULL) {
+ printk(KERN_WARNING "hpt366: out of memory.\n");
+ return;
+ }
+ memset(info, 0, sizeof(struct hpt_info));
+ ide_set_hwifdata(hwif, info);
+
+ if(dmabase) {
+ did = inb(dmabase + 0x22);
+ rid = inb(dmabase + 0x28);
+
+ if((did == 4 && rid == 6) || (did == 5 && rid > 1))
+ info->flags |= IS_372N;
+ }
+
+ info->revision = hpt_revision(hwif->pci_dev);
+
+ if (info->revision >= 3)
+ hpt37x_clocking(hwif);
+ else
+ hpt366_clocking(hwif);
+}
+
static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d)
{
struct pci_dev *findev = NULL;
@@ -1646,6 +1626,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
.name = "HPT366",
.init_setup = init_setup_hpt366,
.init_chipset = init_chipset_hpt366,
+ .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
@@ -1656,6 +1637,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
.name = "HPT372A",
.init_setup = init_setup_hpt37x,
.init_chipset = init_chipset_hpt366,
+ .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
@@ -1665,6 +1647,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
.name = "HPT302",
.init_setup = init_setup_hpt37x,
.init_chipset = init_chipset_hpt366,
+ .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
@@ -1674,6 +1657,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
.name = "HPT371",
.init_setup = init_setup_hpt37x,
.init_chipset = init_chipset_hpt366,
+ .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
@@ -1683,6 +1667,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
.name = "HPT374",
.init_setup = init_setup_hpt374,
.init_chipset = init_chipset_hpt366,
+ .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2, /* 4 */
@@ -1692,6 +1677,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
.name = "HPT372N",
.init_setup = init_setup_hpt37x,
.init_chipset = init_chipset_hpt366,
+ .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2, /* 4 */
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
new file mode 100644
index 00000000000..e440036e651
--- /dev/null
+++ b/drivers/ide/pci/it821x.c
@@ -0,0 +1,812 @@
+
+/*
+ * linux/drivers/ide/pci/it821x.c Version 0.09 December 2004
+ *
+ * Copyright (C) 2004 Red Hat <alan@redhat.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ * Based in part on the ITE vendor provided SCSI driver.
+ *
+ * Documentation available from
+ * http://www.ite.com.tw/pc/IT8212F_V04.pdf
+ * Some other documents are NDA.
+ *
+ * The ITE8212 isn't exactly a standard IDE controller. It has two
+ * modes. In pass through mode then it is an IDE controller. In its smart
+ * mode its actually quite a capable hardware raid controller disguised
+ * as an IDE controller. Smart mode only understands DMA read/write and
+ * identify, none of the fancier commands apply. The IT8211 is identical
+ * in other respects but lacks the raid mode.
+ *
+ * Errata:
+ * o Rev 0x10 also requires master/slave hold the same DMA timings and
+ * cannot do ATAPI MWDMA.
+ * o The identify data for raid volumes lacks CHS info (technically ok)
+ * but also fails to set the LBA28 and other bits. We fix these in
+ * the IDE probe quirk code.
+ * o If you write LBA48 sized I/O's (ie > 256 sector) in smart mode
+ * raid then the controller firmware dies
+ * o Smart mode without RAID doesn't clear all the necessary identify
+ * bits to reduce the command set to the one used
+ *
+ * This has a few impacts on the driver
+ * - In pass through mode we do all the work you would expect
+ * - In smart mode the clocking set up is done by the controller generally
+ * but we must watch the other limits and filter.
+ * - There are a few extra vendor commands that actually talk to the
+ * controller but only work PIO with no IRQ.
+ *
+ * Vendor areas of the identify block in smart mode are used for the
+ * timing and policy set up. Each HDD in raid mode also has a serial
+ * block on the disk. The hardware extra commands are get/set chip status,
+ * rebuild, get rebuild status.
+ *
+ * In Linux the driver supports pass through mode as if the device was
+ * just another IDE controller. If the smart mode is running then
+ * volumes are managed by the controller firmware and each IDE "disk"
+ * is a raid volume. Even more cute - the controller can do automated
+ * hotplug and rebuild.
+ *
+ * The pass through controller itself is a little demented. It has a
+ * flaw that it has a single set of PIO/MWDMA timings per channel so
+ * non UDMA devices restrict each others performance. It also has a
+ * single clock source per channel so mixed UDMA100/133 performance
+ * isn't perfect and we have to pick a clock. Thankfully none of this
+ * matters in smart mode. ATAPI DMA is not currently supported.
+ *
+ * It seems the smart mode is a win for RAID1/RAID10 but otherwise not.
+ *
+ * TODO
+ * - ATAPI UDMA is ok but not MWDMA it seems
+ * - RAID configuration ioctls
+ * - Move to libata once it grows up
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+struct it821x_dev
+{
+ unsigned int smart:1, /* Are we in smart raid mode */
+ timing10:1; /* Rev 0x10 */
+ u8 clock_mode; /* 0, ATA_50 or ATA_66 */
+ u8 want[2][2]; /* Mode/Pri log for master slave */
+ /* We need these for switching the clock when DMA goes on/off
+ The high byte is the 66Mhz timing */
+ u16 pio[2]; /* Cached PIO values */
+ u16 mwdma[2]; /* Cached MWDMA values */
+ u16 udma[2]; /* Cached UDMA values (per drive) */
+};
+
+#define ATA_66 0
+#define ATA_50 1
+#define ATA_ANY 2
+
+#define UDMA_OFF 0
+#define MWDMA_OFF 0
+
+/*
+ * We allow users to force the card into non raid mode without
+ * flashing the alternative BIOS. This is also neccessary right now
+ * for embedded platforms that cannot run a PC BIOS but are using this
+ * device.
+ */
+
+static int it8212_noraid;
+
+/**
+ * it821x_program - program the PIO/MWDMA registers
+ * @drive: drive to tune
+ *
+ * Program the PIO/MWDMA timing for this channel according to the
+ * current clock.
+ */
+
+static void it821x_program(ide_drive_t *drive, u16 timing)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ int channel = hwif->channel;
+ u8 conf;
+
+ /* Program PIO/MWDMA timing bits */
+ if(itdev->clock_mode == ATA_66)
+ conf = timing >> 8;
+ else
+ conf = timing & 0xFF;
+ pci_write_config_byte(hwif->pci_dev, 0x54 + 4 * channel, conf);
+}
+
+/**
+ * it821x_program_udma - program the UDMA registers
+ * @drive: drive to tune
+ *
+ * Program the UDMA timing for this drive according to the
+ * current clock.
+ */
+
+static void it821x_program_udma(ide_drive_t *drive, u16 timing)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ int channel = hwif->channel;
+ int unit = drive->select.b.unit;
+ u8 conf;
+
+ /* Program UDMA timing bits */
+ if(itdev->clock_mode == ATA_66)
+ conf = timing >> 8;
+ else
+ conf = timing & 0xFF;
+ if(itdev->timing10 == 0)
+ pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + unit, conf);
+ else {
+ pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel, conf);
+ pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + 1, conf);
+ }
+}
+
+
+/**
+ * it821x_clock_strategy
+ * @hwif: hardware interface
+ *
+ * Select between the 50 and 66Mhz base clocks to get the best
+ * results for this interface.
+ */
+
+static void it821x_clock_strategy(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+
+ u8 unit = drive->select.b.unit;
+ ide_drive_t *pair = &hwif->drives[1-unit];
+
+ int clock, altclock;
+ u8 v;
+ int sel = 0;
+
+ if(itdev->want[0][0] > itdev->want[1][0]) {
+ clock = itdev->want[0][1];
+ altclock = itdev->want[1][1];
+ } else {
+ clock = itdev->want[1][1];
+ altclock = itdev->want[0][1];
+ }
+
+ /* Master doesn't care does the slave ? */
+ if(clock == ATA_ANY)
+ clock = altclock;
+
+ /* Nobody cares - keep the same clock */
+ if(clock == ATA_ANY)
+ return;
+ /* No change */
+ if(clock == itdev->clock_mode)
+ return;
+
+ /* Load this into the controller ? */
+ if(clock == ATA_66)
+ itdev->clock_mode = ATA_66;
+ else {
+ itdev->clock_mode = ATA_50;
+ sel = 1;
+ }
+ pci_read_config_byte(hwif->pci_dev, 0x50, &v);
+ v &= ~(1 << (1 + hwif->channel));
+ v |= sel << (1 + hwif->channel);
+ pci_write_config_byte(hwif->pci_dev, 0x50, v);
+
+ /*
+ * Reprogram the UDMA/PIO of the pair drive for the switch
+ * MWDMA will be dealt with by the dma switcher
+ */
+ if(pair && itdev->udma[1-unit] != UDMA_OFF) {
+ it821x_program_udma(pair, itdev->udma[1-unit]);
+ it821x_program(pair, itdev->pio[1-unit]);
+ }
+ /*
+ * Reprogram the UDMA/PIO of our drive for the switch.
+ * MWDMA will be dealt with by the dma switcher
+ */
+ if(itdev->udma[unit] != UDMA_OFF) {
+ it821x_program_udma(drive, itdev->udma[unit]);
+ it821x_program(drive, itdev->pio[unit]);
+ }
+}
+
+/**
+ * it821x_ratemask - Compute available modes
+ * @drive: IDE drive
+ *
+ * Compute the available speeds for the devices on the interface. This
+ * is all modes to ATA133 clipped by drive cable setup.
+ */
+
+static u8 it821x_ratemask (ide_drive_t *drive)
+{
+ u8 mode = 4;
+ if (!eighty_ninty_three(drive))
+ mode = min(mode, (u8)1);
+ return mode;
+}
+
+/**
+ * it821x_tuneproc - tune a drive
+ * @drive: drive to tune
+ * @mode_wanted: the target operating mode
+ *
+ * Load the timing settings for this device mode into the
+ * controller. By the time we are called the mode has been
+ * modified as neccessary to handle the absence of seperate
+ * master/slave timers for MWDMA/PIO.
+ *
+ * This code is only used in pass through mode.
+ */
+
+static void it821x_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ int unit = drive->select.b.unit;
+
+ /* Spec says 89 ref driver uses 88 */
+ static u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
+ static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
+
+ if(itdev->smart)
+ return;
+
+ /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */
+ itdev->want[unit][1] = pio_want[mode_wanted];
+ itdev->want[unit][0] = 1; /* PIO is lowest priority */
+ itdev->pio[unit] = pio[mode_wanted];
+ it821x_clock_strategy(drive);
+ it821x_program(drive, itdev->pio[unit]);
+}
+
+/**
+ * it821x_tune_mwdma - tune a channel for MWDMA
+ * @drive: drive to set up
+ * @mode_wanted: the target operating mode
+ *
+ * Load the timing settings for this device mode into the
+ * controller when doing MWDMA in pass through mode. The caller
+ * must manage the whole lack of per device MWDMA/PIO timings and
+ * the shared MWDMA/PIO timing register.
+ */
+
+static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = (void *)ide_get_hwifdata(hwif);
+ int unit = drive->select.b.unit;
+ int channel = hwif->channel;
+ u8 conf;
+
+ static u16 dma[] = { 0x8866, 0x3222, 0x3121 };
+ static u8 mwdma_want[] = { ATA_ANY, ATA_66, ATA_ANY };
+
+ itdev->want[unit][1] = mwdma_want[mode_wanted];
+ itdev->want[unit][0] = 2; /* MWDMA is low priority */
+ itdev->mwdma[unit] = dma[mode_wanted];
+ itdev->udma[unit] = UDMA_OFF;
+
+ /* UDMA bits off - Revision 0x10 do them in pairs */
+ pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
+ if(itdev->timing10)
+ conf |= channel ? 0x60: 0x18;
+ else
+ conf |= 1 << (3 + 2 * channel + unit);
+ pci_write_config_byte(hwif->pci_dev, 0x50, conf);
+
+ it821x_clock_strategy(drive);
+ /* FIXME: do we need to program this ? */
+ /* it821x_program(drive, itdev->mwdma[unit]); */
+}
+
+/**
+ * it821x_tune_udma - tune a channel for UDMA
+ * @drive: drive to set up
+ * @mode_wanted: the target operating mode
+ *
+ * Load the timing settings for this device mode into the
+ * controller when doing UDMA modes in pass through.
+ */
+
+static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ int unit = drive->select.b.unit;
+ int channel = hwif->channel;
+ u8 conf;
+
+ static u16 udma[] = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 };
+ static u8 udma_want[] = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 };
+
+ itdev->want[unit][1] = udma_want[mode_wanted];
+ itdev->want[unit][0] = 3; /* UDMA is high priority */
+ itdev->mwdma[unit] = MWDMA_OFF;
+ itdev->udma[unit] = udma[mode_wanted];
+ if(mode_wanted >= 5)
+ itdev->udma[unit] |= 0x8080; /* UDMA 5/6 select on */
+
+ /* UDMA on. Again revision 0x10 must do the pair */
+ pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
+ if(itdev->timing10)
+ conf &= channel ? 0x9F: 0xE7;
+ else
+ conf &= ~ (1 << (3 + 2 * channel + unit));
+ pci_write_config_byte(hwif->pci_dev, 0x50, conf);
+
+ it821x_clock_strategy(drive);
+ it821x_program_udma(drive, itdev->udma[unit]);
+
+}
+
+/**
+ * config_it821x_chipset_for_pio - set drive timings
+ * @drive: drive to tune
+ * @speed we want
+ *
+ * Compute the best pio mode we can for a given device. We must
+ * pick a speed that does not cause problems with the other device
+ * on the cable.
+ */
+
+static void config_it821x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+ u8 unit = drive->select.b.unit;
+ ide_hwif_t *hwif = drive->hwif;
+ ide_drive_t *pair = &hwif->drives[1-unit];
+ u8 speed = 0, set_pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+ u8 pair_pio;
+
+ /* We have to deal with this mess in pairs */
+ if(pair != NULL) {
+ pair_pio = ide_get_best_pio_mode(pair, 255, 5, NULL);
+ /* Trim PIO to the slowest of the master/slave */
+ if(pair_pio < set_pio)
+ set_pio = pair_pio;
+ }
+ it821x_tuneproc(drive, set_pio);
+ speed = XFER_PIO_0 + set_pio;
+ /* XXX - We trim to the lowest of the pair so the other drive
+ will always be fine at this point until we do hotplug passthru */
+
+ if (set_speed)
+ (void) ide_config_drive_speed(drive, speed);
+}
+
+/**
+ * it821x_dma_read - DMA hook
+ * @drive: drive for DMA
+ *
+ * The IT821x has a single timing register for MWDMA and for PIO
+ * operations. As we flip back and forth we have to reload the
+ * clock. In addition the rev 0x10 device only works if the same
+ * timing value is loaded into the master and slave UDMA clock
+ * so we must also reload that.
+ *
+ * FIXME: we could figure out in advance if we need to do reloads
+ */
+
+static void it821x_dma_start(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ int unit = drive->select.b.unit;
+ if(itdev->mwdma[unit] != MWDMA_OFF)
+ it821x_program(drive, itdev->mwdma[unit]);
+ else if(itdev->udma[unit] != UDMA_OFF && itdev->timing10)
+ it821x_program_udma(drive, itdev->udma[unit]);
+ ide_dma_start(drive);
+}
+
+/**
+ * it821x_dma_write - DMA hook
+ * @drive: drive for DMA stop
+ *
+ * The IT821x has a single timing register for MWDMA and for PIO
+ * operations. As we flip back and forth we have to reload the
+ * clock.
+ */
+
+static int it821x_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ int unit = drive->select.b.unit;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ int ret = __ide_dma_end(drive);
+ if(itdev->mwdma[unit] != MWDMA_OFF)
+ it821x_program(drive, itdev->pio[unit]);
+ return ret;
+}
+
+
+/**
+ * it821x_tune_chipset - set controller timings
+ * @drive: Drive to set up
+ * @xferspeed: speed we want to achieve
+ *
+ * Tune the ITE chipset for the desired mode. If we can't achieve
+ * the desired mode then tune for a lower one, but ultimately
+ * make the thing work.
+ */
+
+static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed)
+{
+
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ u8 speed = ide_rate_filter(it821x_ratemask(drive), xferspeed);
+
+ if(!itdev->smart) {
+ switch(speed) {
+ case XFER_PIO_4:
+ case XFER_PIO_3:
+ case XFER_PIO_2:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ it821x_tuneproc(drive, (speed - XFER_PIO_0));
+ break;
+ /* MWDMA tuning is really hard because our MWDMA and PIO
+ timings are kept in the same place. We can switch in the
+ host dma on/off callbacks */
+ case XFER_MW_DMA_2:
+ case XFER_MW_DMA_1:
+ case XFER_MW_DMA_0:
+ it821x_tune_mwdma(drive, (speed - XFER_MW_DMA_0));
+ break;
+ case XFER_UDMA_6:
+ case XFER_UDMA_5:
+ case XFER_UDMA_4:
+ case XFER_UDMA_3:
+ case XFER_UDMA_2:
+ case XFER_UDMA_1:
+ case XFER_UDMA_0:
+ it821x_tune_udma(drive, (speed - XFER_UDMA_0));
+ break;
+ default:
+ return 1;
+ }
+ }
+ /*
+ * In smart mode the clocking is done by the host controller
+ * snooping the mode we picked. The rest of it is not our problem
+ */
+ return ide_config_drive_speed(drive, speed);
+}
+
+/**
+ * config_chipset_for_dma - configure for DMA
+ * @drive: drive to configure
+ *
+ * Called by the IDE layer when it wants the timings set up.
+ */
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, it821x_ratemask(drive));
+
+ config_it821x_chipset_for_pio(drive, !speed);
+ it821x_tune_chipset(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+/**
+ * it821x_configure_drive_for_dma - set up for DMA transfers
+ * @drive: drive we are going to set up
+ *
+ * Set up the drive for DMA, tune the controller and drive as
+ * required. If the drive isn't suitable for DMA or we hit
+ * other problems then we will drop down to PIO and set up
+ * PIO appropriately
+ */
+
+static int it821x_config_drive_for_dma (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ if (ide_use_dma(drive)) {
+ if (config_chipset_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+ config_it821x_chipset_for_pio(drive, 1);
+ return hwif->ide_dma_off_quietly(drive);
+}
+
+/**
+ * ata66_it821x - check for 80 pin cable
+ * @hwif: interface to check
+ *
+ * Check for the presence of an ATA66 capable cable on the
+ * interface. Problematic as it seems some cards don't have
+ * the needed logic onboard.
+ */
+
+static unsigned int __devinit ata66_it821x(ide_hwif_t *hwif)
+{
+ /* The reference driver also only does disk side */
+ return 1;
+}
+
+/**
+ * it821x_fixup - post init callback
+ * @hwif: interface
+ *
+ * This callback is run after the drives have been probed but
+ * before anything gets attached. It allows drivers to do any
+ * final tuning that is needed, or fixups to work around bugs.
+ */
+
+static void __devinit it821x_fixups(ide_hwif_t *hwif)
+{
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ int i;
+
+ if(!itdev->smart) {
+ /*
+ * If we are in pass through mode then not much
+ * needs to be done, but we do bother to clear the
+ * IRQ mask as we may well be in PIO (eg rev 0x10)
+ * for now and we know unmasking is safe on this chipset.
+ */
+ for (i = 0; i < 2; i++) {
+ ide_drive_t *drive = &hwif->drives[i];
+ if(drive->present)
+ drive->unmask = 1;
+ }
+ return;
+ }
+ /*
+ * Perform fixups on smart mode. We need to "lose" some
+ * capabilities the firmware lacks but does not filter, and
+ * also patch up some capability bits that it forgets to set
+ * in RAID mode.
+ */
+
+ for(i = 0; i < 2; i++) {
+ ide_drive_t *drive = &hwif->drives[i];
+ struct hd_driveid *id;
+ u16 *idbits;
+
+ if(!drive->present)
+ continue;
+ id = drive->id;
+ idbits = (u16 *)drive->id;
+
+ /* Check for RAID v native */
+ if(strstr(id->model, "Integrated Technology Express")) {
+ /* In raid mode the ident block is slightly buggy
+ We need to set the bits so that the IDE layer knows
+ LBA28. LBA48 and DMA ar valid */
+ id->capability |= 3; /* LBA28, DMA */
+ id->command_set_2 |= 0x0400; /* LBA48 valid */
+ id->cfs_enable_2 |= 0x0400; /* LBA48 on */
+ /* Reporting logic */
+ printk(KERN_INFO "%s: IT8212 %sRAID %d volume",
+ drive->name,
+ idbits[147] ? "Bootable ":"",
+ idbits[129]);
+ if(idbits[129] != 1)
+ printk("(%dK stripe)", idbits[146]);
+ printk(".\n");
+ /* Now the core code will have wrongly decided no DMA
+ so we need to fix this */
+ hwif->ide_dma_off_quietly(drive);
+#ifdef CONFIG_IDEDMA_ONLYDISK
+ if (drive->media == ide_disk)
+#endif
+ hwif->ide_dma_check(drive);
+ } else {
+ /* Non RAID volume. Fixups to stop the core code
+ doing unsupported things */
+ id->field_valid &= 1;
+ id->queue_depth = 0;
+ id->command_set_1 = 0;
+ id->command_set_2 &= 0xC400;
+ id->cfsse &= 0xC000;
+ id->cfs_enable_1 = 0;
+ id->cfs_enable_2 &= 0xC400;
+ id->csf_default &= 0xC000;
+ id->word127 = 0;
+ id->dlf = 0;
+ id->csfo = 0;
+ id->cfa_power = 0;
+ printk(KERN_INFO "%s: Performing identify fixups.\n",
+ drive->name);
+ }
+ }
+
+}
+
+/**
+ * init_hwif_it821x - set up hwif structs
+ * @hwif: interface to set up
+ *
+ * We do the basic set up of the interface structure. The IT8212
+ * requires several custom handlers so we override the default
+ * ide DMA handlers appropriately
+ */
+
+static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
+{
+ struct it821x_dev *idev = kmalloc(sizeof(struct it821x_dev), GFP_KERNEL);
+ u8 conf;
+
+ if(idev == NULL) {
+ printk(KERN_ERR "it821x: out of memory, falling back to legacy behaviour.\n");
+ goto fallback;
+ }
+ memset(idev, 0, sizeof(struct it821x_dev));
+ ide_set_hwifdata(hwif, idev);
+
+ pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
+ if(conf & 1) {
+ idev->smart = 1;
+ hwif->atapi_dma = 0;
+ /* Long I/O's although allowed in LBA48 space cause the
+ onboard firmware to enter the twighlight zone */
+ hwif->rqsize = 256;
+ }
+
+ /* Pull the current clocks from 0x50 also */
+ if (conf & (1 << (1 + hwif->channel)))
+ idev->clock_mode = ATA_50;
+ else
+ idev->clock_mode = ATA_66;
+
+ idev->want[0][1] = ATA_ANY;
+ idev->want[1][1] = ATA_ANY;
+
+ /*
+ * Not in the docs but according to the reference driver
+ * this is neccessary.
+ */
+
+ pci_read_config_byte(hwif->pci_dev, 0x08, &conf);
+ if(conf == 0x10) {
+ idev->timing10 = 1;
+ hwif->atapi_dma = 0;
+ if(!idev->smart)
+ printk(KERN_WARNING "it821x: Revision 0x10, workarounds activated.\n");
+ }
+
+ hwif->speedproc = &it821x_tune_chipset;
+ hwif->tuneproc = &it821x_tuneproc;
+
+ /* MWDMA/PIO clock switching for pass through mode */
+ if(!idev->smart) {
+ hwif->dma_start = &it821x_dma_start;
+ hwif->ide_dma_end = &it821x_dma_end;
+ }
+
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+
+ if (!hwif->dma_base)
+ goto fallback;
+
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+ hwif->ide_dma_check = &it821x_config_drive_for_dma;
+ if (!(hwif->udma_four))
+ hwif->udma_four = ata66_it821x(hwif);
+
+ /*
+ * The BIOS often doesn't set up DMA on this controller
+ * so we always do it.
+ */
+
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+ return;
+fallback:
+ hwif->autodma = 0;
+ return;
+}
+
+static void __devinit it8212_disable_raid(struct pci_dev *dev)
+{
+ /* Reset local CPU, and set BIOS not ready */
+ pci_write_config_byte(dev, 0x5E, 0x01);
+
+ /* Set to bypass mode, and reset PCI bus */
+ pci_write_config_byte(dev, 0x50, 0x00);
+ pci_write_config_word(dev, PCI_COMMAND,
+ PCI_COMMAND_PARITY | PCI_COMMAND_IO |
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ pci_write_config_word(dev, 0x40, 0xA0F3);
+
+ pci_write_config_dword(dev,0x4C, 0x02040204);
+ pci_write_config_byte(dev, 0x42, 0x36);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0);
+}
+
+static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const char *name)
+{
+ u8 conf;
+ static char *mode[2] = { "pass through", "smart" };
+
+ /* Force the card into bypass mode if so requested */
+ if (it8212_noraid) {
+ printk(KERN_INFO "it8212: forcing bypass mode.\n");
+ it8212_disable_raid(dev);
+ }
+ pci_read_config_byte(dev, 0x50, &conf);
+ printk(KERN_INFO "it821x: controller in %s mode.\n", mode[conf & 1]);
+ return 0;
+}
+
+
+#define DECLARE_ITE_DEV(name_str) \
+ { \
+ .name = name_str, \
+ .init_chipset = init_chipset_it821x, \
+ .init_hwif = init_hwif_it821x, \
+ .channels = 2, \
+ .autodma = AUTODMA, \
+ .bootable = ON_BOARD, \
+ .fixup = it821x_fixups \
+ }
+
+static ide_pci_device_t it821x_chipsets[] __devinitdata = {
+ /* 0 */ DECLARE_ITE_DEV("IT8212"),
+};
+
+/**
+ * it821x_init_one - pci layer discovery entry
+ * @dev: PCI device
+ * @id: ident table entry
+ *
+ * Called by the PCI code when it finds an ITE821x controller.
+ * We then use the IDE PCI generic helper to do most of the work.
+ */
+
+static int __devinit it821x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ ide_setup_pci_device(dev, &it821x_chipsets[id->driver_data]);
+ return 0;
+}
+
+static struct pci_device_id it821x_pci_tbl[] = {
+ { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8212, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, it821x_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "ITE821x IDE",
+ .id_table = it821x_pci_tbl,
+ .probe = it821x_init_one,
+};
+
+static int __init it821x_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(it821x_ide_init);
+
+module_param_named(noraid, it8212_noraid, int, S_IRUGO);
+MODULE_PARM_DESC(it8212_noraid, "Force card into bypass mode");
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for the ITE 821x");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index 82a1103b241..c6f5fa4b4ca 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -442,7 +442,7 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
return (dev->irq) ? dev->irq : 0;
}
-static unsigned int __init ata66_svwks_svwks (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_svwks_svwks (ide_hwif_t *hwif)
{
return 1;
}
@@ -454,7 +454,7 @@ static unsigned int __init ata66_svwks_svwks (ide_hwif_t *hwif)
* Bit 14 clear = primary IDE channel does not have 80-pin cable.
* Bit 14 set = primary IDE channel has 80-pin cable.
*/
-static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_svwks_dell (ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
@@ -472,7 +472,7 @@ static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
*
* WARNING: this only works on Alpine hardware!
*/
-static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_svwks_cobalt (ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
@@ -483,7 +483,7 @@ static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
return 0;
}
-static unsigned int __init ata66_svwks (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_svwks (ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
@@ -573,7 +573,7 @@ static int __devinit init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
return ide_setup_pci_device(dev, d);
}
-static int __init init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
+static int __devinit init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
{
if (!(PCI_FUNC(dev->devfn) & 1)) {
d->bootable = NEVER_BOARD;
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 569f1676744..818380b5fd2 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -1324,9 +1324,9 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
/* XXX FIXME: Media bay stuff need re-organizing */
if (np->parent && np->parent->name
&& strcasecmp(np->parent->name, "media-bay") == 0) {
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PMAC_MEDIABAY
media_bay_set_ide_infos(np->parent, pmif->regbase, pmif->irq, hwif->index);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PMAC_MEDIABAY */
pmif->mediabay = 1;
if (!bidp)
pmif->aapl_bus_id = 1;
@@ -1382,10 +1382,10 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
pmif->mediabay ? " (mediabay)" : "", hwif->irq);
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PMAC_MEDIABAY
if (pmif->mediabay && check_media_bay_by_base(pmif->regbase, MB_CD) == 0)
hwif->noprobe = 0;
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PMAC_MEDIABAY */
hwif->sg_max_nents = MAX_DCMDS;
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 36e25ac823d..b3d3d22fde6 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -3538,8 +3538,8 @@ static void ohci1394_pci_remove(struct pci_dev *pdev)
static int ohci1394_pci_resume (struct pci_dev *pdev)
{
-#ifdef CONFIG_PMAC_PBOOK
- {
+#ifdef CONFIG_PPC_PMAC
+ if (_machine == _MACH_Pmac) {
struct device_node *of_node;
/* Re-enable 1394 */
@@ -3547,7 +3547,7 @@ static int ohci1394_pci_resume (struct pci_dev *pdev)
if (of_node)
pmac_call_feature (PMAC_FTR_1394_ENABLE, of_node, 0, 1);
}
-#endif
+#endif /* CONFIG_PPC_PMAC */
pci_enable_device(pdev);
@@ -3557,8 +3557,8 @@ static int ohci1394_pci_resume (struct pci_dev *pdev)
static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state)
{
-#ifdef CONFIG_PMAC_PBOOK
- {
+#ifdef CONFIG_PPC_PMAC
+ if (_machine == _MACH_Pmac) {
struct device_node *of_node;
/* Disable 1394 */
diff --git a/drivers/infiniband/core/packer.c b/drivers/infiniband/core/packer.c
index 5f15feffeae..eb5ff54c10d 100644
--- a/drivers/infiniband/core/packer.c
+++ b/drivers/infiniband/core/packer.c
@@ -96,7 +96,7 @@ void ib_pack(const struct ib_field *desc,
else
val = 0;
- mask = cpu_to_be64(((1ull << desc[i].size_bits) - 1) << shift);
+ mask = cpu_to_be64((~0ull >> (64 - desc[i].size_bits)) << shift);
addr = (__be64 *) ((__be32 *) buf + desc[i].offset_words);
*addr = (*addr & ~mask) | (cpu_to_be64(val) & mask);
} else {
@@ -176,7 +176,7 @@ void ib_unpack(const struct ib_field *desc,
__be64 *addr;
shift = 64 - desc[i].offset_bits - desc[i].size_bits;
- mask = ((1ull << desc[i].size_bits) - 1) << shift;
+ mask = (~0ull >> (64 - desc[i].size_bits)) << shift;
addr = (__be64 *) buf + desc[i].offset_words;
val = (be64_to_cpup(addr) & mask) >> shift;
value_write(desc[i].struct_offset_bytes,
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 276e1a53010..5a08e81fa82 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -507,7 +507,13 @@ retry:
spin_unlock_irqrestore(&idr_lock, flags);
}
- return ret;
+ /*
+ * It's not safe to dereference query any more, because the
+ * send may already have completed and freed the query in
+ * another context. So use wr.wr_id, which has a copy of the
+ * query's id.
+ */
+ return ret ? ret : wr.wr_id;
}
static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
@@ -598,14 +604,15 @@ int ib_sa_path_rec_get(struct ib_device *device, u8 port_num,
rec, query->sa_query.mad->data);
*sa_query = &query->sa_query;
+
ret = send_mad(&query->sa_query, timeout_ms);
- if (ret) {
+ if (ret < 0) {
*sa_query = NULL;
kfree(query->sa_query.mad);
kfree(query);
}
- return ret ? ret : query->sa_query.id;
+ return ret;
}
EXPORT_SYMBOL(ib_sa_path_rec_get);
@@ -674,14 +681,15 @@ int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num,
rec, query->sa_query.mad->data);
*sa_query = &query->sa_query;
+
ret = send_mad(&query->sa_query, timeout_ms);
- if (ret) {
+ if (ret < 0) {
*sa_query = NULL;
kfree(query->sa_query.mad);
kfree(query);
}
- return ret ? ret : query->sa_query.id;
+ return ret;
}
EXPORT_SYMBOL(ib_sa_mcmember_rec_query);
diff --git a/drivers/infiniband/hw/mthca/mthca_av.c b/drivers/infiniband/hw/mthca/mthca_av.c
index 085baf393ca..d58dcbe6648 100644
--- a/drivers/infiniband/hw/mthca/mthca_av.c
+++ b/drivers/infiniband/hw/mthca/mthca_av.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index cd9ed958d92..1557a522d83 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -431,6 +431,36 @@ static int mthca_cmd_imm(struct mthca_dev *dev,
timeout, status);
}
+int mthca_cmd_init(struct mthca_dev *dev)
+{
+ sema_init(&dev->cmd.hcr_sem, 1);
+ sema_init(&dev->cmd.poll_sem, 1);
+ dev->cmd.use_events = 0;
+
+ dev->hcr = ioremap(pci_resource_start(dev->pdev, 0) + MTHCA_HCR_BASE,
+ MTHCA_HCR_SIZE);
+ if (!dev->hcr) {
+ mthca_err(dev, "Couldn't map command register.");
+ return -ENOMEM;
+ }
+
+ dev->cmd.pool = pci_pool_create("mthca_cmd", dev->pdev,
+ MTHCA_MAILBOX_SIZE,
+ MTHCA_MAILBOX_SIZE, 0);
+ if (!dev->cmd.pool) {
+ iounmap(dev->hcr);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void mthca_cmd_cleanup(struct mthca_dev *dev)
+{
+ pci_pool_destroy(dev->cmd.pool);
+ iounmap(dev->hcr);
+}
+
/*
* Switch to using events to issue FW commands (should be called after
* event queue to command events has been initialized).
@@ -489,6 +519,33 @@ void mthca_cmd_use_polling(struct mthca_dev *dev)
up(&dev->cmd.poll_sem);
}
+struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev,
+ unsigned int gfp_mask)
+{
+ struct mthca_mailbox *mailbox;
+
+ mailbox = kmalloc(sizeof *mailbox, gfp_mask);
+ if (!mailbox)
+ return ERR_PTR(-ENOMEM);
+
+ mailbox->buf = pci_pool_alloc(dev->cmd.pool, gfp_mask, &mailbox->dma);
+ if (!mailbox->buf) {
+ kfree(mailbox);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return mailbox;
+}
+
+void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox)
+{
+ if (!mailbox)
+ return;
+
+ pci_pool_free(dev->cmd.pool, mailbox->buf, mailbox->dma);
+ kfree(mailbox);
+}
+
int mthca_SYS_EN(struct mthca_dev *dev, u8 *status)
{
u64 out;
@@ -513,20 +570,20 @@ int mthca_SYS_DIS(struct mthca_dev *dev, u8 *status)
static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
u64 virt, u8 *status)
{
- u32 *inbox;
- dma_addr_t indma;
+ struct mthca_mailbox *mailbox;
struct mthca_icm_iter iter;
+ __be64 *pages;
int lg;
int nent = 0;
int i;
int err = 0;
int ts = 0, tc = 0;
- inbox = pci_alloc_consistent(dev->pdev, PAGE_SIZE, &indma);
- if (!inbox)
- return -ENOMEM;
-
- memset(inbox, 0, PAGE_SIZE);
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ memset(mailbox->buf, 0, MTHCA_MAILBOX_SIZE);
+ pages = mailbox->buf;
for (mthca_icm_first(icm, &iter);
!mthca_icm_last(&iter);
@@ -546,19 +603,17 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
}
for (i = 0; i < mthca_icm_size(&iter) / (1 << lg); ++i, ++nent) {
if (virt != -1) {
- *((__be64 *) (inbox + nent * 4)) =
- cpu_to_be64(virt);
+ pages[nent * 2] = cpu_to_be64(virt);
virt += 1 << lg;
}
- *((__be64 *) (inbox + nent * 4 + 2)) =
- cpu_to_be64((mthca_icm_addr(&iter) +
- (i << lg)) | (lg - 12));
+ pages[nent * 2 + 1] = cpu_to_be64((mthca_icm_addr(&iter) +
+ (i << lg)) | (lg - 12));
ts += 1 << (lg - 10);
++tc;
- if (nent == PAGE_SIZE / 16) {
- err = mthca_cmd(dev, indma, nent, 0, op,
+ if (nent == MTHCA_MAILBOX_SIZE / 16) {
+ err = mthca_cmd(dev, mailbox->dma, nent, 0, op,
CMD_TIME_CLASS_B, status);
if (err || *status)
goto out;
@@ -568,7 +623,7 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
}
if (nent)
- err = mthca_cmd(dev, indma, nent, 0, op,
+ err = mthca_cmd(dev, mailbox->dma, nent, 0, op,
CMD_TIME_CLASS_B, status);
switch (op) {
@@ -585,7 +640,7 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
}
out:
- pci_free_consistent(dev->pdev, PAGE_SIZE, inbox, indma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
@@ -606,8 +661,8 @@ int mthca_RUN_FW(struct mthca_dev *dev, u8 *status)
int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
{
+ struct mthca_mailbox *mailbox;
u32 *outbox;
- dma_addr_t outdma;
int err = 0;
u8 lg;
@@ -625,12 +680,12 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
#define QUERY_FW_EQ_ARM_BASE_OFFSET 0x40
#define QUERY_FW_EQ_SET_CI_BASE_OFFSET 0x48
- outbox = pci_alloc_consistent(dev->pdev, QUERY_FW_OUT_SIZE, &outdma);
- if (!outbox) {
- return -ENOMEM;
- }
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ outbox = mailbox->buf;
- err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_FW,
+ err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_FW,
CMD_TIME_CLASS_A, status);
if (err)
@@ -681,15 +736,15 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
}
out:
- pci_free_consistent(dev->pdev, QUERY_FW_OUT_SIZE, outbox, outdma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status)
{
+ struct mthca_mailbox *mailbox;
u8 info;
u32 *outbox;
- dma_addr_t outdma;
int err = 0;
#define ENABLE_LAM_OUT_SIZE 0x100
@@ -700,11 +755,12 @@ int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status)
#define ENABLE_LAM_INFO_HIDDEN_FLAG (1 << 4)
#define ENABLE_LAM_INFO_ECC_MASK 0x3
- outbox = pci_alloc_consistent(dev->pdev, ENABLE_LAM_OUT_SIZE, &outdma);
- if (!outbox)
- return -ENOMEM;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ outbox = mailbox->buf;
- err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_ENABLE_LAM,
+ err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_ENABLE_LAM,
CMD_TIME_CLASS_C, status);
if (err)
@@ -733,7 +789,7 @@ int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status)
(unsigned long long) dev->ddr_end);
out:
- pci_free_consistent(dev->pdev, ENABLE_LAM_OUT_SIZE, outbox, outdma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
@@ -744,9 +800,9 @@ int mthca_DISABLE_LAM(struct mthca_dev *dev, u8 *status)
int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status)
{
+ struct mthca_mailbox *mailbox;
u8 info;
u32 *outbox;
- dma_addr_t outdma;
int err = 0;
#define QUERY_DDR_OUT_SIZE 0x100
@@ -757,11 +813,12 @@ int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status)
#define QUERY_DDR_INFO_HIDDEN_FLAG (1 << 4)
#define QUERY_DDR_INFO_ECC_MASK 0x3
- outbox = pci_alloc_consistent(dev->pdev, QUERY_DDR_OUT_SIZE, &outdma);
- if (!outbox)
- return -ENOMEM;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ outbox = mailbox->buf;
- err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_DDR,
+ err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DDR,
CMD_TIME_CLASS_A, status);
if (err)
@@ -787,15 +844,15 @@ int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status)
(unsigned long long) dev->ddr_end);
out:
- pci_free_consistent(dev->pdev, QUERY_DDR_OUT_SIZE, outbox, outdma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
struct mthca_dev_lim *dev_lim, u8 *status)
{
+ struct mthca_mailbox *mailbox;
u32 *outbox;
- dma_addr_t outdma;
u8 field;
u16 size;
int err;
@@ -860,11 +917,12 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
#define QUERY_DEV_LIM_LAMR_OFFSET 0x9f
#define QUERY_DEV_LIM_MAX_ICM_SZ_OFFSET 0xa0
- outbox = pci_alloc_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, &outdma);
- if (!outbox)
- return -ENOMEM;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ outbox = mailbox->buf;
- err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_DEV_LIM,
+ err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DEV_LIM,
CMD_TIME_CLASS_A, status);
if (err)
@@ -1020,15 +1078,15 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
}
out:
- pci_free_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, outbox, outdma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
int mthca_QUERY_ADAPTER(struct mthca_dev *dev,
struct mthca_adapter *adapter, u8 *status)
{
+ struct mthca_mailbox *mailbox;
u32 *outbox;
- dma_addr_t outdma;
int err;
#define QUERY_ADAPTER_OUT_SIZE 0x100
@@ -1037,23 +1095,24 @@ int mthca_QUERY_ADAPTER(struct mthca_dev *dev,
#define QUERY_ADAPTER_REVISION_ID_OFFSET 0x08
#define QUERY_ADAPTER_INTA_PIN_OFFSET 0x10
- outbox = pci_alloc_consistent(dev->pdev, QUERY_ADAPTER_OUT_SIZE, &outdma);
- if (!outbox)
- return -ENOMEM;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ outbox = mailbox->buf;
- err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_ADAPTER,
+ err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_ADAPTER,
CMD_TIME_CLASS_A, status);
if (err)
goto out;
- MTHCA_GET(adapter->vendor_id, outbox, QUERY_ADAPTER_VENDOR_ID_OFFSET);
- MTHCA_GET(adapter->device_id, outbox, QUERY_ADAPTER_DEVICE_ID_OFFSET);
+ MTHCA_GET(adapter->vendor_id, outbox, QUERY_ADAPTER_VENDOR_ID_OFFSET);
+ MTHCA_GET(adapter->device_id, outbox, QUERY_ADAPTER_DEVICE_ID_OFFSET);
MTHCA_GET(adapter->revision_id, outbox, QUERY_ADAPTER_REVISION_ID_OFFSET);
- MTHCA_GET(adapter->inta_pin, outbox, QUERY_ADAPTER_INTA_PIN_OFFSET);
+ MTHCA_GET(adapter->inta_pin, outbox, QUERY_ADAPTER_INTA_PIN_OFFSET);
out:
- pci_free_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, outbox, outdma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
@@ -1061,8 +1120,8 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
struct mthca_init_hca_param *param,
u8 *status)
{
+ struct mthca_mailbox *mailbox;
u32 *inbox;
- dma_addr_t indma;
int err;
#define INIT_HCA_IN_SIZE 0x200
@@ -1102,9 +1161,10 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
#define INIT_HCA_UAR_SCATCH_BASE_OFFSET (INIT_HCA_UAR_OFFSET + 0x10)
#define INIT_HCA_UAR_CTX_BASE_OFFSET (INIT_HCA_UAR_OFFSET + 0x18)
- inbox = pci_alloc_consistent(dev->pdev, INIT_HCA_IN_SIZE, &indma);
- if (!inbox)
- return -ENOMEM;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ inbox = mailbox->buf;
memset(inbox, 0, INIT_HCA_IN_SIZE);
@@ -1167,10 +1227,9 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
MTHCA_PUT(inbox, param->uarc_base, INIT_HCA_UAR_CTX_BASE_OFFSET);
}
- err = mthca_cmd(dev, indma, 0, 0, CMD_INIT_HCA,
- HZ, status);
+ err = mthca_cmd(dev, mailbox->dma, 0, 0, CMD_INIT_HCA, HZ, status);
- pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
@@ -1178,8 +1237,8 @@ int mthca_INIT_IB(struct mthca_dev *dev,
struct mthca_init_ib_param *param,
int port, u8 *status)
{
+ struct mthca_mailbox *mailbox;
u32 *inbox;
- dma_addr_t indma;
int err;
u32 flags;
@@ -1199,9 +1258,10 @@ int mthca_INIT_IB(struct mthca_dev *dev,
#define INIT_IB_NODE_GUID_OFFSET 0x18
#define INIT_IB_SI_GUID_OFFSET 0x20
- inbox = pci_alloc_consistent(dev->pdev, INIT_IB_IN_SIZE, &indma);
- if (!inbox)
- return -ENOMEM;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ inbox = mailbox->buf;
memset(inbox, 0, INIT_IB_IN_SIZE);
@@ -1221,10 +1281,10 @@ int mthca_INIT_IB(struct mthca_dev *dev,
MTHCA_PUT(inbox, param->node_guid, INIT_IB_NODE_GUID_OFFSET);
MTHCA_PUT(inbox, param->si_guid, INIT_IB_SI_GUID_OFFSET);
- err = mthca_cmd(dev, indma, port, 0, CMD_INIT_IB,
+ err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_INIT_IB,
CMD_TIME_CLASS_A, status);
- pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
@@ -1241,8 +1301,8 @@ int mthca_CLOSE_HCA(struct mthca_dev *dev, int panic, u8 *status)
int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
int port, u8 *status)
{
+ struct mthca_mailbox *mailbox;
u32 *inbox;
- dma_addr_t indma;
int err;
u32 flags = 0;
@@ -1253,9 +1313,10 @@ int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
#define SET_IB_CAP_MASK_OFFSET 0x04
#define SET_IB_SI_GUID_OFFSET 0x08
- inbox = pci_alloc_consistent(dev->pdev, SET_IB_IN_SIZE, &indma);
- if (!inbox)
- return -ENOMEM;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ inbox = mailbox->buf;
memset(inbox, 0, SET_IB_IN_SIZE);
@@ -1266,10 +1327,10 @@ int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
MTHCA_PUT(inbox, param->cap_mask, SET_IB_CAP_MASK_OFFSET);
MTHCA_PUT(inbox, param->si_guid, SET_IB_SI_GUID_OFFSET);
- err = mthca_cmd(dev, indma, port, 0, CMD_SET_IB,
+ err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_SET_IB,
CMD_TIME_CLASS_B, status);
- pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
@@ -1280,20 +1341,22 @@ int mthca_MAP_ICM(struct mthca_dev *dev, struct mthca_icm *icm, u64 virt, u8 *st
int mthca_MAP_ICM_page(struct mthca_dev *dev, u64 dma_addr, u64 virt, u8 *status)
{
+ struct mthca_mailbox *mailbox;
u64 *inbox;
- dma_addr_t indma;
int err;
- inbox = pci_alloc_consistent(dev->pdev, 16, &indma);
- if (!inbox)
- return -ENOMEM;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ inbox = mailbox->buf;
inbox[0] = cpu_to_be64(virt);
inbox[1] = cpu_to_be64(dma_addr);
- err = mthca_cmd(dev, indma, 1, 0, CMD_MAP_ICM, CMD_TIME_CLASS_B, status);
+ err = mthca_cmd(dev, mailbox->dma, 1, 0, CMD_MAP_ICM,
+ CMD_TIME_CLASS_B, status);
- pci_free_consistent(dev->pdev, 16, inbox, indma);
+ mthca_free_mailbox(dev, mailbox);
if (!err)
mthca_dbg(dev, "Mapped page at %llx to %llx for ICM.\n",
@@ -1338,69 +1401,26 @@ int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages,
return 0;
}
-int mthca_SW2HW_MPT(struct mthca_dev *dev, void *mpt_entry,
+int mthca_SW2HW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int mpt_index, u8 *status)
{
- dma_addr_t indma;
- int err;
-
- indma = pci_map_single(dev->pdev, mpt_entry,
- MTHCA_MPT_ENTRY_SIZE,
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(indma))
- return -ENOMEM;
-
- err = mthca_cmd(dev, indma, mpt_index, 0, CMD_SW2HW_MPT,
- CMD_TIME_CLASS_B, status);
-
- pci_unmap_single(dev->pdev, indma,
- MTHCA_MPT_ENTRY_SIZE, PCI_DMA_TODEVICE);
- return err;
+ return mthca_cmd(dev, mailbox->dma, mpt_index, 0, CMD_SW2HW_MPT,
+ CMD_TIME_CLASS_B, status);
}
-int mthca_HW2SW_MPT(struct mthca_dev *dev, void *mpt_entry,
+int mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int mpt_index, u8 *status)
{
- dma_addr_t outdma = 0;
- int err;
-
- if (mpt_entry) {
- outdma = pci_map_single(dev->pdev, mpt_entry,
- MTHCA_MPT_ENTRY_SIZE,
- PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(outdma))
- return -ENOMEM;
- }
-
- err = mthca_cmd_box(dev, 0, outdma, mpt_index, !mpt_entry,
- CMD_HW2SW_MPT,
- CMD_TIME_CLASS_B, status);
-
- if (mpt_entry)
- pci_unmap_single(dev->pdev, outdma,
- MTHCA_MPT_ENTRY_SIZE,
- PCI_DMA_FROMDEVICE);
- return err;
+ return mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, mpt_index,
+ !mailbox, CMD_HW2SW_MPT,
+ CMD_TIME_CLASS_B, status);
}
-int mthca_WRITE_MTT(struct mthca_dev *dev, u64 *mtt_entry,
+int mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int num_mtt, u8 *status)
{
- dma_addr_t indma;
- int err;
-
- indma = pci_map_single(dev->pdev, mtt_entry,
- (num_mtt + 2) * 8,
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(indma))
- return -ENOMEM;
-
- err = mthca_cmd(dev, indma, num_mtt, 0, CMD_WRITE_MTT,
- CMD_TIME_CLASS_B, status);
-
- pci_unmap_single(dev->pdev, indma,
- (num_mtt + 2) * 8, PCI_DMA_TODEVICE);
- return err;
+ return mthca_cmd(dev, mailbox->dma, num_mtt, 0, CMD_WRITE_MTT,
+ CMD_TIME_CLASS_B, status);
}
int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status)
@@ -1418,92 +1438,38 @@ int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap,
0, CMD_MAP_EQ, CMD_TIME_CLASS_B, status);
}
-int mthca_SW2HW_EQ(struct mthca_dev *dev, void *eq_context,
+int mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int eq_num, u8 *status)
{
- dma_addr_t indma;
- int err;
-
- indma = pci_map_single(dev->pdev, eq_context,
- MTHCA_EQ_CONTEXT_SIZE,
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(indma))
- return -ENOMEM;
-
- err = mthca_cmd(dev, indma, eq_num, 0, CMD_SW2HW_EQ,
- CMD_TIME_CLASS_A, status);
-
- pci_unmap_single(dev->pdev, indma,
- MTHCA_EQ_CONTEXT_SIZE, PCI_DMA_TODEVICE);
- return err;
+ return mthca_cmd(dev, mailbox->dma, eq_num, 0, CMD_SW2HW_EQ,
+ CMD_TIME_CLASS_A, status);
}
-int mthca_HW2SW_EQ(struct mthca_dev *dev, void *eq_context,
+int mthca_HW2SW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int eq_num, u8 *status)
{
- dma_addr_t outdma = 0;
- int err;
-
- outdma = pci_map_single(dev->pdev, eq_context,
- MTHCA_EQ_CONTEXT_SIZE,
- PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(outdma))
- return -ENOMEM;
-
- err = mthca_cmd_box(dev, 0, outdma, eq_num, 0,
- CMD_HW2SW_EQ,
- CMD_TIME_CLASS_A, status);
-
- pci_unmap_single(dev->pdev, outdma,
- MTHCA_EQ_CONTEXT_SIZE,
- PCI_DMA_FROMDEVICE);
- return err;
+ return mthca_cmd_box(dev, 0, mailbox->dma, eq_num, 0,
+ CMD_HW2SW_EQ,
+ CMD_TIME_CLASS_A, status);
}
-int mthca_SW2HW_CQ(struct mthca_dev *dev, void *cq_context,
+int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int cq_num, u8 *status)
{
- dma_addr_t indma;
- int err;
-
- indma = pci_map_single(dev->pdev, cq_context,
- MTHCA_CQ_CONTEXT_SIZE,
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(indma))
- return -ENOMEM;
-
- err = mthca_cmd(dev, indma, cq_num, 0, CMD_SW2HW_CQ,
+ return mthca_cmd(dev, mailbox->dma, cq_num, 0, CMD_SW2HW_CQ,
CMD_TIME_CLASS_A, status);
-
- pci_unmap_single(dev->pdev, indma,
- MTHCA_CQ_CONTEXT_SIZE, PCI_DMA_TODEVICE);
- return err;
}
-int mthca_HW2SW_CQ(struct mthca_dev *dev, void *cq_context,
+int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int cq_num, u8 *status)
{
- dma_addr_t outdma = 0;
- int err;
-
- outdma = pci_map_single(dev->pdev, cq_context,
- MTHCA_CQ_CONTEXT_SIZE,
- PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(outdma))
- return -ENOMEM;
-
- err = mthca_cmd_box(dev, 0, outdma, cq_num, 0,
- CMD_HW2SW_CQ,
- CMD_TIME_CLASS_A, status);
-
- pci_unmap_single(dev->pdev, outdma,
- MTHCA_CQ_CONTEXT_SIZE,
- PCI_DMA_FROMDEVICE);
- return err;
+ return mthca_cmd_box(dev, 0, mailbox->dma, cq_num, 0,
+ CMD_HW2SW_CQ,
+ CMD_TIME_CLASS_A, status);
}
int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
- int is_ee, void *qp_context, u32 optmask,
+ int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
u8 *status)
{
static const u16 op[] = {
@@ -1520,36 +1486,34 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
[MTHCA_TRANS_ANY2RST] = CMD_ERR2RST_QPEE
};
u8 op_mod = 0;
-
- dma_addr_t indma;
+ int my_mailbox = 0;
int err;
if (trans < 0 || trans >= ARRAY_SIZE(op))
return -EINVAL;
if (trans == MTHCA_TRANS_ANY2RST) {
- indma = 0;
op_mod = 3; /* don't write outbox, any->reset */
/* For debugging */
- qp_context = pci_alloc_consistent(dev->pdev, MTHCA_QP_CONTEXT_SIZE,
- &indma);
- op_mod = 2; /* write outbox, any->reset */
+ if (!mailbox) {
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (!IS_ERR(mailbox)) {
+ my_mailbox = 1;
+ op_mod = 2; /* write outbox, any->reset */
+ } else
+ mailbox = NULL;
+ }
} else {
- indma = pci_map_single(dev->pdev, qp_context,
- MTHCA_QP_CONTEXT_SIZE,
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(indma))
- return -ENOMEM;
-
if (0) {
int i;
mthca_dbg(dev, "Dumping QP context:\n");
- printk(" opt param mask: %08x\n", be32_to_cpup(qp_context));
+ printk(" opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
for (i = 0; i < 0x100 / 4; ++i) {
if (i % 8 == 0)
printk(" [%02x] ", i * 4);
- printk(" %08x", be32_to_cpu(((u32 *) qp_context)[i + 2]));
+ printk(" %08x",
+ be32_to_cpu(((u32 *) mailbox->buf)[i + 2]));
if ((i + 1) % 8 == 0)
printk("\n");
}
@@ -1557,55 +1521,39 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
}
if (trans == MTHCA_TRANS_ANY2RST) {
- err = mthca_cmd_box(dev, 0, indma, (!!is_ee << 24) | num,
- op_mod, op[trans], CMD_TIME_CLASS_C, status);
+ err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0,
+ (!!is_ee << 24) | num, op_mod,
+ op[trans], CMD_TIME_CLASS_C, status);
- if (0) {
+ if (0 && mailbox) {
int i;
mthca_dbg(dev, "Dumping QP context:\n");
- printk(" %08x\n", be32_to_cpup(qp_context));
+ printk(" %08x\n", be32_to_cpup(mailbox->buf));
for (i = 0; i < 0x100 / 4; ++i) {
if (i % 8 == 0)
printk("[%02x] ", i * 4);
- printk(" %08x", be32_to_cpu(((u32 *) qp_context)[i + 2]));
+ printk(" %08x",
+ be32_to_cpu(((u32 *) mailbox->buf)[i + 2]));
if ((i + 1) % 8 == 0)
printk("\n");
}
}
} else
- err = mthca_cmd(dev, indma, (!!is_ee << 24) | num,
+ err = mthca_cmd(dev, mailbox->dma, (!!is_ee << 24) | num,
op_mod, op[trans], CMD_TIME_CLASS_C, status);
- if (trans != MTHCA_TRANS_ANY2RST)
- pci_unmap_single(dev->pdev, indma,
- MTHCA_QP_CONTEXT_SIZE, PCI_DMA_TODEVICE);
- else
- pci_free_consistent(dev->pdev, MTHCA_QP_CONTEXT_SIZE,
- qp_context, indma);
+ if (my_mailbox)
+ mthca_free_mailbox(dev, mailbox);
+
return err;
}
int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
- void *qp_context, u8 *status)
+ struct mthca_mailbox *mailbox, u8 *status)
{
- dma_addr_t outdma = 0;
- int err;
-
- outdma = pci_map_single(dev->pdev, qp_context,
- MTHCA_QP_CONTEXT_SIZE,
- PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(outdma))
- return -ENOMEM;
-
- err = mthca_cmd_box(dev, 0, outdma, (!!is_ee << 24) | num, 0,
- CMD_QUERY_QPEE,
- CMD_TIME_CLASS_A, status);
-
- pci_unmap_single(dev->pdev, outdma,
- MTHCA_QP_CONTEXT_SIZE,
- PCI_DMA_FROMDEVICE);
- return err;
+ return mthca_cmd_box(dev, 0, mailbox->dma, (!!is_ee << 24) | num, 0,
+ CMD_QUERY_QPEE, CMD_TIME_CLASS_A, status);
}
int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
@@ -1635,11 +1583,11 @@ int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
}
int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
- int port, struct ib_wc* in_wc, struct ib_grh* in_grh,
+ int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
void *in_mad, void *response_mad, u8 *status)
{
- void *box;
- dma_addr_t dma;
+ struct mthca_mailbox *inmailbox, *outmailbox;
+ void *inbox;
int err;
u32 in_modifier = port;
u8 op_modifier = 0;
@@ -1653,11 +1601,18 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
#define MAD_IFC_PKEY_OFFSET 0x10e
#define MAD_IFC_GRH_OFFSET 0x140
- box = pci_alloc_consistent(dev->pdev, MAD_IFC_BOX_SIZE, &dma);
- if (!box)
- return -ENOMEM;
+ inmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(inmailbox))
+ return PTR_ERR(inmailbox);
+ inbox = inmailbox->buf;
- memcpy(box, in_mad, 256);
+ outmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(outmailbox)) {
+ mthca_free_mailbox(dev, inmailbox);
+ return PTR_ERR(outmailbox);
+ }
+
+ memcpy(inbox, in_mad, 256);
/*
* Key check traps can't be generated unless we have in_wc to
@@ -1671,97 +1626,65 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
if (in_wc) {
u8 val;
- memset(box + 256, 0, 256);
+ memset(inbox + 256, 0, 256);
- MTHCA_PUT(box, in_wc->qp_num, MAD_IFC_MY_QPN_OFFSET);
- MTHCA_PUT(box, in_wc->src_qp, MAD_IFC_RQPN_OFFSET);
+ MTHCA_PUT(inbox, in_wc->qp_num, MAD_IFC_MY_QPN_OFFSET);
+ MTHCA_PUT(inbox, in_wc->src_qp, MAD_IFC_RQPN_OFFSET);
val = in_wc->sl << 4;
- MTHCA_PUT(box, val, MAD_IFC_SL_OFFSET);
+ MTHCA_PUT(inbox, val, MAD_IFC_SL_OFFSET);
val = in_wc->dlid_path_bits |
(in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0);
- MTHCA_PUT(box, val, MAD_IFC_GRH_OFFSET);
+ MTHCA_PUT(inbox, val, MAD_IFC_GRH_OFFSET);
- MTHCA_PUT(box, in_wc->slid, MAD_IFC_RLID_OFFSET);
- MTHCA_PUT(box, in_wc->pkey_index, MAD_IFC_PKEY_OFFSET);
+ MTHCA_PUT(inbox, in_wc->slid, MAD_IFC_RLID_OFFSET);
+ MTHCA_PUT(inbox, in_wc->pkey_index, MAD_IFC_PKEY_OFFSET);
if (in_grh)
- memcpy((u8 *) box + MAD_IFC_GRH_OFFSET, in_grh, 40);
+ memcpy(inbox + MAD_IFC_GRH_OFFSET, in_grh, 40);
op_modifier |= 0x10;
in_modifier |= in_wc->slid << 16;
}
- err = mthca_cmd_box(dev, dma, dma + 512, in_modifier, op_modifier,
+ err = mthca_cmd_box(dev, inmailbox->dma, outmailbox->dma,
+ in_modifier, op_modifier,
CMD_MAD_IFC, CMD_TIME_CLASS_C, status);
if (!err && !*status)
- memcpy(response_mad, box + 512, 256);
+ memcpy(response_mad, outmailbox->buf, 256);
- pci_free_consistent(dev->pdev, MAD_IFC_BOX_SIZE, box, dma);
+ mthca_free_mailbox(dev, inmailbox);
+ mthca_free_mailbox(dev, outmailbox);
return err;
}
-int mthca_READ_MGM(struct mthca_dev *dev, int index, void *mgm,
- u8 *status)
+int mthca_READ_MGM(struct mthca_dev *dev, int index,
+ struct mthca_mailbox *mailbox, u8 *status)
{
- dma_addr_t outdma = 0;
- int err;
-
- outdma = pci_map_single(dev->pdev, mgm,
- MTHCA_MGM_ENTRY_SIZE,
- PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(outdma))
- return -ENOMEM;
-
- err = mthca_cmd_box(dev, 0, outdma, index, 0,
- CMD_READ_MGM,
- CMD_TIME_CLASS_A, status);
-
- pci_unmap_single(dev->pdev, outdma,
- MTHCA_MGM_ENTRY_SIZE,
- PCI_DMA_FROMDEVICE);
- return err;
+ return mthca_cmd_box(dev, 0, mailbox->dma, index, 0,
+ CMD_READ_MGM, CMD_TIME_CLASS_A, status);
}
-int mthca_WRITE_MGM(struct mthca_dev *dev, int index, void *mgm,
- u8 *status)
+int mthca_WRITE_MGM(struct mthca_dev *dev, int index,
+ struct mthca_mailbox *mailbox, u8 *status)
{
- dma_addr_t indma;
- int err;
-
- indma = pci_map_single(dev->pdev, mgm,
- MTHCA_MGM_ENTRY_SIZE,
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(indma))
- return -ENOMEM;
-
- err = mthca_cmd(dev, indma, index, 0, CMD_WRITE_MGM,
- CMD_TIME_CLASS_A, status);
-
- pci_unmap_single(dev->pdev, indma,
- MTHCA_MGM_ENTRY_SIZE, PCI_DMA_TODEVICE);
- return err;
+ return mthca_cmd(dev, mailbox->dma, index, 0, CMD_WRITE_MGM,
+ CMD_TIME_CLASS_A, status);
}
-int mthca_MGID_HASH(struct mthca_dev *dev, void *gid, u16 *hash,
- u8 *status)
+int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
+ u16 *hash, u8 *status)
{
- dma_addr_t indma;
u64 imm;
int err;
- indma = pci_map_single(dev->pdev, gid, 16, PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(indma))
- return -ENOMEM;
-
- err = mthca_cmd_imm(dev, indma, &imm, 0, 0, CMD_MGID_HASH,
+ err = mthca_cmd_imm(dev, mailbox->dma, &imm, 0, 0, CMD_MGID_HASH,
CMD_TIME_CLASS_A, status);
- *hash = imm;
- pci_unmap_single(dev->pdev, indma, 16, PCI_DMA_TODEVICE);
+ *hash = imm;
return err;
}
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.h b/drivers/infiniband/hw/mthca/mthca_cmd.h
index adf039b3c54..ed517f175dd 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.h
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.h
@@ -37,8 +37,7 @@
#include <ib_verbs.h>
-#define MTHCA_CMD_MAILBOX_ALIGN 16UL
-#define MTHCA_CMD_MAILBOX_EXTRA (MTHCA_CMD_MAILBOX_ALIGN - 1)
+#define MTHCA_MAILBOX_SIZE 4096
enum {
/* command completed successfully: */
@@ -112,6 +111,11 @@ enum {
DEV_LIM_FLAG_UD_MULTI = 1 << 21,
};
+struct mthca_mailbox {
+ dma_addr_t dma;
+ void *buf;
+};
+
struct mthca_dev_lim {
int max_srq_sz;
int max_qp_sz;
@@ -235,11 +239,17 @@ struct mthca_set_ib_param {
u32 cap_mask;
};
+int mthca_cmd_init(struct mthca_dev *dev);
+void mthca_cmd_cleanup(struct mthca_dev *dev);
int mthca_cmd_use_events(struct mthca_dev *dev);
void mthca_cmd_use_polling(struct mthca_dev *dev);
void mthca_cmd_event(struct mthca_dev *dev, u16 token,
u8 status, u64 out_param);
+struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev,
+ unsigned int gfp_mask);
+void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox);
+
int mthca_SYS_EN(struct mthca_dev *dev, u8 *status);
int mthca_SYS_DIS(struct mthca_dev *dev, u8 *status);
int mthca_MAP_FA(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status);
@@ -270,41 +280,39 @@ int mthca_MAP_ICM_AUX(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status);
int mthca_UNMAP_ICM_AUX(struct mthca_dev *dev, u8 *status);
int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages,
u8 *status);
-int mthca_SW2HW_MPT(struct mthca_dev *dev, void *mpt_entry,
+int mthca_SW2HW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int mpt_index, u8 *status);
-int mthca_HW2SW_MPT(struct mthca_dev *dev, void *mpt_entry,
+int mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int mpt_index, u8 *status);
-int mthca_WRITE_MTT(struct mthca_dev *dev, u64 *mtt_entry,
+int mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int num_mtt, u8 *status);
int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status);
int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap,
int eq_num, u8 *status);
-int mthca_SW2HW_EQ(struct mthca_dev *dev, void *eq_context,
+int mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int eq_num, u8 *status);
-int mthca_HW2SW_EQ(struct mthca_dev *dev, void *eq_context,
+int mthca_HW2SW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int eq_num, u8 *status);
-int mthca_SW2HW_CQ(struct mthca_dev *dev, void *cq_context,
+int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int cq_num, u8 *status);
-int mthca_HW2SW_CQ(struct mthca_dev *dev, void *cq_context,
+int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int cq_num, u8 *status);
int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
- int is_ee, void *qp_context, u32 optmask,
+ int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
u8 *status);
int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
- void *qp_context, u8 *status);
+ struct mthca_mailbox *mailbox, u8 *status);
int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
u8 *status);
int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
- int port, struct ib_wc* in_wc, struct ib_grh* in_grh,
+ int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
void *in_mad, void *response_mad, u8 *status);
-int mthca_READ_MGM(struct mthca_dev *dev, int index, void *mgm,
- u8 *status);
-int mthca_WRITE_MGM(struct mthca_dev *dev, int index, void *mgm,
- u8 *status);
-int mthca_MGID_HASH(struct mthca_dev *dev, void *gid, u16 *hash,
- u8 *status);
+int mthca_READ_MGM(struct mthca_dev *dev, int index,
+ struct mthca_mailbox *mailbox, u8 *status);
+int mthca_WRITE_MGM(struct mthca_dev *dev, int index,
+ struct mthca_mailbox *mailbox, u8 *status);
+int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
+ u16 *hash, u8 *status);
int mthca_NOP(struct mthca_dev *dev, u8 *status);
-#define MAILBOX_ALIGN(x) ((void *) ALIGN((unsigned long) (x), MTHCA_CMD_MAILBOX_ALIGN))
-
#endif /* MTHCA_CMD_H */
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index 2bf347b84c3..766e9031ec4 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -171,6 +172,17 @@ static inline void set_cqe_hw(struct mthca_cqe *cqe)
cqe->owner = MTHCA_CQ_ENTRY_OWNER_HW;
}
+static void dump_cqe(struct mthca_dev *dev, void *cqe_ptr)
+{
+ __be32 *cqe = cqe_ptr;
+
+ (void) cqe; /* avoid warning if mthca_dbg compiled away... */
+ mthca_dbg(dev, "CQE contents %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ be32_to_cpu(cqe[0]), be32_to_cpu(cqe[1]), be32_to_cpu(cqe[2]),
+ be32_to_cpu(cqe[3]), be32_to_cpu(cqe[4]), be32_to_cpu(cqe[5]),
+ be32_to_cpu(cqe[6]), be32_to_cpu(cqe[7]));
+}
+
/*
* incr is ignored in native Arbel (mem-free) mode, so cq->cons_index
* should be correct before calling update_cons_index().
@@ -280,16 +292,12 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
int dbd;
u32 new_wqe;
- if (1 && cqe->syndrome != SYNDROME_WR_FLUSH_ERR) {
- int j;
-
- mthca_dbg(dev, "%x/%d: error CQE -> QPN %06x, WQE @ %08x\n",
- cq->cqn, cq->cons_index, be32_to_cpu(cqe->my_qpn),
- be32_to_cpu(cqe->wqe));
-
- for (j = 0; j < 8; ++j)
- printk(KERN_DEBUG " [%2x] %08x\n",
- j * 4, be32_to_cpu(((u32 *) cqe)[j]));
+ if (cqe->syndrome == SYNDROME_LOCAL_QP_OP_ERR) {
+ mthca_dbg(dev, "local QP operation err "
+ "(QPN %06x, WQE @ %08x, CQN %06x, index %d)\n",
+ be32_to_cpu(cqe->my_qpn), be32_to_cpu(cqe->wqe),
+ cq->cqn, cq->cons_index);
+ dump_cqe(dev, cqe);
}
/*
@@ -377,15 +385,6 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
return 0;
}
-static void dump_cqe(struct mthca_cqe *cqe)
-{
- int j;
-
- for (j = 0; j < 8; ++j)
- printk(KERN_DEBUG " [%2x] %08x\n",
- j * 4, be32_to_cpu(((u32 *) cqe)[j]));
-}
-
static inline int mthca_poll_one(struct mthca_dev *dev,
struct mthca_cq *cq,
struct mthca_qp **cur_qp,
@@ -414,8 +413,7 @@ static inline int mthca_poll_one(struct mthca_dev *dev,
mthca_dbg(dev, "%x/%d: CQE -> QPN %06x, WQE @ %08x\n",
cq->cqn, cq->cons_index, be32_to_cpu(cqe->my_qpn),
be32_to_cpu(cqe->wqe));
-
- dump_cqe(cqe);
+ dump_cqe(dev, cqe);
}
is_error = (cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) ==
@@ -638,19 +636,19 @@ static void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq *cq)
int size;
if (cq->is_direct)
- pci_free_consistent(dev->pdev,
- (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
- cq->queue.direct.buf,
- pci_unmap_addr(&cq->queue.direct,
- mapping));
+ dma_free_coherent(&dev->pdev->dev,
+ (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
+ cq->queue.direct.buf,
+ pci_unmap_addr(&cq->queue.direct,
+ mapping));
else {
size = (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE;
for (i = 0; i < (size + PAGE_SIZE - 1) / PAGE_SIZE; ++i)
if (cq->queue.page_list[i].buf)
- pci_free_consistent(dev->pdev, PAGE_SIZE,
- cq->queue.page_list[i].buf,
- pci_unmap_addr(&cq->queue.page_list[i],
- mapping));
+ dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+ cq->queue.page_list[i].buf,
+ pci_unmap_addr(&cq->queue.page_list[i],
+ mapping));
kfree(cq->queue.page_list);
}
@@ -670,8 +668,8 @@ static int mthca_alloc_cq_buf(struct mthca_dev *dev, int size,
npages = 1;
shift = get_order(size) + PAGE_SHIFT;
- cq->queue.direct.buf = pci_alloc_consistent(dev->pdev,
- size, &t);
+ cq->queue.direct.buf = dma_alloc_coherent(&dev->pdev->dev,
+ size, &t, GFP_KERNEL);
if (!cq->queue.direct.buf)
return -ENOMEM;
@@ -709,7 +707,8 @@ static int mthca_alloc_cq_buf(struct mthca_dev *dev, int size,
for (i = 0; i < npages; ++i) {
cq->queue.page_list[i].buf =
- pci_alloc_consistent(dev->pdev, PAGE_SIZE, &t);
+ dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
+ &t, GFP_KERNEL);
if (!cq->queue.page_list[i].buf)
goto err_free;
@@ -746,7 +745,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
struct mthca_cq *cq)
{
int size = nent * MTHCA_CQ_ENTRY_SIZE;
- void *mailbox = NULL;
+ struct mthca_mailbox *mailbox;
struct mthca_cq_context *cq_context;
int err = -ENOMEM;
u8 status;
@@ -780,12 +779,11 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
goto err_out_ci;
}
- mailbox = kmalloc(sizeof (struct mthca_cq_context) + MTHCA_CMD_MAILBOX_EXTRA,
- GFP_KERNEL);
- if (!mailbox)
- goto err_out_mailbox;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ goto err_out_arm;
- cq_context = MAILBOX_ALIGN(mailbox);
+ cq_context = mailbox->buf;
err = mthca_alloc_cq_buf(dev, size, cq);
if (err)
@@ -816,7 +814,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
cq_context->state_db = cpu_to_be32(cq->arm_db_index);
}
- err = mthca_SW2HW_CQ(dev, cq_context, cq->cqn, &status);
+ err = mthca_SW2HW_CQ(dev, mailbox, cq->cqn, &status);
if (err) {
mthca_warn(dev, "SW2HW_CQ failed (%d)\n", err);
goto err_out_free_mr;
@@ -840,7 +838,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
cq->cons_index = 0;
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
return 0;
@@ -849,8 +847,9 @@ err_out_free_mr:
mthca_free_cq_buf(dev, cq);
err_out_mailbox:
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
+err_out_arm:
if (mthca_is_memfree(dev))
mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
@@ -870,28 +869,26 @@ err_out:
void mthca_free_cq(struct mthca_dev *dev,
struct mthca_cq *cq)
{
- void *mailbox;
+ struct mthca_mailbox *mailbox;
int err;
u8 status;
might_sleep();
- mailbox = kmalloc(sizeof (struct mthca_cq_context) + MTHCA_CMD_MAILBOX_EXTRA,
- GFP_KERNEL);
- if (!mailbox) {
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox)) {
mthca_warn(dev, "No memory for mailbox to free CQ.\n");
return;
}
- err = mthca_HW2SW_CQ(dev, MAILBOX_ALIGN(mailbox), cq->cqn, &status);
+ err = mthca_HW2SW_CQ(dev, mailbox, cq->cqn, &status);
if (err)
mthca_warn(dev, "HW2SW_CQ failed (%d)\n", err);
else if (status)
- mthca_warn(dev, "HW2SW_CQ returned status 0x%02x\n",
- status);
+ mthca_warn(dev, "HW2SW_CQ returned status 0x%02x\n", status);
if (0) {
- u32 *ctx = MAILBOX_ALIGN(mailbox);
+ u32 *ctx = mailbox->buf;
int j;
printk(KERN_ERR "context for CQN %x (cons index %x, next sw %d)\n",
@@ -919,11 +916,11 @@ void mthca_free_cq(struct mthca_dev *dev,
if (mthca_is_memfree(dev)) {
mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
- mthca_table_put(dev, dev->cq_table.table, cq->cqn);
}
+ mthca_table_put(dev, dev->cq_table.table, cq->cqn);
mthca_free(&dev->cq_table.alloc, cq->cqn);
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
}
int __devinit mthca_init_cq_table(struct mthca_dev *dev)
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index e3d79e267dc..4127f09dc5e 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -46,8 +47,8 @@
#define DRV_NAME "ib_mthca"
#define PFX DRV_NAME ": "
-#define DRV_VERSION "0.06-pre"
-#define DRV_RELDATE "November 8, 2004"
+#define DRV_VERSION "0.06"
+#define DRV_RELDATE "June 23, 2005"
enum {
MTHCA_FLAG_DDR_HIDDEN = 1 << 1,
@@ -98,6 +99,7 @@ enum {
};
struct mthca_cmd {
+ struct pci_pool *pool;
int use_events;
struct semaphore hcr_sem;
struct semaphore poll_sem;
@@ -379,6 +381,12 @@ void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar);
int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd);
void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd);
+struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size);
+void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt);
+int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
+ int start_index, u64 *buffer_list, int list_len);
+int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
+ u64 iova, u64 total_size, u32 access, struct mthca_mr *mr);
int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
u32 access, struct mthca_mr *mr);
int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
diff --git a/drivers/infiniband/hw/mthca/mthca_doorbell.h b/drivers/infiniband/hw/mthca/mthca_doorbell.h
index 821039a4904..535fad7710f 100644
--- a/drivers/infiniband/hw/mthca/mthca_doorbell.h
+++ b/drivers/infiniband/hw/mthca/mthca_doorbell.h
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
index f46d615d396..cbcf2b4722e 100644
--- a/drivers/infiniband/hw/mthca/mthca_eq.c
+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -469,7 +469,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
PAGE_SIZE;
u64 *dma_list = NULL;
dma_addr_t t;
- void *mailbox = NULL;
+ struct mthca_mailbox *mailbox;
struct mthca_eq_context *eq_context;
int err = -ENOMEM;
int i;
@@ -494,17 +494,16 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
if (!dma_list)
goto err_out_free;
- mailbox = kmalloc(sizeof *eq_context + MTHCA_CMD_MAILBOX_EXTRA,
- GFP_KERNEL);
- if (!mailbox)
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
goto err_out_free;
- eq_context = MAILBOX_ALIGN(mailbox);
+ eq_context = mailbox->buf;
for (i = 0; i < npages; ++i) {
- eq->page_list[i].buf = pci_alloc_consistent(dev->pdev,
- PAGE_SIZE, &t);
+ eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev,
+ PAGE_SIZE, &t, GFP_KERNEL);
if (!eq->page_list[i].buf)
- goto err_out_free;
+ goto err_out_free_pages;
dma_list[i] = t;
pci_unmap_addr_set(&eq->page_list[i], mapping, t);
@@ -517,7 +516,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
eq->eqn = mthca_alloc(&dev->eq_table.alloc);
if (eq->eqn == -1)
- goto err_out_free;
+ goto err_out_free_pages;
err = mthca_mr_alloc_phys(dev, dev->driver_pd.pd_num,
dma_list, PAGE_SHIFT, npages,
@@ -548,7 +547,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
eq_context->intr = intr;
eq_context->lkey = cpu_to_be32(eq->mr.ibmr.lkey);
- err = mthca_SW2HW_EQ(dev, eq_context, eq->eqn, &status);
+ err = mthca_SW2HW_EQ(dev, mailbox, eq->eqn, &status);
if (err) {
mthca_warn(dev, "SW2HW_EQ failed (%d)\n", err);
goto err_out_free_mr;
@@ -561,7 +560,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
}
kfree(dma_list);
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
eq->eqn_mask = swab32(1 << eq->eqn);
eq->cons_index = 0;
@@ -579,17 +578,19 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
err_out_free_eq:
mthca_free(&dev->eq_table.alloc, eq->eqn);
- err_out_free:
+ err_out_free_pages:
for (i = 0; i < npages; ++i)
if (eq->page_list[i].buf)
- pci_free_consistent(dev->pdev, PAGE_SIZE,
- eq->page_list[i].buf,
- pci_unmap_addr(&eq->page_list[i],
- mapping));
+ dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+ eq->page_list[i].buf,
+ pci_unmap_addr(&eq->page_list[i],
+ mapping));
+
+ mthca_free_mailbox(dev, mailbox);
+ err_out_free:
kfree(eq->page_list);
kfree(dma_list);
- kfree(mailbox);
err_out:
return err;
@@ -598,25 +599,22 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
static void mthca_free_eq(struct mthca_dev *dev,
struct mthca_eq *eq)
{
- void *mailbox = NULL;
+ struct mthca_mailbox *mailbox;
int err;
u8 status;
int npages = (eq->nent * MTHCA_EQ_ENTRY_SIZE + PAGE_SIZE - 1) /
PAGE_SIZE;
int i;
- mailbox = kmalloc(sizeof (struct mthca_eq_context) + MTHCA_CMD_MAILBOX_EXTRA,
- GFP_KERNEL);
- if (!mailbox)
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
return;
- err = mthca_HW2SW_EQ(dev, MAILBOX_ALIGN(mailbox),
- eq->eqn, &status);
+ err = mthca_HW2SW_EQ(dev, mailbox, eq->eqn, &status);
if (err)
mthca_warn(dev, "HW2SW_EQ failed (%d)\n", err);
if (status)
- mthca_warn(dev, "HW2SW_EQ returned status 0x%02x\n",
- status);
+ mthca_warn(dev, "HW2SW_EQ returned status 0x%02x\n", status);
dev->eq_table.arm_mask &= ~eq->eqn_mask;
@@ -625,7 +623,7 @@ static void mthca_free_eq(struct mthca_dev *dev,
for (i = 0; i < sizeof (struct mthca_eq_context) / 4; ++i) {
if (i % 4 == 0)
printk("[%02x] ", i * 4);
- printk(" %08x", be32_to_cpup(MAILBOX_ALIGN(mailbox) + i * 4));
+ printk(" %08x", be32_to_cpup(mailbox->buf + i * 4));
if ((i + 1) % 4 == 0)
printk("\n");
}
@@ -638,7 +636,7 @@ static void mthca_free_eq(struct mthca_dev *dev,
pci_unmap_addr(&eq->page_list[i], mapping));
kfree(eq->page_list);
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
}
static void mthca_free_irqs(struct mthca_dev *dev)
@@ -709,8 +707,7 @@ static int __devinit mthca_map_eq_regs(struct mthca_dev *dev)
if (mthca_map_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
dev->fw.arbel.eq_arm_base) + 4, 4,
&dev->eq_regs.arbel.eq_arm)) {
- mthca_err(dev, "Couldn't map interrupt clear register, "
- "aborting.\n");
+ mthca_err(dev, "Couldn't map EQ arm register, aborting.\n");
mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
dev->clr_base);
@@ -721,8 +718,7 @@ static int __devinit mthca_map_eq_regs(struct mthca_dev *dev)
dev->fw.arbel.eq_set_ci_base,
MTHCA_EQ_SET_CI_SIZE,
&dev->eq_regs.arbel.eq_set_ci_base)) {
- mthca_err(dev, "Couldn't map interrupt clear register, "
- "aborting.\n");
+ mthca_err(dev, "Couldn't map EQ CI register, aborting.\n");
mthca_unmap_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
dev->fw.arbel.eq_arm_base) + 4, 4,
dev->eq_regs.arbel.eq_arm);
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index d40590356df..09519b604c0 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -69,7 +70,7 @@ MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero");
#endif /* CONFIG_PCI_MSI */
static const char mthca_version[] __devinitdata =
- "ib_mthca: Mellanox InfiniBand HCA driver v"
+ DRV_NAME ": Mellanox InfiniBand HCA driver v"
DRV_VERSION " (" DRV_RELDATE ")\n";
static struct mthca_profile default_profile = {
@@ -927,13 +928,13 @@ static int __devinit mthca_init_one(struct pci_dev *pdev,
*/
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
pci_resource_len(pdev, 0) != 1 << 20) {
- dev_err(&pdev->dev, "Missing DCS, aborting.");
+ dev_err(&pdev->dev, "Missing DCS, aborting.\n");
err = -ENODEV;
goto err_disable_pdev;
}
if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM) ||
pci_resource_len(pdev, 2) != 1 << 23) {
- dev_err(&pdev->dev, "Missing UAR, aborting.");
+ dev_err(&pdev->dev, "Missing UAR, aborting.\n");
err = -ENODEV;
goto err_disable_pdev;
}
@@ -1004,25 +1005,18 @@ static int __devinit mthca_init_one(struct pci_dev *pdev,
!pci_enable_msi(pdev))
mdev->mthca_flags |= MTHCA_FLAG_MSI;
- sema_init(&mdev->cmd.hcr_sem, 1);
- sema_init(&mdev->cmd.poll_sem, 1);
- mdev->cmd.use_events = 0;
-
- mdev->hcr = ioremap(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, MTHCA_HCR_SIZE);
- if (!mdev->hcr) {
- mthca_err(mdev, "Couldn't map command register, "
- "aborting.\n");
- err = -ENOMEM;
+ if (mthca_cmd_init(mdev)) {
+ mthca_err(mdev, "Failed to init command interface, aborting.\n");
goto err_free_dev;
}
err = mthca_tune_pci(mdev);
if (err)
- goto err_iounmap;
+ goto err_cmd;
err = mthca_init_hca(mdev);
if (err)
- goto err_iounmap;
+ goto err_cmd;
if (mdev->fw_ver < mthca_hca_table[id->driver_data].latest_fw) {
mthca_warn(mdev, "HCA FW version %x.%x.%x is old (%x.%x.%x is current).\n",
@@ -1070,8 +1064,8 @@ err_cleanup:
err_close:
mthca_close_hca(mdev);
-err_iounmap:
- iounmap(mdev->hcr);
+err_cmd:
+ mthca_cmd_cleanup(mdev);
err_free_dev:
if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
@@ -1118,10 +1112,8 @@ static void __devexit mthca_remove_one(struct pci_dev *pdev)
iounmap(mdev->kar);
mthca_uar_free(mdev, &mdev->driver_uar);
mthca_cleanup_uar_table(mdev);
-
mthca_close_hca(mdev);
-
- iounmap(mdev->hcr);
+ mthca_cmd_cleanup(mdev);
if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
pci_disable_msix(pdev);
@@ -1163,7 +1155,7 @@ static struct pci_device_id mthca_pci_table[] = {
MODULE_DEVICE_TABLE(pci, mthca_pci_table);
static struct pci_driver mthca_driver = {
- .name = "ib_mthca",
+ .name = DRV_NAME,
.id_table = mthca_pci_table,
.probe = mthca_init_one,
.remove = __devexit_p(mthca_remove_one)
diff --git a/drivers/infiniband/hw/mthca/mthca_mcg.c b/drivers/infiniband/hw/mthca/mthca_mcg.c
index 70a6553a588..5be7d949dbf 100644
--- a/drivers/infiniband/hw/mthca/mthca_mcg.c
+++ b/drivers/infiniband/hw/mthca/mthca_mcg.c
@@ -66,22 +66,23 @@ static const u8 zero_gid[16]; /* automatically initialized to 0 */
* entry in hash chain and *mgm holds end of hash chain.
*/
static int find_mgm(struct mthca_dev *dev,
- u8 *gid, struct mthca_mgm *mgm,
+ u8 *gid, struct mthca_mailbox *mgm_mailbox,
u16 *hash, int *prev, int *index)
{
- void *mailbox;
+ struct mthca_mailbox *mailbox;
+ struct mthca_mgm *mgm = mgm_mailbox->buf;
u8 *mgid;
int err;
u8 status;
- mailbox = kmalloc(16 + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
- if (!mailbox)
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
return -ENOMEM;
- mgid = MAILBOX_ALIGN(mailbox);
+ mgid = mailbox->buf;
memcpy(mgid, gid, 16);
- err = mthca_MGID_HASH(dev, mgid, hash, &status);
+ err = mthca_MGID_HASH(dev, mailbox, hash, &status);
if (err)
goto out;
if (status) {
@@ -103,7 +104,7 @@ static int find_mgm(struct mthca_dev *dev,
*prev = -1;
do {
- err = mthca_READ_MGM(dev, *index, mgm, &status);
+ err = mthca_READ_MGM(dev, *index, mgm_mailbox, &status);
if (err)
goto out;
if (status) {
@@ -129,14 +130,14 @@ static int find_mgm(struct mthca_dev *dev,
*index = -1;
out:
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
{
struct mthca_dev *dev = to_mdev(ibqp->device);
- void *mailbox;
+ struct mthca_mailbox *mailbox;
struct mthca_mgm *mgm;
u16 hash;
int index, prev;
@@ -145,15 +146,15 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
int err;
u8 status;
- mailbox = kmalloc(sizeof *mgm + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
- if (!mailbox)
- return -ENOMEM;
- mgm = MAILBOX_ALIGN(mailbox);
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ mgm = mailbox->buf;
if (down_interruptible(&dev->mcg_table.sem))
return -EINTR;
- err = find_mgm(dev, gid->raw, mgm, &hash, &prev, &index);
+ err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
if (err)
goto out;
@@ -170,7 +171,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
goto out;
}
- err = mthca_READ_MGM(dev, index, mgm, &status);
+ err = mthca_READ_MGM(dev, index, mailbox, &status);
if (err)
goto out;
if (status) {
@@ -195,7 +196,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
goto out;
}
- err = mthca_WRITE_MGM(dev, index, mgm, &status);
+ err = mthca_WRITE_MGM(dev, index, mailbox, &status);
if (err)
goto out;
if (status) {
@@ -206,7 +207,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
if (!link)
goto out;
- err = mthca_READ_MGM(dev, prev, mgm, &status);
+ err = mthca_READ_MGM(dev, prev, mailbox, &status);
if (err)
goto out;
if (status) {
@@ -217,7 +218,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
mgm->next_gid_index = cpu_to_be32(index << 5);
- err = mthca_WRITE_MGM(dev, prev, mgm, &status);
+ err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
if (err)
goto out;
if (status) {
@@ -227,14 +228,14 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
out:
up(&dev->mcg_table.sem);
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
{
struct mthca_dev *dev = to_mdev(ibqp->device);
- void *mailbox;
+ struct mthca_mailbox *mailbox;
struct mthca_mgm *mgm;
u16 hash;
int prev, index;
@@ -242,15 +243,15 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
int err;
u8 status;
- mailbox = kmalloc(sizeof *mgm + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
- if (!mailbox)
- return -ENOMEM;
- mgm = MAILBOX_ALIGN(mailbox);
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ mgm = mailbox->buf;
if (down_interruptible(&dev->mcg_table.sem))
return -EINTR;
- err = find_mgm(dev, gid->raw, mgm, &hash, &prev, &index);
+ err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
if (err)
goto out;
@@ -285,7 +286,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
mgm->qp[loc] = mgm->qp[i - 1];
mgm->qp[i - 1] = 0;
- err = mthca_WRITE_MGM(dev, index, mgm, &status);
+ err = mthca_WRITE_MGM(dev, index, mailbox, &status);
if (err)
goto out;
if (status) {
@@ -304,7 +305,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
if (be32_to_cpu(mgm->next_gid_index) >> 5) {
err = mthca_READ_MGM(dev,
be32_to_cpu(mgm->next_gid_index) >> 5,
- mgm, &status);
+ mailbox, &status);
if (err)
goto out;
if (status) {
@@ -316,7 +317,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
} else
memset(mgm->gid, 0, 16);
- err = mthca_WRITE_MGM(dev, index, mgm, &status);
+ err = mthca_WRITE_MGM(dev, index, mailbox, &status);
if (err)
goto out;
if (status) {
@@ -327,7 +328,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
} else {
/* Remove entry from AMGM */
index = be32_to_cpu(mgm->next_gid_index) >> 5;
- err = mthca_READ_MGM(dev, prev, mgm, &status);
+ err = mthca_READ_MGM(dev, prev, mailbox, &status);
if (err)
goto out;
if (status) {
@@ -338,7 +339,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
mgm->next_gid_index = cpu_to_be32(index << 5);
- err = mthca_WRITE_MGM(dev, prev, mgm, &status);
+ err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
if (err)
goto out;
if (status) {
@@ -350,7 +351,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
out:
up(&dev->mcg_table.sem);
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
index 637b30e3559..6d3b05dd9e3 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -179,9 +179,14 @@ out:
void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int obj)
{
- int i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE;
+ int i;
u8 status;
+ if (!mthca_is_memfree(dev))
+ return;
+
+ i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE;
+
down(&table->mutex);
if (--table->icm[i]->refcount == 0) {
@@ -256,6 +261,9 @@ void mthca_table_put_range(struct mthca_dev *dev, struct mthca_icm_table *table,
{
int i;
+ if (!mthca_is_memfree(dev))
+ return;
+
for (i = start; i <= end; i += MTHCA_TABLE_CHUNK_SIZE / table->obj_size)
mthca_table_put(dev, table, i);
}
diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c
index 8960fc2306b..cbe50feaf68 100644
--- a/drivers/infiniband/hw/mthca/mthca_mr.c
+++ b/drivers/infiniband/hw/mthca/mthca_mr.c
@@ -40,6 +40,12 @@
#include "mthca_cmd.h"
#include "mthca_memfree.h"
+struct mthca_mtt {
+ struct mthca_buddy *buddy;
+ int order;
+ u32 first_seg;
+};
+
/*
* Must be packed because mtt_seg is 64 bits but only aligned to 32 bits.
*/
@@ -173,8 +179,8 @@ static void __devexit mthca_buddy_cleanup(struct mthca_buddy *buddy)
kfree(buddy->bits);
}
-static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order,
- struct mthca_buddy *buddy)
+static u32 mthca_alloc_mtt_range(struct mthca_dev *dev, int order,
+ struct mthca_buddy *buddy)
{
u32 seg = mthca_buddy_alloc(buddy, order);
@@ -191,14 +197,102 @@ static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order,
return seg;
}
-static void mthca_free_mtt(struct mthca_dev *dev, u32 seg, int order,
- struct mthca_buddy* buddy)
+static struct mthca_mtt *__mthca_alloc_mtt(struct mthca_dev *dev, int size,
+ struct mthca_buddy *buddy)
{
- mthca_buddy_free(buddy, seg, order);
+ struct mthca_mtt *mtt;
+ int i;
- if (mthca_is_memfree(dev))
- mthca_table_put_range(dev, dev->mr_table.mtt_table, seg,
- seg + (1 << order) - 1);
+ if (size <= 0)
+ return ERR_PTR(-EINVAL);
+
+ mtt = kmalloc(sizeof *mtt, GFP_KERNEL);
+ if (!mtt)
+ return ERR_PTR(-ENOMEM);
+
+ mtt->buddy = buddy;
+ mtt->order = 0;
+ for (i = MTHCA_MTT_SEG_SIZE / 8; i < size; i <<= 1)
+ ++mtt->order;
+
+ mtt->first_seg = mthca_alloc_mtt_range(dev, mtt->order, buddy);
+ if (mtt->first_seg == -1) {
+ kfree(mtt);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return mtt;
+}
+
+struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size)
+{
+ return __mthca_alloc_mtt(dev, size, &dev->mr_table.mtt_buddy);
+}
+
+void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt)
+{
+ if (!mtt)
+ return;
+
+ mthca_buddy_free(mtt->buddy, mtt->first_seg, mtt->order);
+
+ mthca_table_put_range(dev, dev->mr_table.mtt_table,
+ mtt->first_seg,
+ mtt->first_seg + (1 << mtt->order) - 1);
+
+ kfree(mtt);
+}
+
+int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
+ int start_index, u64 *buffer_list, int list_len)
+{
+ struct mthca_mailbox *mailbox;
+ u64 *mtt_entry;
+ int err = 0;
+ u8 status;
+ int i;
+
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ mtt_entry = mailbox->buf;
+
+ while (list_len > 0) {
+ mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base +
+ mtt->first_seg * MTHCA_MTT_SEG_SIZE +
+ start_index * 8);
+ mtt_entry[1] = 0;
+ for (i = 0; i < list_len && i < MTHCA_MAILBOX_SIZE / 8 - 2; ++i)
+ mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] |
+ MTHCA_MTT_FLAG_PRESENT);
+
+ /*
+ * If we have an odd number of entries to write, add
+ * one more dummy entry for firmware efficiency.
+ */
+ if (i & 1)
+ mtt_entry[i + 2] = 0;
+
+ err = mthca_WRITE_MTT(dev, mailbox, (i + 1) & ~1, &status);
+ if (err) {
+ mthca_warn(dev, "WRITE_MTT failed (%d)\n", err);
+ goto out;
+ }
+ if (status) {
+ mthca_warn(dev, "WRITE_MTT returned status 0x%02x\n",
+ status);
+ err = -EINVAL;
+ goto out;
+ }
+
+ list_len -= i;
+ start_index += i;
+ buffer_list += i;
+ }
+
+out:
+ mthca_free_mailbox(dev, mailbox);
+ return err;
}
static inline u32 tavor_hw_index_to_key(u32 ind)
@@ -237,91 +331,18 @@ static inline u32 key_to_hw_index(struct mthca_dev *dev, u32 key)
return tavor_key_to_hw_index(key);
}
-int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
- u32 access, struct mthca_mr *mr)
+int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
+ u64 iova, u64 total_size, u32 access, struct mthca_mr *mr)
{
- void *mailbox = NULL;
+ struct mthca_mailbox *mailbox;
struct mthca_mpt_entry *mpt_entry;
u32 key;
+ int i;
int err;
u8 status;
might_sleep();
- mr->order = -1;
- key = mthca_alloc(&dev->mr_table.mpt_alloc);
- if (key == -1)
- return -ENOMEM;
- mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);
-
- if (mthca_is_memfree(dev)) {
- err = mthca_table_get(dev, dev->mr_table.mpt_table, key);
- if (err)
- goto err_out_mpt_free;
- }
-
- mailbox = kmalloc(sizeof *mpt_entry + MTHCA_CMD_MAILBOX_EXTRA,
- GFP_KERNEL);
- if (!mailbox) {
- err = -ENOMEM;
- goto err_out_table;
- }
- mpt_entry = MAILBOX_ALIGN(mailbox);
-
- mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS |
- MTHCA_MPT_FLAG_MIO |
- MTHCA_MPT_FLAG_PHYSICAL |
- MTHCA_MPT_FLAG_REGION |
- access);
- mpt_entry->page_size = 0;
- mpt_entry->key = cpu_to_be32(key);
- mpt_entry->pd = cpu_to_be32(pd);
- mpt_entry->start = 0;
- mpt_entry->length = ~0ULL;
-
- memset(&mpt_entry->lkey, 0,
- sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
-
- err = mthca_SW2HW_MPT(dev, mpt_entry,
- key & (dev->limits.num_mpts - 1),
- &status);
- if (err) {
- mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
- goto err_out_table;
- } else if (status) {
- mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",
- status);
- err = -EINVAL;
- goto err_out_table;
- }
-
- kfree(mailbox);
- return err;
-
-err_out_table:
- if (mthca_is_memfree(dev))
- mthca_table_put(dev, dev->mr_table.mpt_table, key);
-
-err_out_mpt_free:
- mthca_free(&dev->mr_table.mpt_alloc, key);
- kfree(mailbox);
- return err;
-}
-
-int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
- u64 *buffer_list, int buffer_size_shift,
- int list_len, u64 iova, u64 total_size,
- u32 access, struct mthca_mr *mr)
-{
- void *mailbox;
- u64 *mtt_entry;
- struct mthca_mpt_entry *mpt_entry;
- u32 key;
- int err = -ENOMEM;
- u8 status;
- int i;
-
- might_sleep();
WARN_ON(buffer_size_shift >= 32);
key = mthca_alloc(&dev->mr_table.mpt_alloc);
@@ -335,75 +356,33 @@ int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
goto err_out_mpt_free;
}
- for (i = MTHCA_MTT_SEG_SIZE / 8, mr->order = 0;
- i < list_len;
- i <<= 1, ++mr->order)
- ; /* nothing */
-
- mr->first_seg = mthca_alloc_mtt(dev, mr->order,
- &dev->mr_table.mtt_buddy);
- if (mr->first_seg == -1)
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox)) {
+ err = PTR_ERR(mailbox);
goto err_out_table;
-
- /*
- * If list_len is odd, we add one more dummy entry for
- * firmware efficiency.
- */
- mailbox = kmalloc(max(sizeof *mpt_entry,
- (size_t) 8 * (list_len + (list_len & 1) + 2)) +
- MTHCA_CMD_MAILBOX_EXTRA,
- GFP_KERNEL);
- if (!mailbox)
- goto err_out_free_mtt;
-
- mtt_entry = MAILBOX_ALIGN(mailbox);
-
- mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base +
- mr->first_seg * MTHCA_MTT_SEG_SIZE);
- mtt_entry[1] = 0;
- for (i = 0; i < list_len; ++i)
- mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] |
- MTHCA_MTT_FLAG_PRESENT);
- if (list_len & 1) {
- mtt_entry[i + 2] = 0;
- ++list_len;
- }
-
- if (0) {
- mthca_dbg(dev, "Dumping MPT entry\n");
- for (i = 0; i < list_len + 2; ++i)
- printk(KERN_ERR "[%2d] %016llx\n",
- i, (unsigned long long) be64_to_cpu(mtt_entry[i]));
- }
-
- err = mthca_WRITE_MTT(dev, mtt_entry, list_len, &status);
- if (err) {
- mthca_warn(dev, "WRITE_MTT failed (%d)\n", err);
- goto err_out_mailbox_free;
- }
- if (status) {
- mthca_warn(dev, "WRITE_MTT returned status 0x%02x\n",
- status);
- err = -EINVAL;
- goto err_out_mailbox_free;
}
-
- mpt_entry = MAILBOX_ALIGN(mailbox);
+ mpt_entry = mailbox->buf;
mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS |
MTHCA_MPT_FLAG_MIO |
MTHCA_MPT_FLAG_REGION |
access);
+ if (!mr->mtt)
+ mpt_entry->flags |= cpu_to_be32(MTHCA_MPT_FLAG_PHYSICAL);
mpt_entry->page_size = cpu_to_be32(buffer_size_shift - 12);
mpt_entry->key = cpu_to_be32(key);
mpt_entry->pd = cpu_to_be32(pd);
mpt_entry->start = cpu_to_be64(iova);
mpt_entry->length = cpu_to_be64(total_size);
+
memset(&mpt_entry->lkey, 0,
sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
- mpt_entry->mtt_seg = cpu_to_be64(dev->mr_table.mtt_base +
- mr->first_seg * MTHCA_MTT_SEG_SIZE);
+
+ if (mr->mtt)
+ mpt_entry->mtt_seg =
+ cpu_to_be64(dev->mr_table.mtt_base +
+ mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE);
if (0) {
mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey);
@@ -416,45 +395,70 @@ int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
}
}
- err = mthca_SW2HW_MPT(dev, mpt_entry,
+ err = mthca_SW2HW_MPT(dev, mailbox,
key & (dev->limits.num_mpts - 1),
&status);
- if (err)
+ if (err) {
mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
- else if (status) {
+ goto err_out_mailbox;
+ } else if (status) {
mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",
status);
err = -EINVAL;
+ goto err_out_mailbox;
}
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
return err;
-err_out_mailbox_free:
- kfree(mailbox);
-
-err_out_free_mtt:
- mthca_free_mtt(dev, mr->first_seg, mr->order, &dev->mr_table.mtt_buddy);
+err_out_mailbox:
+ mthca_free_mailbox(dev, mailbox);
err_out_table:
- if (mthca_is_memfree(dev))
- mthca_table_put(dev, dev->mr_table.mpt_table, key);
+ mthca_table_put(dev, dev->mr_table.mpt_table, key);
err_out_mpt_free:
mthca_free(&dev->mr_table.mpt_alloc, key);
return err;
}
-/* Free mr or fmr */
-static void mthca_free_region(struct mthca_dev *dev, u32 lkey, int order,
- u32 first_seg, struct mthca_buddy *buddy)
+int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
+ u32 access, struct mthca_mr *mr)
{
- if (order >= 0)
- mthca_free_mtt(dev, first_seg, order, buddy);
+ mr->mtt = NULL;
+ return mthca_mr_alloc(dev, pd, 12, 0, ~0ULL, access, mr);
+}
- if (mthca_is_memfree(dev))
- mthca_table_put(dev, dev->mr_table.mpt_table,
- arbel_key_to_hw_index(lkey));
+int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
+ u64 *buffer_list, int buffer_size_shift,
+ int list_len, u64 iova, u64 total_size,
+ u32 access, struct mthca_mr *mr)
+{
+ int err;
+
+ mr->mtt = mthca_alloc_mtt(dev, list_len);
+ if (IS_ERR(mr->mtt))
+ return PTR_ERR(mr->mtt);
+
+ err = mthca_write_mtt(dev, mr->mtt, 0, buffer_list, list_len);
+ if (err) {
+ mthca_free_mtt(dev, mr->mtt);
+ return err;
+ }
+
+ err = mthca_mr_alloc(dev, pd, buffer_size_shift, iova,
+ total_size, access, mr);
+ if (err)
+ mthca_free_mtt(dev, mr->mtt);
+
+ return err;
+}
+
+/* Free mr or fmr */
+static void mthca_free_region(struct mthca_dev *dev, u32 lkey)
+{
+ mthca_table_put(dev, dev->mr_table.mpt_table,
+ arbel_key_to_hw_index(lkey));
mthca_free(&dev->mr_table.mpt_alloc, key_to_hw_index(dev, lkey));
}
@@ -476,15 +480,15 @@ void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr)
mthca_warn(dev, "HW2SW_MPT returned status 0x%02x\n",
status);
- mthca_free_region(dev, mr->ibmr.lkey, mr->order, mr->first_seg,
- &dev->mr_table.mtt_buddy);
+ mthca_free_region(dev, mr->ibmr.lkey);
+ mthca_free_mtt(dev, mr->mtt);
}
int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
u32 access, struct mthca_fmr *mr)
{
struct mthca_mpt_entry *mpt_entry;
- void *mailbox;
+ struct mthca_mailbox *mailbox;
u64 mtt_seg;
u32 key, idx;
u8 status;
@@ -522,31 +526,24 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base +
sizeof *(mr->mem.tavor.mpt) * idx;
- for (i = MTHCA_MTT_SEG_SIZE / 8, mr->order = 0;
- i < list_len;
- i <<= 1, ++mr->order)
- ; /* nothing */
-
- mr->first_seg = mthca_alloc_mtt(dev, mr->order,
- dev->mr_table.fmr_mtt_buddy);
- if (mr->first_seg == -1)
+ mr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy);
+ if (IS_ERR(mr->mtt))
goto err_out_table;
- mtt_seg = mr->first_seg * MTHCA_MTT_SEG_SIZE;
+ mtt_seg = mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE;
if (mthca_is_memfree(dev)) {
mr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table,
- mr->first_seg);
+ mr->mtt->first_seg);
BUG_ON(!mr->mem.arbel.mtts);
} else
mr->mem.tavor.mtts = dev->mr_table.tavor_fmr.mtt_base + mtt_seg;
- mailbox = kmalloc(sizeof *mpt_entry + MTHCA_CMD_MAILBOX_EXTRA,
- GFP_KERNEL);
- if (!mailbox)
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
goto err_out_free_mtt;
- mpt_entry = MAILBOX_ALIGN(mailbox);
+ mpt_entry = mailbox->buf;
mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS |
MTHCA_MPT_FLAG_MIO |
@@ -571,7 +568,7 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
}
}
- err = mthca_SW2HW_MPT(dev, mpt_entry,
+ err = mthca_SW2HW_MPT(dev, mailbox,
key & (dev->limits.num_mpts - 1),
&status);
if (err) {
@@ -585,19 +582,17 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
goto err_out_mailbox_free;
}
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
return 0;
err_out_mailbox_free:
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
err_out_free_mtt:
- mthca_free_mtt(dev, mr->first_seg, mr->order,
- dev->mr_table.fmr_mtt_buddy);
+ mthca_free_mtt(dev, mr->mtt);
err_out_table:
- if (mthca_is_memfree(dev))
- mthca_table_put(dev, dev->mr_table.mpt_table, key);
+ mthca_table_put(dev, dev->mr_table.mpt_table, key);
err_out_mpt_free:
mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);
@@ -609,8 +604,9 @@ int mthca_free_fmr(struct mthca_dev *dev, struct mthca_fmr *fmr)
if (fmr->maps)
return -EBUSY;
- mthca_free_region(dev, fmr->ibmr.lkey, fmr->order, fmr->first_seg,
- dev->mr_table.fmr_mtt_buddy);
+ mthca_free_region(dev, fmr->ibmr.lkey);
+ mthca_free_mtt(dev, fmr->mtt);
+
return 0;
}
@@ -826,7 +822,8 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev)
if (dev->limits.reserved_mtts) {
i = fls(dev->limits.reserved_mtts - 1);
- if (mthca_alloc_mtt(dev, i, dev->mr_table.fmr_mtt_buddy) == -1) {
+ if (mthca_alloc_mtt_range(dev, i,
+ dev->mr_table.fmr_mtt_buddy) == -1) {
mthca_warn(dev, "MTT table of order %d is too small.\n",
dev->mr_table.fmr_mtt_buddy->max_order);
err = -ENOMEM;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 159f4e6c312..0b5adfd9159 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -52,7 +53,7 @@ static int mthca_query_device(struct ib_device *ibdev,
if (!in_mad || !out_mad)
goto out;
- memset(props, 0, sizeof props);
+ memset(props, 0, sizeof *props);
props->fw_ver = mdev->fw_ver;
@@ -558,6 +559,7 @@ static struct ib_mr *mthca_reg_phys_mr(struct ib_pd *pd,
convert_access(acc), mr);
if (err) {
+ kfree(page_list);
kfree(mr);
return ERR_PTR(err);
}
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h
index 619710f95a8..4d976cccb1a 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.h
+++ b/drivers/infiniband/hw/mthca/mthca_provider.h
@@ -54,18 +54,18 @@ struct mthca_uar {
int index;
};
+struct mthca_mtt;
+
struct mthca_mr {
- struct ib_mr ibmr;
- int order;
- u32 first_seg;
+ struct ib_mr ibmr;
+ struct mthca_mtt *mtt;
};
struct mthca_fmr {
- struct ib_fmr ibmr;
+ struct ib_fmr ibmr;
struct ib_fmr_attr attr;
- int order;
- u32 first_seg;
- int maps;
+ struct mthca_mtt *mtt;
+ int maps;
union {
struct {
struct mthca_mpt_entry __iomem *mpt;
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index ca73bab11a0..163a8ef4186 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -357,6 +357,9 @@ static const struct {
[UD] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_QKEY),
+ [UC] = (IB_QP_PKEY_INDEX |
+ IB_QP_PORT |
+ IB_QP_ACCESS_FLAGS),
[RC] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_ACCESS_FLAGS),
@@ -378,6 +381,9 @@ static const struct {
[UD] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_QKEY),
+ [UC] = (IB_QP_PKEY_INDEX |
+ IB_QP_PORT |
+ IB_QP_ACCESS_FLAGS),
[RC] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_ACCESS_FLAGS),
@@ -388,6 +394,11 @@ static const struct {
[IB_QPS_RTR] = {
.trans = MTHCA_TRANS_INIT2RTR,
.req_param = {
+ [UC] = (IB_QP_AV |
+ IB_QP_PATH_MTU |
+ IB_QP_DEST_QPN |
+ IB_QP_RQ_PSN |
+ IB_QP_MAX_DEST_RD_ATOMIC),
[RC] = (IB_QP_AV |
IB_QP_PATH_MTU |
IB_QP_DEST_QPN |
@@ -398,6 +409,9 @@ static const struct {
.opt_param = {
[UD] = (IB_QP_PKEY_INDEX |
IB_QP_QKEY),
+ [UC] = (IB_QP_ALT_PATH |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_PKEY_INDEX),
[RC] = (IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_PKEY_INDEX),
@@ -413,6 +427,8 @@ static const struct {
.trans = MTHCA_TRANS_RTR2RTS,
.req_param = {
[UD] = IB_QP_SQ_PSN,
+ [UC] = (IB_QP_SQ_PSN |
+ IB_QP_MAX_QP_RD_ATOMIC),
[RC] = (IB_QP_TIMEOUT |
IB_QP_RETRY_CNT |
IB_QP_RNR_RETRY |
@@ -423,6 +439,11 @@ static const struct {
.opt_param = {
[UD] = (IB_QP_CUR_STATE |
IB_QP_QKEY),
+ [UC] = (IB_QP_CUR_STATE |
+ IB_QP_ALT_PATH |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_PKEY_INDEX |
+ IB_QP_PATH_MIG_STATE),
[RC] = (IB_QP_CUR_STATE |
IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
@@ -442,6 +463,9 @@ static const struct {
.opt_param = {
[UD] = (IB_QP_CUR_STATE |
IB_QP_QKEY),
+ [UC] = (IB_QP_ACCESS_FLAGS |
+ IB_QP_ALT_PATH |
+ IB_QP_PATH_MIG_STATE),
[RC] = (IB_QP_ACCESS_FLAGS |
IB_QP_ALT_PATH |
IB_QP_PATH_MIG_STATE |
@@ -462,6 +486,10 @@ static const struct {
.opt_param = {
[UD] = (IB_QP_CUR_STATE |
IB_QP_QKEY),
+ [UC] = (IB_QP_CUR_STATE |
+ IB_QP_ALT_PATH |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_PATH_MIG_STATE),
[RC] = (IB_QP_CUR_STATE |
IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
@@ -476,6 +504,14 @@ static const struct {
.opt_param = {
[UD] = (IB_QP_PKEY_INDEX |
IB_QP_QKEY),
+ [UC] = (IB_QP_AV |
+ IB_QP_MAX_QP_RD_ATOMIC |
+ IB_QP_MAX_DEST_RD_ATOMIC |
+ IB_QP_CUR_STATE |
+ IB_QP_ALT_PATH |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_PKEY_INDEX |
+ IB_QP_PATH_MIG_STATE),
[RC] = (IB_QP_AV |
IB_QP_TIMEOUT |
IB_QP_RETRY_CNT |
@@ -501,6 +537,7 @@ static const struct {
.opt_param = {
[UD] = (IB_QP_CUR_STATE |
IB_QP_QKEY),
+ [UC] = (IB_QP_CUR_STATE),
[RC] = (IB_QP_CUR_STATE |
IB_QP_MIN_RNR_TIMER),
[MLX] = (IB_QP_CUR_STATE |
@@ -552,7 +589,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
struct mthca_dev *dev = to_mdev(ibqp->device);
struct mthca_qp *qp = to_mqp(ibqp);
enum ib_qp_state cur_state, new_state;
- void *mailbox = NULL;
+ struct mthca_mailbox *mailbox;
struct mthca_qp_param *qp_param;
struct mthca_qp_context *qp_context;
u32 req_param, opt_param;
@@ -609,10 +646,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
return -EINVAL;
}
- mailbox = kmalloc(sizeof (*qp_param) + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
- if (!mailbox)
- return -ENOMEM;
- qp_param = MAILBOX_ALIGN(mailbox);
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ qp_param = mailbox->buf;
qp_context = &qp_param->context;
memset(qp_param, 0, sizeof *qp_param);
@@ -683,7 +720,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
if (attr_mask & IB_QP_AV) {
qp_context->pri_path.g_mylmc = attr->ah_attr.src_path_bits & 0x7f;
qp_context->pri_path.rlid = cpu_to_be16(attr->ah_attr.dlid);
- qp_context->pri_path.static_rate = (!!attr->ah_attr.static_rate) << 3;
+ qp_context->pri_path.static_rate = !!attr->ah_attr.static_rate;
if (attr->ah_attr.ah_flags & IB_AH_GRH) {
qp_context->pri_path.g_mylmc |= 1 << 7;
qp_context->pri_path.mgid_index = attr->ah_attr.grh.sgid_index;
@@ -724,9 +761,9 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RETRY_COUNT);
}
- if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
- qp_context->params1 |= cpu_to_be32(min(attr->max_dest_rd_atomic ?
- ffs(attr->max_dest_rd_atomic) - 1 : 0,
+ if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
+ qp_context->params1 |= cpu_to_be32(min(attr->max_rd_atomic ?
+ ffs(attr->max_rd_atomic) - 1 : 0,
7) << 21);
qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_SRA_MAX);
}
@@ -764,10 +801,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
qp->atomic_rd_en = attr->qp_access_flags;
}
- if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
+ if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
u8 rra_max;
- if (qp->resp_depth && !attr->max_rd_atomic) {
+ if (qp->resp_depth && !attr->max_dest_rd_atomic) {
/*
* Lowering our responder resources to zero.
* Turn off RDMA/atomics as responder.
@@ -778,7 +815,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
MTHCA_QP_OPTPAR_RAE);
}
- if (!qp->resp_depth && attr->max_rd_atomic) {
+ if (!qp->resp_depth && attr->max_dest_rd_atomic) {
/*
* Increasing our responder resources from
* zero. Turn on RDMA/atomics as appropriate.
@@ -799,7 +836,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
}
for (rra_max = 0;
- 1 << rra_max < attr->max_rd_atomic &&
+ 1 << rra_max < attr->max_dest_rd_atomic &&
rra_max < dev->qp_table.rdb_shift;
++rra_max)
; /* nothing */
@@ -807,7 +844,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
qp_context->params2 |= cpu_to_be32(rra_max << 21);
qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRA_MAX);
- qp->resp_depth = attr->max_rd_atomic;
+ qp->resp_depth = attr->max_dest_rd_atomic;
}
qp_context->params2 |= cpu_to_be32(MTHCA_QP_BIT_RSC);
@@ -835,7 +872,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
}
err = mthca_MODIFY_QP(dev, state_table[cur_state][new_state].trans,
- qp->qpn, 0, qp_param, 0, &status);
+ qp->qpn, 0, mailbox, 0, &status);
if (status) {
mthca_warn(dev, "modify QP %d returned status %02x.\n",
state_table[cur_state][new_state].trans, status);
@@ -845,7 +882,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
if (!err)
qp->state = new_state;
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
if (is_sqp(dev, qp))
store_attrs(to_msqp(qp), attr, attr_mask);
@@ -934,7 +971,8 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
mthca_dbg(dev, "Creating direct QP of size %d (shift %d)\n",
size, shift);
- qp->queue.direct.buf = pci_alloc_consistent(dev->pdev, size, &t);
+ qp->queue.direct.buf = dma_alloc_coherent(&dev->pdev->dev, size,
+ &t, GFP_KERNEL);
if (!qp->queue.direct.buf)
goto err_out;
@@ -973,7 +1011,8 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
for (i = 0; i < npages; ++i) {
qp->queue.page_list[i].buf =
- pci_alloc_consistent(dev->pdev, PAGE_SIZE, &t);
+ dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
+ &t, GFP_KERNEL);
if (!qp->queue.page_list[i].buf)
goto err_out_free;
@@ -996,16 +1035,15 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
err_out_free:
if (qp->is_direct) {
- pci_free_consistent(dev->pdev, size,
- qp->queue.direct.buf,
- pci_unmap_addr(&qp->queue.direct, mapping));
+ dma_free_coherent(&dev->pdev->dev, size, qp->queue.direct.buf,
+ pci_unmap_addr(&qp->queue.direct, mapping));
} else
for (i = 0; i < npages; ++i) {
if (qp->queue.page_list[i].buf)
- pci_free_consistent(dev->pdev, PAGE_SIZE,
- qp->queue.page_list[i].buf,
- pci_unmap_addr(&qp->queue.page_list[i],
- mapping));
+ dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+ qp->queue.page_list[i].buf,
+ pci_unmap_addr(&qp->queue.page_list[i],
+ mapping));
}
@@ -1073,11 +1111,12 @@ static void mthca_free_memfree(struct mthca_dev *dev,
if (mthca_is_memfree(dev)) {
mthca_free_db(dev, MTHCA_DB_TYPE_SQ, qp->sq.db_index);
mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
- mthca_table_put(dev, dev->qp_table.rdb_table,
- qp->qpn << dev->qp_table.rdb_shift);
- mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
- mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn);
}
+
+ mthca_table_put(dev, dev->qp_table.rdb_table,
+ qp->qpn << dev->qp_table.rdb_shift);
+ mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
+ mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn);
}
static void mthca_wq_init(struct mthca_wq* wq)
@@ -1529,6 +1568,26 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
break;
+ case UC:
+ switch (wr->opcode) {
+ case IB_WR_RDMA_WRITE:
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ ((struct mthca_raddr_seg *) wqe)->raddr =
+ cpu_to_be64(wr->wr.rdma.remote_addr);
+ ((struct mthca_raddr_seg *) wqe)->rkey =
+ cpu_to_be32(wr->wr.rdma.rkey);
+ ((struct mthca_raddr_seg *) wqe)->reserved = 0;
+ wqe += sizeof (struct mthca_raddr_seg);
+ size += sizeof (struct mthca_raddr_seg) / 16;
+ break;
+
+ default:
+ /* No extra segments required for sends */
+ break;
+ }
+
+ break;
+
case UD:
((struct mthca_tavor_ud_seg *) wqe)->lkey =
cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
@@ -1814,9 +1873,29 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
sizeof (struct mthca_atomic_seg);
break;
+ case IB_WR_RDMA_READ:
+ case IB_WR_RDMA_WRITE:
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ ((struct mthca_raddr_seg *) wqe)->raddr =
+ cpu_to_be64(wr->wr.rdma.remote_addr);
+ ((struct mthca_raddr_seg *) wqe)->rkey =
+ cpu_to_be32(wr->wr.rdma.rkey);
+ ((struct mthca_raddr_seg *) wqe)->reserved = 0;
+ wqe += sizeof (struct mthca_raddr_seg);
+ size += sizeof (struct mthca_raddr_seg) / 16;
+ break;
+
+ default:
+ /* No extra segments required for sends */
+ break;
+ }
+
+ break;
+
+ case UC:
+ switch (wr->opcode) {
case IB_WR_RDMA_WRITE:
case IB_WR_RDMA_WRITE_WITH_IMM:
- case IB_WR_RDMA_READ:
((struct mthca_raddr_seg *) wqe)->raddr =
cpu_to_be64(wr->wr.rdma.remote_addr);
((struct mthca_raddr_seg *) wqe)->rkey =
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 556264b4342..374f404e81d 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -21,6 +21,7 @@
#include <linux/smp_lock.h>
#include <linux/device.h>
#include <linux/devfs_fs_kernel.h>
+#include <linux/compat.h>
struct evdev {
int exist;
@@ -145,6 +146,41 @@ static int evdev_open(struct inode * inode, struct file * file)
return 0;
}
+#ifdef CONFIG_COMPAT
+struct input_event_compat {
+ struct compat_timeval time;
+ __u16 type;
+ __u16 code;
+ __s32 value;
+};
+
+#ifdef CONFIG_X86_64
+# define COMPAT_TEST test_thread_flag(TIF_IA32)
+#elif defined(CONFIG_IA64)
+# define COMPAT_TEST IS_IA32_PROCESS(ia64_task_regs(current))
+#elif defined(CONFIG_ARCH_S390)
+# define COMPAT_TEST test_thread_flag(TIF_31BIT)
+#else
+# define COMPAT_TEST test_thread_flag(TIF_32BIT)
+#endif
+
+static ssize_t evdev_write_compat(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
+{
+ struct evdev_list *list = file->private_data;
+ struct input_event_compat event;
+ int retval = 0;
+
+ while (retval < count) {
+ if (copy_from_user(&event, buffer + retval, sizeof(struct input_event_compat)))
+ return -EFAULT;
+ input_event(list->evdev->handle.dev, event.type, event.code, event.value);
+ retval += sizeof(struct input_event_compat);
+ }
+
+ return retval;
+}
+#endif
+
static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
{
struct evdev_list *list = file->private_data;
@@ -153,6 +189,11 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_
if (!list->evdev->exist) return -ENODEV;
+#ifdef CONFIG_COMPAT
+ if (COMPAT_TEST)
+ return evdev_write_compat(file, buffer, count, ppos);
+#endif
+
while (retval < count) {
if (copy_from_user(&event, buffer + retval, sizeof(struct input_event)))
@@ -164,11 +205,56 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_
return retval;
}
+#ifdef CONFIG_COMPAT
+static ssize_t evdev_read_compat(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
+{
+ struct evdev_list *list = file->private_data;
+ int retval;
+
+ if (count < sizeof(struct input_event_compat))
+ return -EINVAL;
+
+ if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
+ return -EAGAIN;
+
+ retval = wait_event_interruptible(list->evdev->wait,
+ list->head != list->tail || (!list->evdev->exist));
+
+ if (retval)
+ return retval;
+
+ if (!list->evdev->exist)
+ return -ENODEV;
+
+ while (list->head != list->tail && retval + sizeof(struct input_event_compat) <= count) {
+ struct input_event *event = (struct input_event *) list->buffer + list->tail;
+ struct input_event_compat event_compat;
+ event_compat.time.tv_sec = event->time.tv_sec;
+ event_compat.time.tv_usec = event->time.tv_usec;
+ event_compat.type = event->type;
+ event_compat.code = event->code;
+ event_compat.value = event->value;
+
+ if (copy_to_user(buffer + retval, &event_compat,
+ sizeof(struct input_event_compat))) return -EFAULT;
+ list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
+ retval += sizeof(struct input_event_compat);
+ }
+
+ return retval;
+}
+#endif
+
static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
{
struct evdev_list *list = file->private_data;
int retval;
+#ifdef CONFIG_COMPAT
+ if (COMPAT_TEST)
+ return evdev_read_compat(file, buffer, count, ppos);
+#endif
+
if (count < sizeof(struct input_event))
return -EINVAL;
@@ -186,7 +272,7 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count
while (list->head != list->tail && retval + sizeof(struct input_event) <= count) {
if (copy_to_user(buffer + retval, list->buffer + list->tail,
- sizeof(struct input_event))) return -EFAULT;
+ sizeof(struct input_event))) return -EFAULT;
list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
retval += sizeof(struct input_event);
}
@@ -203,7 +289,7 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
(list->evdev->exist ? 0 : (POLLHUP | POLLERR));
}
-static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct evdev_list *list = file->private_data;
struct evdev *evdev = list->evdev;
@@ -285,109 +371,267 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
default:
- if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
+ if (_IOC_TYPE(cmd) != 'E')
return -EINVAL;
- if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
-
- long *bits;
- int len;
-
- switch (_IOC_NR(cmd) & EV_MAX) {
- case 0: bits = dev->evbit; len = EV_MAX; break;
- case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
- case EV_REL: bits = dev->relbit; len = REL_MAX; break;
- case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
- case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
- case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
- case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
- case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
- default: return -EINVAL;
+ if (_IOC_DIR(cmd) == _IOC_READ) {
+
+ if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
+
+ long *bits;
+ int len;
+
+ switch (_IOC_NR(cmd) & EV_MAX) {
+ case 0: bits = dev->evbit; len = EV_MAX; break;
+ case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
+ case EV_REL: bits = dev->relbit; len = REL_MAX; break;
+ case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
+ case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
+ case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
+ case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
+ case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
+ default: return -EINVAL;
+ }
+ len = NBITS(len) * sizeof(long);
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, bits, len) ? -EFAULT : len;
}
- len = NBITS(len) * sizeof(long);
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, bits, len) ? -EFAULT : len;
- }
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
- int len;
- len = NBITS(KEY_MAX) * sizeof(long);
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, dev->key, len) ? -EFAULT : len;
- }
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
+ int len;
+ len = NBITS(KEY_MAX) * sizeof(long);
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->key, len) ? -EFAULT : len;
+ }
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) {
- int len;
- len = NBITS(LED_MAX) * sizeof(long);
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, dev->led, len) ? -EFAULT : len;
- }
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) {
+ int len;
+ len = NBITS(LED_MAX) * sizeof(long);
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->led, len) ? -EFAULT : len;
+ }
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) {
- int len;
- len = NBITS(SND_MAX) * sizeof(long);
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, dev->snd, len) ? -EFAULT : len;
- }
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) {
+ int len;
+ len = NBITS(SND_MAX) * sizeof(long);
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->snd, len) ? -EFAULT : len;
+ }
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
- int len;
- if (!dev->name) return -ENOENT;
- len = strlen(dev->name) + 1;
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, dev->name, len) ? -EFAULT : len;
- }
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
+ int len;
+ if (!dev->name) return -ENOENT;
+ len = strlen(dev->name) + 1;
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->name, len) ? -EFAULT : len;
+ }
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
+ int len;
+ if (!dev->phys) return -ENOENT;
+ len = strlen(dev->phys) + 1;
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
+ }
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
+ int len;
+ if (!dev->uniq) return -ENOENT;
+ len = strlen(dev->uniq) + 1;
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
+ }
+
+ if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+
+ int t = _IOC_NR(cmd) & ABS_MAX;
+
+ abs.value = dev->abs[t];
+ abs.minimum = dev->absmin[t];
+ abs.maximum = dev->absmax[t];
+ abs.fuzz = dev->absfuzz[t];
+ abs.flat = dev->absflat[t];
+
+ if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
+ return -EFAULT;
+
+ return 0;
+ }
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
- int len;
- if (!dev->phys) return -ENOENT;
- len = strlen(dev->phys) + 1;
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
}
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
- int len;
- if (!dev->uniq) return -ENOENT;
- len = strlen(dev->uniq) + 1;
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
+ if (_IOC_DIR(cmd) == _IOC_WRITE) {
+
+ if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
+
+ int t = _IOC_NR(cmd) & ABS_MAX;
+
+ if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
+ return -EFAULT;
+
+ dev->abs[t] = abs.value;
+ dev->absmin[t] = abs.minimum;
+ dev->absmax[t] = abs.maximum;
+ dev->absfuzz[t] = abs.fuzz;
+ dev->absflat[t] = abs.flat;
+
+ return 0;
+ }
}
+ }
+ return -EINVAL;
+}
- if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+#ifdef CONFIG_COMPAT
+
+#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8)
+#define NBITS_COMPAT(x) ((((x)-1)/BITS_PER_LONG_COMPAT)+1)
+#define OFF_COMPAT(x) ((x)%BITS_PER_LONG_COMPAT)
+#define BIT_COMPAT(x) (1UL<<OFF_COMPAT(x))
+#define LONG_COMPAT(x) ((x)/BITS_PER_LONG_COMPAT)
+#define test_bit_compat(bit, array) ((array[LONG_COMPAT(bit)] >> OFF_COMPAT(bit)) & 1)
+
+#ifdef __BIG_ENDIAN
+#define bit_to_user(bit, max) \
+do { \
+ int i; \
+ int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \
+ for (i = 0; i < len / sizeof(compat_long_t); i++) \
+ if (copy_to_user((compat_long_t*) p + i, \
+ (compat_long_t*) (bit) + i + 1 - ((i % 2) << 1), \
+ sizeof(compat_long_t))) \
+ return -EFAULT; \
+ return len; \
+} while (0)
+#else
+#define bit_to_user(bit, max) \
+do { \
+ int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \
+ return copy_to_user(p, (bit), len) ? -EFAULT : len; \
+} while (0)
+#endif
+
+static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct evdev_list *list = file->private_data;
+ struct evdev *evdev = list->evdev;
+ struct input_dev *dev = evdev->handle.dev;
+ struct input_absinfo abs;
+ void __user *p = compat_ptr(arg);
- int t = _IOC_NR(cmd) & ABS_MAX;
+ if (!evdev->exist) return -ENODEV;
- abs.value = dev->abs[t];
- abs.minimum = dev->absmin[t];
- abs.maximum = dev->absmax[t];
- abs.fuzz = dev->absfuzz[t];
- abs.flat = dev->absflat[t];
+ switch (cmd) {
- if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
- return -EFAULT;
+ case EVIOCGVERSION:
+ case EVIOCGID:
+ case EVIOCGKEYCODE:
+ case EVIOCSKEYCODE:
+ case EVIOCSFF:
+ case EVIOCRMFF:
+ case EVIOCGEFFECTS:
+ case EVIOCGRAB:
+ return evdev_ioctl(file, cmd, (unsigned long) p);
- return 0;
+ default:
+
+ if (_IOC_TYPE(cmd) != 'E')
+ return -EINVAL;
+
+ if (_IOC_DIR(cmd) == _IOC_READ) {
+
+ if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
+ long *bits;
+ int max;
+
+ switch (_IOC_NR(cmd) & EV_MAX) {
+ case 0: bits = dev->evbit; max = EV_MAX; break;
+ case EV_KEY: bits = dev->keybit; max = KEY_MAX; break;
+ case EV_REL: bits = dev->relbit; max = REL_MAX; break;
+ case EV_ABS: bits = dev->absbit; max = ABS_MAX; break;
+ case EV_MSC: bits = dev->mscbit; max = MSC_MAX; break;
+ case EV_LED: bits = dev->ledbit; max = LED_MAX; break;
+ case EV_SND: bits = dev->sndbit; max = SND_MAX; break;
+ case EV_FF: bits = dev->ffbit; max = FF_MAX; break;
+ default: return -EINVAL;
+ }
+ bit_to_user(bits, max);
+ }
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
+ bit_to_user(dev->key, KEY_MAX);
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
+ bit_to_user(dev->led, LED_MAX);
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
+ bit_to_user(dev->snd, SND_MAX);
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
+ int len;
+ if (!dev->name) return -ENOENT;
+ len = strlen(dev->name) + 1;
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->name, len) ? -EFAULT : len;
+ }
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
+ int len;
+ if (!dev->phys) return -ENOENT;
+ len = strlen(dev->phys) + 1;
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
+ }
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
+ int len;
+ if (!dev->uniq) return -ENOENT;
+ len = strlen(dev->uniq) + 1;
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
+ }
+
+ if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+
+ int t = _IOC_NR(cmd) & ABS_MAX;
+
+ abs.value = dev->abs[t];
+ abs.minimum = dev->absmin[t];
+ abs.maximum = dev->absmax[t];
+ abs.fuzz = dev->absfuzz[t];
+ abs.flat = dev->absflat[t];
+
+ if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
+ return -EFAULT;
+
+ return 0;
+ }
}
- if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
+ if (_IOC_DIR(cmd) == _IOC_WRITE) {
- int t = _IOC_NR(cmd) & ABS_MAX;
+ if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
- if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
- return -EFAULT;
+ int t = _IOC_NR(cmd) & ABS_MAX;
- dev->abs[t] = abs.value;
- dev->absmin[t] = abs.minimum;
- dev->absmax[t] = abs.maximum;
- dev->absfuzz[t] = abs.fuzz;
- dev->absflat[t] = abs.flat;
+ if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
+ return -EFAULT;
- return 0;
+ dev->abs[t] = abs.value;
+ dev->absmin[t] = abs.minimum;
+ dev->absmax[t] = abs.maximum;
+ dev->absfuzz[t] = abs.fuzz;
+ dev->absflat[t] = abs.flat;
+
+ return 0;
+ }
}
}
return -EINVAL;
}
+#endif
static struct file_operations evdev_fops = {
.owner = THIS_MODULE,
@@ -396,7 +640,10 @@ static struct file_operations evdev_fops = {
.poll = evdev_poll,
.open = evdev_open,
.release = evdev_release,
- .ioctl = evdev_ioctl,
+ .unlocked_ioctl = evdev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = evdev_ioctl_compat,
+#endif
.fasync = evdev_fasync,
.flush = evdev_flush
};
diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig
index 1d93f509290..7524bd7d8b8 100644
--- a/drivers/input/gameport/Kconfig
+++ b/drivers/input/gameport/Kconfig
@@ -49,22 +49,8 @@ config GAMEPORT_EMU10K1
To compile this driver as a module, choose M here: the
module will be called emu10k1-gp.
-config GAMEPORT_VORTEX
- tristate "Aureal Vortex, Vortex 2 gameport support"
- depends on PCI
- help
- Say Y here if you have an Aureal Vortex 1 or 2 card and want
- to use its gameport.
-
- To compile this driver as a module, choose M here: the
- module will be called vortex.
-
config GAMEPORT_FM801
tristate "ForteMedia FM801 gameport support"
depends on PCI
-config GAMEPORT_CS461X
- tristate "Crystal SoundFusion gameport support"
- depends on PCI
-
endif
diff --git a/drivers/input/gameport/Makefile b/drivers/input/gameport/Makefile
index 5367b4267ad..b6f6097bd8c 100644
--- a/drivers/input/gameport/Makefile
+++ b/drivers/input/gameport/Makefile
@@ -5,9 +5,7 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_GAMEPORT) += gameport.o
-obj-$(CONFIG_GAMEPORT_CS461X) += cs461x.o
obj-$(CONFIG_GAMEPORT_EMU10K1) += emu10k1-gp.o
obj-$(CONFIG_GAMEPORT_FM801) += fm801-gp.o
obj-$(CONFIG_GAMEPORT_L4) += lightning.o
obj-$(CONFIG_GAMEPORT_NS558) += ns558.o
-obj-$(CONFIG_GAMEPORT_VORTEX) += vortex.o
diff --git a/drivers/input/gameport/cs461x.c b/drivers/input/gameport/cs461x.c
deleted file mode 100644
index d4013ff9862..00000000000
--- a/drivers/input/gameport/cs461x.c
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- The all defines and part of code (such as cs461x_*) are
- contributed from ALSA 0.5.8 sources.
- See http://www.alsa-project.org/ for sources
-
- Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
-*/
-
-#include <asm/io.h>
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-
-MODULE_AUTHOR("Victor Krapivin");
-MODULE_LICENSE("GPL");
-
-/*
- These options are experimental
-
-#define CS461X_FULL_MAP
-*/
-
-
-#ifndef PCI_VENDOR_ID_CIRRUS
-#define PCI_VENDOR_ID_CIRRUS 0x1013
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4610
-#define PCI_DEVICE_ID_CIRRUS_4610 0x6001
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4612
-#define PCI_DEVICE_ID_CIRRUS_4612 0x6003
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4615
-#define PCI_DEVICE_ID_CIRRUS_4615 0x6004
-#endif
-
-/* Registers */
-
-#define BA0_JSPT 0x00000480
-#define BA0_JSCTL 0x00000484
-#define BA0_JSC1 0x00000488
-#define BA0_JSC2 0x0000048C
-#define BA0_JSIO 0x000004A0
-
-/* Bits for JSPT */
-
-#define JSPT_CAX 0x00000001
-#define JSPT_CAY 0x00000002
-#define JSPT_CBX 0x00000004
-#define JSPT_CBY 0x00000008
-#define JSPT_BA1 0x00000010
-#define JSPT_BA2 0x00000020
-#define JSPT_BB1 0x00000040
-#define JSPT_BB2 0x00000080
-
-/* Bits for JSCTL */
-
-#define JSCTL_SP_MASK 0x00000003
-#define JSCTL_SP_SLOW 0x00000000
-#define JSCTL_SP_MEDIUM_SLOW 0x00000001
-#define JSCTL_SP_MEDIUM_FAST 0x00000002
-#define JSCTL_SP_FAST 0x00000003
-#define JSCTL_ARE 0x00000004
-
-/* Data register pairs masks */
-
-#define JSC1_Y1V_MASK 0x0000FFFF
-#define JSC1_X1V_MASK 0xFFFF0000
-#define JSC1_Y1V_SHIFT 0
-#define JSC1_X1V_SHIFT 16
-#define JSC2_Y2V_MASK 0x0000FFFF
-#define JSC2_X2V_MASK 0xFFFF0000
-#define JSC2_Y2V_SHIFT 0
-#define JSC2_X2V_SHIFT 16
-
-/* JS GPIO */
-
-#define JSIO_DAX 0x00000001
-#define JSIO_DAY 0x00000002
-#define JSIO_DBX 0x00000004
-#define JSIO_DBY 0x00000008
-#define JSIO_AXOE 0x00000010
-#define JSIO_AYOE 0x00000020
-#define JSIO_BXOE 0x00000040
-#define JSIO_BYOE 0x00000080
-
-/*
- The card initialization code is obfuscated; the module cs461x
- need to be loaded after ALSA modules initialized and something
- played on the CS 4610 chip (see sources for details of CS4610
- initialization code from ALSA)
-*/
-
-/* Card specific definitions */
-
-#define CS461X_BA0_SIZE 0x2000
-#define CS461X_BA1_DATA0_SIZE 0x3000
-#define CS461X_BA1_DATA1_SIZE 0x3800
-#define CS461X_BA1_PRG_SIZE 0x7000
-#define CS461X_BA1_REG_SIZE 0x0100
-
-#define BA1_SP_DMEM0 0x00000000
-#define BA1_SP_DMEM1 0x00010000
-#define BA1_SP_PMEM 0x00020000
-#define BA1_SP_REG 0x00030000
-
-#define BA1_DWORD_SIZE (13 * 1024 + 512)
-#define BA1_MEMORY_COUNT 3
-
-/*
- Only one CS461x card is still suppoted; the code requires
- redesign to avoid this limitatuion.
-*/
-
-static unsigned long ba0_addr;
-static unsigned int __iomem *ba0;
-
-#ifdef CS461X_FULL_MAP
-static unsigned long ba1_addr;
-static union ba1_t {
- struct {
- unsigned int __iomem *data0;
- unsigned int __iomem *data1;
- unsigned int __iomem *pmem;
- unsigned int __iomem *reg;
- } name;
- unsigned int __iomem *idx[4];
-} ba1;
-
-static void cs461x_poke(unsigned long reg, unsigned int val)
-{
- writel(val, &ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
-}
-
-static unsigned int cs461x_peek(unsigned long reg)
-{
- return readl(&ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
-}
-
-#endif
-
-static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
-{
- writel(val, &ba0[reg >> 2]);
-}
-
-static unsigned int cs461x_peekBA0(unsigned long reg)
-{
- return readl(&ba0[reg >> 2]);
-}
-
-static int cs461x_free(struct pci_dev *pdev)
-{
- struct gameport *port = pci_get_drvdata(pdev);
-
- if (port)
- gameport_unregister_port(port);
-
- if (ba0) iounmap(ba0);
-#ifdef CS461X_FULL_MAP
- if (ba1.name.data0) iounmap(ba1.name.data0);
- if (ba1.name.data1) iounmap(ba1.name.data1);
- if (ba1.name.pmem) iounmap(ba1.name.pmem);
- if (ba1.name.reg) iounmap(ba1.name.reg);
-#endif
- return 0;
-}
-
-static void cs461x_gameport_trigger(struct gameport *gameport)
-{
- cs461x_pokeBA0(BA0_JSPT, 0xFF); //outb(gameport->io, 0xFF);
-}
-
-static unsigned char cs461x_gameport_read(struct gameport *gameport)
-{
- return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
-}
-
-static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
- unsigned js1, js2, jst;
-
- js1 = cs461x_peekBA0(BA0_JSC1);
- js2 = cs461x_peekBA0(BA0_JSC2);
- jst = cs461x_peekBA0(BA0_JSPT);
-
- *buttons = (~jst >> 4) & 0x0F;
-
- axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
- axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
- axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
- axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
-
- for(jst=0;jst<4;++jst)
- if(axes[jst]==0xFFFF) axes[jst] = -1;
- return 0;
-}
-
-static int cs461x_gameport_open(struct gameport *gameport, int mode)
-{
- switch (mode) {
- case GAMEPORT_MODE_COOKED:
- case GAMEPORT_MODE_RAW:
- return 0;
- default:
- return -1;
- }
- return 0;
-}
-
-static struct pci_device_id cs461x_pci_tbl[] = {
- { PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
- { PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
- { PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
- { 0, }
-};
-MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
-
-static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- int rc;
- struct gameport* port;
-
- rc = pci_enable_device(pdev);
- if (rc) {
- printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
- pdev->bus->number, pdev->devfn, rc);
- return rc;
- }
-
- ba0_addr = pci_resource_start(pdev, 0);
-#ifdef CS461X_FULL_MAP
- ba1_addr = pci_resource_start(pdev, 1);
-#endif
- if (ba0_addr == 0 || ba0_addr == ~0
-#ifdef CS461X_FULL_MAP
- || ba1_addr == 0 || ba1_addr == ~0
-#endif
- ) {
- printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
-#ifdef CS461X_FULL_MAP
- printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
-#endif
- cs461x_free(pdev);
- return -ENOMEM;
- }
-
- ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
-#ifdef CS461X_FULL_MAP
- ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
- ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
- ba1.name.pmem = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
- ba1.name.reg = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
-
- if (ba0 == NULL || ba1.name.data0 == NULL ||
- ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
- ba1.name.reg == NULL) {
- cs461x_free(pdev);
- return -ENOMEM;
- }
-#else
- if (ba0 == NULL) {
- cs461x_free(pdev);
- return -ENOMEM;
- }
-#endif
-
- if (!(port = gameport_allocate_port())) {
- printk(KERN_ERR "cs461x: Memory allocation failed\n");
- cs461x_free(pdev);
- return -ENOMEM;
- }
-
- pci_set_drvdata(pdev, port);
-
- port->open = cs461x_gameport_open;
- port->trigger = cs461x_gameport_trigger;
- port->read = cs461x_gameport_read;
- port->cooked_read = cs461x_gameport_cooked_read;
-
- gameport_set_name(port, "CS416x");
- gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
- port->dev.parent = &pdev->dev;
-
- cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
- cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
-
- gameport_register_port(port);
-
- return 0;
-}
-
-static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
-{
- cs461x_free(pdev);
-}
-
-static struct pci_driver cs461x_pci_driver = {
- .name = "CS461x_gameport",
- .id_table = cs461x_pci_tbl,
- .probe = cs461x_pci_probe,
- .remove = __devexit_p(cs461x_pci_remove),
-};
-
-static int __init cs461x_init(void)
-{
- return pci_register_driver(&cs461x_pci_driver);
-}
-
-static void __exit cs461x_exit(void)
-{
- pci_unregister_driver(&cs461x_pci_driver);
-}
-
-module_init(cs461x_init);
-module_exit(cs461x_exit);
-
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index c77a82e4605..3e72c9b1461 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -17,11 +17,10 @@
#include <linux/init.h>
#include <linux/gameport.h>
#include <linux/wait.h>
-#include <linux/completion.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/kthread.h>
/*#include <asm/io.h>*/
@@ -238,8 +237,7 @@ struct gameport_event {
static DEFINE_SPINLOCK(gameport_event_lock); /* protects gameport_event_list */
static LIST_HEAD(gameport_event_list);
static DECLARE_WAIT_QUEUE_HEAD(gameport_wait);
-static DECLARE_COMPLETION(gameport_exited);
-static int gameport_pid;
+static struct task_struct *gameport_task;
static void gameport_queue_event(void *object, struct module *owner,
enum gameport_event_type event_type)
@@ -250,12 +248,12 @@ static void gameport_queue_event(void *object, struct module *owner,
spin_lock_irqsave(&gameport_event_lock, flags);
/*
- * Scan event list for the other events for the same gameport port,
+ * Scan event list for the other events for the same gameport port,
* starting with the most recent one. If event is the same we
* do not need add new one. If event is of different type we
* need to add this event and should not look further because
* we need to preseve sequence of distinct events.
- */
+ */
list_for_each_entry_reverse(event, &gameport_event_list, node) {
if (event->object == object) {
if (event->type == event_type)
@@ -432,20 +430,15 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent)
static int gameport_thread(void *nothing)
{
- lock_kernel();
- daemonize("kgameportd");
- allow_signal(SIGTERM);
-
do {
gameport_handle_events();
- wait_event_interruptible(gameport_wait, !list_empty(&gameport_event_list));
+ wait_event_interruptible(gameport_wait,
+ kthread_should_stop() || !list_empty(&gameport_event_list));
try_to_freeze();
- } while (!signal_pending(current));
+ } while (!kthread_should_stop());
printk(KERN_DEBUG "gameport: kgameportd exiting\n");
-
- unlock_kernel();
- complete_and_exit(&gameport_exited, 0);
+ return 0;
}
@@ -773,9 +766,10 @@ void gameport_close(struct gameport *gameport)
static int __init gameport_init(void)
{
- if (!(gameport_pid = kernel_thread(gameport_thread, NULL, CLONE_KERNEL))) {
+ gameport_task = kthread_run(gameport_thread, NULL, "kgameportd");
+ if (IS_ERR(gameport_task)) {
printk(KERN_ERR "gameport: Failed to start kgameportd\n");
- return -1;
+ return PTR_ERR(gameport_task);
}
gameport_bus.dev_attrs = gameport_device_attrs;
@@ -789,8 +783,7 @@ static int __init gameport_init(void)
static void __exit gameport_exit(void)
{
bus_unregister(&gameport_bus);
- kill_proc(gameport_pid, SIGTERM, 1);
- wait_for_completion(&gameport_exited);
+ kthread_stop(gameport_task);
}
module_init(gameport_init);
diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
index 7c5c6318eeb..1ab5f2dc8a2 100644
--- a/drivers/input/gameport/ns558.c
+++ b/drivers/input/gameport/ns558.c
@@ -258,18 +258,18 @@ static int __init ns558_init(void)
{
int i = 0;
+ if (pnp_register_driver(&ns558_pnp_driver) >= 0)
+ pnp_registered = 1;
+
/*
- * Probe ISA ports first so that PnP gets to choose free port addresses
- * not occupied by the ISA ports.
+ * Probe ISA ports after PnP, so that PnP ports that are already
+ * enabled get detected as PnP. This may be suboptimal in multi-device
+ * configurations, but saves hassle with simple setups.
*/
while (ns558_isa_portlist[i])
ns558_isa_probe(ns558_isa_portlist[i++]);
- if (pnp_register_driver(&ns558_pnp_driver) >= 0)
- pnp_registered = 1;
-
-
return (list_empty(&ns558_list) && !pnp_registered) ? -ENODEV : 0;
}
diff --git a/drivers/input/gameport/vortex.c b/drivers/input/gameport/vortex.c
deleted file mode 100644
index 36b0309c8bf..00000000000
--- a/drivers/input/gameport/vortex.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * $Id: vortex.c,v 1.5 2002/07/01 15:39:30 vojtech Exp $
- *
- * Copyright (c) 2000-2001 Vojtech Pavlik
- *
- * Based on the work of:
- * Raymond Ingles
- */
-
-/*
- * Trident 4DWave and Aureal Vortex gameport driver for Linux
- */
-
-/*
- * 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
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/gameport.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Aureal Vortex and Vortex2 gameport driver");
-MODULE_LICENSE("GPL");
-
-#define VORTEX_GCR 0x0c /* Gameport control register */
-#define VORTEX_LEG 0x08 /* Legacy port location */
-#define VORTEX_AXD 0x10 /* Axes start */
-#define VORTEX_DATA_WAIT 20 /* 20 ms */
-
-struct vortex {
- struct gameport *gameport;
- struct pci_dev *dev;
- unsigned char __iomem *base;
- unsigned char __iomem *io;
-};
-
-static unsigned char vortex_read(struct gameport *gameport)
-{
- struct vortex *vortex = gameport->port_data;
- return readb(vortex->io + VORTEX_LEG);
-}
-
-static void vortex_trigger(struct gameport *gameport)
-{
- struct vortex *vortex = gameport->port_data;
- writeb(0xff, vortex->io + VORTEX_LEG);
-}
-
-static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
- struct vortex *vortex = gameport->port_data;
- int i;
-
- *buttons = (~readb(vortex->base + VORTEX_LEG) >> 4) & 0xf;
-
- for (i = 0; i < 4; i++) {
- axes[i] = readw(vortex->io + VORTEX_AXD + i * sizeof(u32));
- if (axes[i] == 0x1fff) axes[i] = -1;
- }
-
- return 0;
-}
-
-static int vortex_open(struct gameport *gameport, int mode)
-{
- struct vortex *vortex = gameport->port_data;
-
- switch (mode) {
- case GAMEPORT_MODE_COOKED:
- writeb(0x40, vortex->io + VORTEX_GCR);
- msleep(VORTEX_DATA_WAIT);
- return 0;
- case GAMEPORT_MODE_RAW:
- writeb(0x00, vortex->io + VORTEX_GCR);
- return 0;
- default:
- return -1;
- }
-
- return 0;
-}
-
-static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
- struct vortex *vortex;
- struct gameport *port;
- int i;
-
- vortex = kcalloc(1, sizeof(struct vortex), GFP_KERNEL);
- port = gameport_allocate_port();
- if (!vortex || !port) {
- printk(KERN_ERR "vortex: Memory allocation failed.\n");
- kfree(vortex);
- gameport_free_port(port);
- return -ENOMEM;
- }
-
- for (i = 0; i < 6; i++)
- if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
- break;
-
- pci_enable_device(dev);
-
- vortex->dev = dev;
- vortex->gameport = port;
- vortex->base = ioremap(pci_resource_start(vortex->dev, i),
- pci_resource_len(vortex->dev, i));
- vortex->io = vortex->base + id->driver_data;
-
- pci_set_drvdata(dev, vortex);
-
- port->port_data = vortex;
- port->fuzz = 64;
-
- gameport_set_name(port, "AU88x0");
- gameport_set_phys(port, "pci%s/gameport0", pci_name(dev));
- port->dev.parent = &dev->dev;
- port->read = vortex_read;
- port->trigger = vortex_trigger;
- port->cooked_read = vortex_cooked_read;
- port->open = vortex_open;
-
- gameport_register_port(port);
-
- return 0;
-}
-
-static void __devexit vortex_remove(struct pci_dev *dev)
-{
- struct vortex *vortex = pci_get_drvdata(dev);
-
- gameport_unregister_port(vortex->gameport);
- iounmap(vortex->base);
- kfree(vortex);
-}
-
-static struct pci_device_id vortex_id_table[] = {
- { 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 },
- { 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 },
- { 0 }
-};
-
-static struct pci_driver vortex_driver = {
- .name = "vortex_gameport",
- .id_table = vortex_id_table,
- .probe = vortex_probe,
- .remove = __devexit_p(vortex_remove),
-};
-
-static int __init vortex_init(void)
-{
- return pci_register_driver(&vortex_driver);
-}
-
-static void __exit vortex_exit(void)
-{
- pci_unregister_driver(&vortex_driver);
-}
-
-module_init(vortex_init);
-module_exit(vortex_exit);
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 83c77c990dd..7c4b4d37b3e 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -219,10 +219,24 @@ void input_release_device(struct input_handle *handle)
int input_open_device(struct input_handle *handle)
{
+ struct input_dev *dev = handle->dev;
+ int err;
+
+ err = down_interruptible(&dev->sem);
+ if (err)
+ return err;
+
handle->open++;
- if (handle->dev->open)
- return handle->dev->open(handle->dev);
- return 0;
+
+ if (!dev->users++ && dev->open)
+ err = dev->open(dev);
+
+ if (err)
+ handle->open--;
+
+ up(&dev->sem);
+
+ return err;
}
int input_flush_device(struct input_handle* handle, struct file* file)
@@ -235,10 +249,17 @@ int input_flush_device(struct input_handle* handle, struct file* file)
void input_close_device(struct input_handle *handle)
{
+ struct input_dev *dev = handle->dev;
+
input_release_device(handle);
- if (handle->dev->close)
- handle->dev->close(handle->dev);
+
+ down(&dev->sem);
+
+ if (!--dev->users && dev->close)
+ dev->close(dev);
handle->open--;
+
+ up(&dev->sem);
}
static void input_link_handle(struct input_handle *handle)
@@ -415,6 +436,8 @@ void input_register_device(struct input_dev *dev)
set_bit(EV_SYN, dev->evbit);
+ init_MUTEX(&dev->sem);
+
/*
* If delay and period are pre-set by the driver, then autorepeating
* is handled by the driver itself and we don't do it in input.c.
@@ -674,6 +697,8 @@ static int input_handlers_read(char *buf, char **start, off_t pos, int count, in
return (count > cnt) ? cnt : count;
}
+static struct file_operations input_fileops;
+
static int __init input_proc_init(void)
{
struct proc_dir_entry *entry;
@@ -688,6 +713,8 @@ static int __init input_proc_init(void)
return -ENOMEM;
}
entry->owner = THIS_MODULE;
+ input_fileops = *entry->proc_fops;
+ entry->proc_fops = &input_fileops;
entry->proc_fops->poll = input_devices_poll;
entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL);
if (entry == NULL) {
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 39775fc380c..ff8e1bbd0e1 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -285,48 +285,33 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)
(POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR));
}
-static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
{
- struct joydev_list *list = file->private_data;
- struct joydev *joydev = list->joydev;
struct input_dev *dev = joydev->handle.dev;
- void __user *argp = (void __user *)arg;
int i, j;
- if (!joydev->exist) return -ENODEV;
-
switch (cmd) {
case JS_SET_CAL:
return copy_from_user(&joydev->glue.JS_CORR, argp,
- sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
+ sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
case JS_GET_CAL:
return copy_to_user(argp, &joydev->glue.JS_CORR,
- sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
+ sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
case JS_SET_TIMEOUT:
- return get_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
+ return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
case JS_GET_TIMEOUT:
- return put_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
- case JS_SET_TIMELIMIT:
- return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
- case JS_GET_TIMELIMIT:
- return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
- case JS_SET_ALL:
- return copy_from_user(&joydev->glue, argp,
- sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
- case JS_GET_ALL:
- return copy_to_user(argp, &joydev->glue,
- sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
+ return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
case JSIOCGVERSION:
- return put_user(JS_VERSION, (__u32 __user *) arg);
+ return put_user(JS_VERSION, (__u32 __user *) argp);
case JSIOCGAXES:
- return put_user(joydev->nabs, (__u8 __user *) arg);
+ return put_user(joydev->nabs, (__u8 __user *) argp);
case JSIOCGBUTTONS:
- return put_user(joydev->nkey, (__u8 __user *) arg);
+ return put_user(joydev->nkey, (__u8 __user *) argp);
case JSIOCSCORR:
if (copy_from_user(joydev->corr, argp,
- sizeof(struct js_corr) * joydev->nabs))
+ sizeof(joydev->corr[0]) * joydev->nabs))
return -EFAULT;
for (i = 0; i < joydev->nabs; i++) {
j = joydev->abspam[i];
@@ -335,7 +320,7 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return 0;
case JSIOCGCORR:
return copy_to_user(argp, joydev->corr,
- sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
+ sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
case JSIOCSAXMAP:
if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
return -EFAULT;
@@ -371,6 +356,84 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return -EINVAL;
}
+#ifdef CONFIG_COMPAT
+static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct joydev_list *list = file->private_data;
+ struct joydev *joydev = list->joydev;
+ void __user *argp = (void __user *)arg;
+ s32 tmp32;
+ struct JS_DATA_SAVE_TYPE_32 ds32;
+ int err;
+
+ if (!joydev->exist) return -ENODEV;
+ switch(cmd) {
+ case JS_SET_TIMELIMIT:
+ err = get_user(tmp32, (s32 __user *) arg);
+ if (err == 0)
+ joydev->glue.JS_TIMELIMIT = tmp32;
+ break;
+ case JS_GET_TIMELIMIT:
+ tmp32 = joydev->glue.JS_TIMELIMIT;
+ err = put_user(tmp32, (s32 __user *) arg);
+ break;
+
+ case JS_SET_ALL:
+ err = copy_from_user(&ds32, argp,
+ sizeof(ds32)) ? -EFAULT : 0;
+ if (err == 0) {
+ joydev->glue.JS_TIMEOUT = ds32.JS_TIMEOUT;
+ joydev->glue.BUSY = ds32.BUSY;
+ joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME;
+ joydev->glue.JS_TIMELIMIT = ds32.JS_TIMELIMIT;
+ joydev->glue.JS_SAVE = ds32.JS_SAVE;
+ joydev->glue.JS_CORR = ds32.JS_CORR;
+ }
+ break;
+
+ case JS_GET_ALL:
+ ds32.JS_TIMEOUT = joydev->glue.JS_TIMEOUT;
+ ds32.BUSY = joydev->glue.BUSY;
+ ds32.JS_EXPIRETIME = joydev->glue.JS_EXPIRETIME;
+ ds32.JS_TIMELIMIT = joydev->glue.JS_TIMELIMIT;
+ ds32.JS_SAVE = joydev->glue.JS_SAVE;
+ ds32.JS_CORR = joydev->glue.JS_CORR;
+
+ err = copy_to_user(argp, &ds32,
+ sizeof(ds32)) ? -EFAULT : 0;
+ break;
+
+ default:
+ err = joydev_ioctl_common(joydev, cmd, argp);
+ }
+ return err;
+}
+#endif /* CONFIG_COMPAT */
+
+static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct joydev_list *list = file->private_data;
+ struct joydev *joydev = list->joydev;
+ void __user *argp = (void __user *)arg;
+
+ if (!joydev->exist) return -ENODEV;
+
+ switch(cmd) {
+ case JS_SET_TIMELIMIT:
+ return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+ case JS_GET_TIMELIMIT:
+ return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+ case JS_SET_ALL:
+ return copy_from_user(&joydev->glue, argp,
+ sizeof(joydev->glue)) ? -EFAULT : 0;
+ case JS_GET_ALL:
+ return copy_to_user(argp, &joydev->glue,
+ sizeof(joydev->glue)) ? -EFAULT : 0;
+ default:
+ return joydev_ioctl_common(joydev, cmd, argp);
+ }
+}
+
static struct file_operations joydev_fops = {
.owner = THIS_MODULE,
.read = joydev_read,
@@ -379,6 +442,9 @@ static struct file_operations joydev_fops = {
.open = joydev_open,
.release = joydev_release,
.ioctl = joydev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = joydev_compat_ioctl,
+#endif
.fasync = joydev_fasync,
};
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
index ad39fe4bf35..bf34f75b946 100644
--- a/drivers/input/joystick/a3d.c
+++ b/drivers/input/joystick/a3d.c
@@ -185,7 +185,7 @@ static void a3d_poll(struct gameport *gameport)
a3d->reads++;
if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length ||
data[0] != a3d->mode || a3d_csum(data, a3d->length))
- a3d->bads++;
+ a3d->bads++;
else
a3d_read(a3d, data);
}
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
index 83f6dafc171..265962956c6 100644
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -82,7 +82,7 @@ static char adi_cm2_abs[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
static char adi_wmf_abs[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
static short adi_wmgpe_key[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT };
-static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
+static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
static short adi_wmed3d_key[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 };
static short adi_cm2_key[] = { BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
@@ -183,7 +183,7 @@ static void adi_move_bits(struct adi_port *port, int length)
int i;
struct adi *adi = port->adi;
- adi[0].idx = adi[1].idx = 0;
+ adi[0].idx = adi[1].idx = 0;
if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
index cf36ca9b92f..033456bb9fe 100644
--- a/drivers/input/joystick/amijoy.c
+++ b/drivers/input/joystick/amijoy.c
@@ -51,7 +51,8 @@ MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is
__obsolete_setup("amijoy=");
-static int amijoy_used[2] = { 0, 0 };
+static int amijoy_used;
+static DECLARE_MUTEX(amijoy_sem);
static struct input_dev amijoy_dev[2];
static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
@@ -84,26 +85,30 @@ static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
static int amijoy_open(struct input_dev *dev)
{
- int *used = dev->private;
+ int err;
- if ((*used)++)
- return 0;
+ err = down_interruptible(&amijoy_sem);
+ if (err)
+ return err;
- if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
- (*used)--;
+ if (!amijoy_used && request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
- return -EBUSY;
+ err = -EBUSY;
+ goto out;
}
- return 0;
+ amijoy_used++;
+out:
+ up(&amijoy_sem);
+ return err;
}
static void amijoy_close(struct input_dev *dev)
{
- int *used = dev->private;
-
- if (!--(*used))
+ down(&amijoysem);
+ if (!--amijoy_used)
free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
+ up(&amijoy_sem);
}
static int __init amijoy_init(void)
@@ -138,8 +143,6 @@ static int __init amijoy_init(void)
amijoy_dev[i].id.product = 0x0003;
amijoy_dev[i].id.version = 0x0100;
- amijoy_dev[i].private = amijoy_used + i;
-
input_register_device(amijoy_dev + i);
printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i);
}
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index cfdd3acf06a..fbd3eed07f9 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -87,7 +87,7 @@ __obsolete_setup("db9_3=");
#define DB9_NORMAL 0x0a
#define DB9_NOSELECT 0x08
-#define DB9_MAX_DEVICES 2
+#define DB9_MAX_DEVICES 2
#define DB9_GENESIS6_DELAY 14
#define DB9_REFRESH_TIME HZ/100
@@ -98,6 +98,7 @@ struct db9 {
struct pardevice *pd;
int mode;
int used;
+ struct semaphore sem;
char phys[2][32];
};
@@ -503,6 +504,11 @@ static int db9_open(struct input_dev *dev)
{
struct db9 *db9 = dev->private;
struct parport *port = db9->pd->port;
+ int err;
+
+ err = down_interruptible(&db9->sem);
+ if (err)
+ return err;
if (!db9->used++) {
parport_claim(db9->pd);
@@ -514,6 +520,7 @@ static int db9_open(struct input_dev *dev)
mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
}
+ up(&db9->sem);
return 0;
}
@@ -522,12 +529,14 @@ static void db9_close(struct input_dev *dev)
struct db9 *db9 = dev->private;
struct parport *port = db9->pd->port;
+ down(&db9->sem);
if (!--db9->used) {
- del_timer(&db9->timer);
+ del_timer_sync(&db9->timer);
parport_write_control(port, 0x00);
parport_data_forward(port);
parport_release(db9->pd);
}
+ up(&db9->sem);
}
static struct db9 __init *db9_probe(int *config, int nargs)
@@ -563,12 +572,12 @@ static struct db9 __init *db9_probe(int *config, int nargs)
}
}
- if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL))) {
+ if (!(db9 = kcalloc(1, sizeof(struct db9), GFP_KERNEL))) {
parport_put_port(pp);
return NULL;
}
- memset(db9, 0, sizeof(struct db9));
+ init_MUTEX(&db9->sem);
db9->mode = config[1];
init_timer(&db9->timer);
db9->timer.data = (long) db9;
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index 8732f52bdd0..95bbdd302aa 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -1,12 +1,12 @@
/*
* NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux
*
- * Copyright (c) 1999-2004 Vojtech Pavlik <vojtech@suse.cz>
- * Copyright (c) 2004 Peter Nelson <rufus-kernel@hackish.org>
+ * Copyright (c) 1999-2004 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2004 Peter Nelson <rufus-kernel@hackish.org>
*
* Based on the work of:
- * Andree Borrmann John Dahlstrom
- * David Kuder Nathan Hand
+ * Andree Borrmann John Dahlstrom
+ * David Kuder Nathan Hand
*/
/*
@@ -81,6 +81,7 @@ struct gc {
struct timer_list timer;
unsigned char pads[GC_MAX + 1];
int used;
+ struct semaphore sem;
char phys[5][32];
};
@@ -433,7 +434,7 @@ static void gc_timer(unsigned long private)
gc_psx_read_packet(gc, data_psx, data);
for (i = 0; i < 5; i++) {
- switch (data[i]) {
+ switch (data[i]) {
case GC_PSX_RUMBLE:
@@ -503,22 +504,33 @@ static void gc_timer(unsigned long private)
static int gc_open(struct input_dev *dev)
{
struct gc *gc = dev->private;
+ int err;
+
+ err = down_interruptible(&gc->sem);
+ if (err)
+ return err;
+
if (!gc->used++) {
parport_claim(gc->pd);
parport_write_control(gc->pd->port, 0x04);
mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
}
+
+ up(&gc->sem);
return 0;
}
static void gc_close(struct input_dev *dev)
{
struct gc *gc = dev->private;
+
+ down(&gc->sem);
if (!--gc->used) {
- del_timer(&gc->timer);
+ del_timer_sync(&gc->timer);
parport_write_control(gc->pd->port, 0x00);
parport_release(gc->pd);
}
+ up(&gc->sem);
}
static struct gc __init *gc_probe(int *config, int nargs)
@@ -542,11 +554,12 @@ static struct gc __init *gc_probe(int *config, int nargs)
return NULL;
}
- if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL))) {
+ if (!(gc = kcalloc(1, sizeof(struct gc), GFP_KERNEL))) {
parport_put_port(pp);
return NULL;
}
- memset(gc, 0, sizeof(struct gc));
+
+ init_MUTEX(&gc->sem);
gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index ad13f09a4e7..7d969420066 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -329,7 +329,7 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
for (i = 0; i < gf2k_axes[gf2k->id]; i++) {
gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 :
- gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
+ gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
gf2k->dev.absmin[gf2k_abs[i]] = 32;
gf2k->dev.absfuzz[gf2k_abs[i]] = 8;
gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;
diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c
index 42e5005d621..0da7bd133cc 100644
--- a/drivers/input/joystick/grip_mp.c
+++ b/drivers/input/joystick/grip_mp.c
@@ -171,7 +171,7 @@ static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *pa
*packet = 0;
raw_data = gameport_read(gameport);
if (raw_data & 1)
- return IO_RETRY;
+ return IO_RETRY;
for (i = 0; i < 64; i++) {
raw_data = gameport_read(gameport);
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index 028f3513629..e31b7b93fde 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -78,6 +78,7 @@ static struct iforce_device iforce_device[] = {
{ 0x061c, 0xc0a4, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //?
+ { 0x06f8, 0x0004, "Gullemot Jet Leader 3D", btn_joystick, abs_joystick, ff_iforce }, //?
{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce }
};
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index 617c0b0e5a3..6369a24684f 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -229,6 +229,7 @@ static struct usb_device_id iforce_usb_ids [] = {
{ USB_DEVICE(0x061c, 0xc0a4) }, /* ACT LABS Force RS */
{ USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */
{ USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */
+ { USB_DEVICE(0x06f8, 0xa302) }, /* Guillemot Jet Leader 3D */
{ } /* Terminating entry */
};
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index ec0a2a64d49..a436f222085 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -4,8 +4,8 @@
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* Based on the work of:
- * David Thompson
- * Joseph Krahn
+ * David Thompson
+ * Joseph Krahn
*/
/*
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
index 874367bfab0..01fd2e4791a 100644
--- a/drivers/input/joystick/spaceorb.c
+++ b/drivers/input/joystick/spaceorb.c
@@ -4,7 +4,7 @@
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* Based on the work of:
- * David Thompson
+ * David Thompson
*/
/*
diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
index aaee52ceb92..9eb9954cac6 100644
--- a/drivers/input/joystick/tmdc.c
+++ b/drivers/input/joystick/tmdc.c
@@ -79,7 +79,7 @@ static short tmdc_btn_pad[TMDC_BTN] =
{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR };
static short tmdc_btn_joy[TMDC_BTN] =
{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE,
- BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
+ BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
static short tmdc_btn_fm[TMDC_BTN] =
{ BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 };
static short tmdc_btn_at[TMDC_BTN] =
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index dd88b9cb49f..28100d461cb 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -84,6 +84,7 @@ static struct tgfx {
char phys[7][32];
int sticks;
int used;
+ struct semaphore sem;
} *tgfx_base[3];
/*
@@ -99,7 +100,7 @@ static void tgfx_timer(unsigned long private)
for (i = 0; i < 7; i++)
if (tgfx->sticks & (1 << i)) {
- dev = tgfx->dev + i;
+ dev = tgfx->dev + i;
parport_write_data(tgfx->pd->port, ~(1 << i));
data1 = parport_read_status(tgfx->pd->port) ^ 0x7f;
@@ -122,23 +123,34 @@ static void tgfx_timer(unsigned long private)
static int tgfx_open(struct input_dev *dev)
{
- struct tgfx *tgfx = dev->private;
- if (!tgfx->used++) {
+ struct tgfx *tgfx = dev->private;
+ int err;
+
+ err = down_interruptible(&tgfx->sem);
+ if (err)
+ return err;
+
+ if (!tgfx->used++) {
parport_claim(tgfx->pd);
parport_write_control(tgfx->pd->port, 0x04);
- mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
+ mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
}
- return 0;
+
+ up(&tgfx->sem);
+ return 0;
}
static void tgfx_close(struct input_dev *dev)
{
- struct tgfx *tgfx = dev->private;
- if (!--tgfx->used) {
- del_timer(&tgfx->timer);
+ struct tgfx *tgfx = dev->private;
+
+ down(&tgfx->sem);
+ if (!--tgfx->used) {
+ del_timer_sync(&tgfx->timer);
parport_write_control(tgfx->pd->port, 0x00);
- parport_release(tgfx->pd);
+ parport_release(tgfx->pd);
}
+ up(&tgfx->sem);
}
/*
@@ -166,11 +178,12 @@ static struct tgfx __init *tgfx_probe(int *config, int nargs)
return NULL;
}
- if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL))) {
+ if (!(tgfx = kcalloc(1, sizeof(struct tgfx), GFP_KERNEL))) {
parport_put_port(pp);
return NULL;
}
- memset(tgfx, 0, sizeof(struct tgfx));
+
+ init_MUTEX(&tgfx->sem);
tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 82fad9a23ac..4d4985b59ab 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -227,7 +227,7 @@ static ssize_t atkbd_do_set_##_name(struct device *d, struct device_attribute *a
{ \
return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \
} \
-static struct device_attribute atkbd_attr_##_name = \
+static struct device_attribute atkbd_attr_##_name = \
__ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
ATKBD_DEFINE_ATTR(extra);
@@ -388,7 +388,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
value = atkbd->release ? 0 :
(1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key)));
- switch (value) { /* Workaround Toshiba laptop multiple keypress */
+ switch (value) { /* Workaround Toshiba laptop multiple keypress */
case 0:
atkbd->last = 0;
break;
@@ -894,7 +894,7 @@ static int atkbd_reconnect(struct serio *serio)
if (atkbd->write) {
param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0)
| (test_bit(LED_NUML, atkbd->dev.led) ? 2 : 0)
- | (test_bit(LED_CAPSL, atkbd->dev.led) ? 4 : 0);
+ | (test_bit(LED_CAPSL, atkbd->dev.led) ? 4 : 0);
if (atkbd_probe(atkbd))
return -1;
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index 0f1220a0ceb..a8551711e8d 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -39,6 +39,7 @@
#define CORGI_KEY_CALENDER KEY_F1
#define CORGI_KEY_ADDRESS KEY_F2
#define CORGI_KEY_FN KEY_F3
+#define CORGI_KEY_CANCEL KEY_F4
#define CORGI_KEY_OFF KEY_SUSPEND
#define CORGI_KEY_EXOK KEY_F5
#define CORGI_KEY_EXCANCEL KEY_F6
@@ -46,6 +47,7 @@
#define CORGI_KEY_EXJOGUP KEY_F8
#define CORGI_KEY_JAP1 KEY_LEFTCTRL
#define CORGI_KEY_JAP2 KEY_LEFTALT
+#define CORGI_KEY_MAIL KEY_F10
#define CORGI_KEY_OK KEY_F11
#define CORGI_KEY_MENU KEY_F12
#define CORGI_HINGE_0 KEY_KP0
@@ -59,8 +61,8 @@ static unsigned char corgikbd_keycode[NR_SCANCODES] = {
KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0, /* 33-48 */
CORGI_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0, /* 49-64 */
CORGI_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, /* 65-80 */
- KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0, /* 81-96 */
- KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0, /* 97-112 */
+ CORGI_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0, /* 81-96 */
+ KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, CORGI_KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0, /* 97-112 */
CORGI_KEY_OFF, CORGI_KEY_EXOK, CORGI_KEY_EXCANCEL, CORGI_KEY_EXJOGDOWN, CORGI_KEY_EXJOGUP, 0, 0, 0, 0, 0, 0, 0, /* 113-124 */
CORGI_HINGE_0, CORGI_HINGE_1, CORGI_HINGE_2 /* 125-127 */
};
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
index 2694ff2b5be..098963c7cdd 100644
--- a/drivers/input/keyboard/lkkbd.c
+++ b/drivers/input/keyboard/lkkbd.c
@@ -15,10 +15,10 @@
* information given below, I will _not_ be liable!
*
* RJ10 pinout: To DE9: Or DB25:
- * 1 - RxD <----> Pin 3 (TxD) <-> Pin 2 (TxD)
- * 2 - GND <----> Pin 5 (GND) <-> Pin 7 (GND)
- * 4 - TxD <----> Pin 2 (RxD) <-> Pin 3 (RxD)
- * 3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!!
+ * 1 - RxD <----> Pin 3 (TxD) <-> Pin 2 (TxD)
+ * 2 - GND <----> Pin 5 (GND) <-> Pin 7 (GND)
+ * 4 - TxD <----> Pin 2 (RxD) <-> Pin 3 (RxD)
+ * 3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!!
*
* Pin numbers for DE9 and DB25 are noted on the plug (quite small:). For
* RJ10, it's like this:
diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
index d3e9dd6a13c..8935290256b 100644
--- a/drivers/input/keyboard/locomokbd.c
+++ b/drivers/input/keyboard/locomokbd.c
@@ -42,7 +42,7 @@ MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
MODULE_DESCRIPTION("LoCoMo keyboard driver");
MODULE_LICENSE("GPL");
-#define LOCOMOKBD_NUMKEYS 128
+#define LOCOMOKBD_NUMKEYS 128
#define KEY_ACTIVITY KEY_F16
#define KEY_CONTACT KEY_F18
@@ -61,7 +61,7 @@ static unsigned char locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
KEY_G, KEY_F, KEY_X, KEY_S, 0, 0, 0, 0, 0, 0, /* 90 - 99 */
0, 0, KEY_DOT, 0, KEY_COMMA, KEY_N, KEY_B, KEY_C, KEY_Z, KEY_A, /* 100 - 109 */
KEY_LEFTSHIFT, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0, 0, 0, /* 110 - 119 */
- KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0 /* 120 - 128 */
+ KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0 /* 120 - 128 */
};
#define KB_ROWS 16
@@ -82,7 +82,7 @@ struct locomokbd {
struct locomo_dev *ldev;
unsigned long base;
spinlock_t lock;
-
+
struct timer_list timer;
};
@@ -95,7 +95,7 @@ static inline void locomokbd_charge_all(unsigned long membase)
static inline void locomokbd_activate_all(unsigned long membase)
{
unsigned long r;
-
+
locomo_writel(0, membase + LOCOMO_KSC);
r = locomo_readl(membase + LOCOMO_KIC);
r &= 0xFEFF;
@@ -127,7 +127,7 @@ static inline void locomokbd_reset_col(unsigned long membase, int col)
*/
/* Scan the hardware keyboard and push any changes up through the input layer */
-static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *regs)
+static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *regs)
{
unsigned int row, col, rowd, scancode;
unsigned long flags;
@@ -138,7 +138,7 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
if (regs)
input_regs(&locomokbd->input, regs);
-
+
locomokbd_charge_all(membase);
num_pressed = 0;
@@ -146,9 +146,9 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
locomokbd_activate_col(membase, col);
udelay(KB_DELAY);
-
+
rowd = ~locomo_readl(membase + LOCOMO_KIB);
- for (row = 0; row < KB_ROWS; row++ ) {
+ for (row = 0; row < KB_ROWS; row++) {
scancode = SCANCODE(col, row);
if (rowd & KB_ROWMASK(row)) {
num_pressed += 1;
@@ -170,7 +170,7 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
spin_unlock_irqrestore(&locomokbd->lock, flags);
}
-/*
+/*
* LoCoMo keyboard interrupt handler.
*/
static irqreturn_t locomokbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -205,8 +205,8 @@ static int locomokbd_probe(struct locomo_dev *dev)
memset(locomokbd, 0, sizeof(struct locomokbd));
/* try and claim memory region */
- if (!request_mem_region((unsigned long) dev->mapbase,
- dev->length,
+ if (!request_mem_region((unsigned long) dev->mapbase,
+ dev->length,
LOCOMO_DRIVER_NAME(dev))) {
ret = -EBUSY;
printk(KERN_ERR "locomokbd: Can't acquire access to io memory for keyboard\n");
@@ -225,7 +225,7 @@ static int locomokbd_probe(struct locomo_dev *dev)
locomokbd->timer.data = (unsigned long) locomokbd;
locomokbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
-
+
init_input_dev(&locomokbd->input);
locomokbd->input.keycode = locomokbd->keycode;
locomokbd->input.keycodesize = sizeof(unsigned char);
@@ -271,11 +271,11 @@ free:
static int locomokbd_remove(struct locomo_dev *dev)
{
struct locomokbd *locomokbd = locomo_get_drvdata(dev);
-
+
free_irq(dev->irq[0], locomokbd);
del_timer_sync(&locomokbd->timer);
-
+
input_unregister_device(&locomokbd->input);
locomo_set_drvdata(dev, NULL);
diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c
index 859ed771ee0..eecbde294f1 100644
--- a/drivers/input/keyboard/maple_keyb.c
+++ b/drivers/input/keyboard/maple_keyb.c
@@ -1,6 +1,6 @@
/*
* $Id: maple_keyb.c,v 1.4 2004/03/22 01:18:15 lethal Exp $
- * SEGA Dreamcast keyboard driver
+ * SEGA Dreamcast keyboard driver
* Based on drivers/usb/usbkbd.c
*/
@@ -40,7 +40,6 @@ struct dc_kbd {
struct input_dev dev;
unsigned char new[8];
unsigned char old[8];
- int open;
};
@@ -95,22 +94,6 @@ static void dc_kbd_callback(struct mapleq *mq)
}
}
-
-static int dc_kbd_open(struct input_dev *dev)
-{
- struct dc_kbd *kbd = dev->private;
- kbd->open++;
- return 0;
-}
-
-
-static void dc_kbd_close(struct input_dev *dev)
-{
- struct dc_kbd *kbd = dev->private;
- kbd->open--;
-}
-
-
static int dc_kbd_connect(struct maple_device *dev)
{
int i;
@@ -133,9 +116,6 @@ static int dc_kbd_connect(struct maple_device *dev)
clear_bit(0, kbd->dev.keybit);
kbd->dev.private = kbd;
- kbd->dev.open = dc_kbd_open;
- kbd->dev.close = dc_kbd_close;
- kbd->dev.event = NULL;
kbd->dev.name = dev->product_name;
kbd->dev.id.bustype = BUS_MAPLE;
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 158c8e845ff..98710997aaa 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -298,9 +298,11 @@ static int uinput_alloc_device(struct file *file, const char __user *buffer, siz
/* check if absmin/absmax/absfuzz/absflat are filled as
* told in Documentation/input/input-programming.txt */
if (test_bit(EV_ABS, dev->evbit)) {
- retval = uinput_validate_absbits(dev);
- if (retval < 0)
+ int err = uinput_validate_absbits(dev);
+ if (err < 0) {
+ retval = err;
kfree(dev->name);
+ }
}
exit:
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index a7864195806..c4909b49337 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -15,4 +15,4 @@ obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
-psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o
+psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 7bf4be733e9..a12e98158a7 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -30,10 +30,11 @@
#define ALPS_DUALPOINT 0x01
#define ALPS_WHEEL 0x02
-#define ALPS_FW_BK 0x04
+#define ALPS_FW_BK_1 0x04
#define ALPS_4BTN 0x08
#define ALPS_OLDPROTO 0x10
#define ALPS_PASS 0x20
+#define ALPS_FW_BK_2 0x40
static struct alps_model_info alps_model_data[] = {
{ { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */
@@ -43,11 +44,11 @@ static struct alps_model_info alps_model_data[] = {
{ { 0x63, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x02, 0x3c }, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */
- { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK }, /* NEC Versa L320 */
+ { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */
{ { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS }, /* Dell Latitude D800 */
{ { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
- { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
+ { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */
{ { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
{ { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
@@ -61,11 +62,11 @@ static struct alps_model_info alps_model_data[] = {
/*
* ALPS abolute Mode - new format
- *
- * byte 0: 1 ? ? ? 1 ? ? ?
+ *
+ * byte 0: 1 ? ? ? 1 ? ? ?
* byte 1: 0 x6 x5 x4 x3 x2 x1 x0
* byte 2: 0 x10 x9 x8 x7 ? fin ges
- * byte 3: 0 y9 y8 y7 1 M R L
+ * byte 3: 0 y9 y8 y7 1 M R L
* byte 4: 0 y6 y5 y4 y3 y2 y1 y0
* byte 5: 0 z6 z5 z4 z3 z2 z1 z0
*
@@ -81,11 +82,12 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
struct input_dev *dev = &psmouse->dev;
struct input_dev *dev2 = &priv->dev2;
int x, y, z, ges, fin, left, right, middle;
+ int back = 0, forward = 0;
input_regs(dev, regs);
if ((packet[0] & 0xc8) == 0x08) { /* 3-byte PS/2 packet */
- input_report_key(dev2, BTN_LEFT, packet[0] & 1);
+ input_report_key(dev2, BTN_LEFT, packet[0] & 1);
input_report_key(dev2, BTN_RIGHT, packet[0] & 2);
input_report_key(dev2, BTN_MIDDLE, packet[0] & 4);
input_report_rel(dev2, REL_X,
@@ -112,6 +114,18 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
z = packet[5];
}
+ if (priv->i->flags & ALPS_FW_BK_1) {
+ back = packet[2] & 4;
+ forward = packet[0] & 0x10;
+ }
+
+ if (priv->i->flags & ALPS_FW_BK_2) {
+ back = packet[3] & 4;
+ forward = packet[2] & 4;
+ if ((middle = forward && back))
+ forward = back = 0;
+ }
+
ges = packet[2] & 1;
fin = packet[2] & 2;
@@ -155,13 +169,12 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
input_report_abs(dev, ABS_PRESSURE, z);
input_report_key(dev, BTN_TOOL_FINGER, z > 0);
-
if (priv->i->flags & ALPS_WHEEL)
input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08));
- if (priv->i->flags & ALPS_FW_BK) {
- input_report_key(dev, BTN_FORWARD, packet[0] & 0x10);
- input_report_key(dev, BTN_BACK, packet[2] & 0x04);
+ if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
+ input_report_key(dev, BTN_FORWARD, forward);
+ input_report_key(dev, BTN_BACK, back);
}
input_sync(dev);
@@ -257,7 +270,6 @@ static struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *vers
static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
- unsigned char param[3];
int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
if (ps2_command(ps2dev, NULL, cmd) ||
@@ -267,7 +279,7 @@ static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
return -1;
/* we may get 3 more bytes, just ignore them */
- ps2_command(ps2dev, param, 0x0300);
+ ps2_drain(ps2dev, 3, 100);
return 0;
}
@@ -425,7 +437,7 @@ int alps_init(struct psmouse *psmouse)
psmouse->dev.relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL);
}
- if (priv->i->flags & ALPS_FW_BK) {
+ if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
}
@@ -436,8 +448,8 @@ int alps_init(struct psmouse *psmouse)
priv->dev2.id.bustype = BUS_I8042;
priv->dev2.id.vendor = 0x0002;
priv->dev2.id.product = PSMOUSE_ALPS;
- priv->dev2.id.version = 0x0000;
-
+ priv->dev2.id.version = 0x0000;
+
priv->dev2.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
priv->dev2.relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y);
priv->dev2.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
@@ -461,17 +473,15 @@ init_fail:
int alps_detect(struct psmouse *psmouse, int set_properties)
{
int version;
- struct alps_model_info *model;
+ struct alps_model_info *model;
if (!(model = alps_get_model(psmouse, &version)))
return -1;
if (set_properties) {
psmouse->vendor = "ALPS";
- if (model->flags & ALPS_DUALPOINT)
- psmouse->name = "DualPoint TouchPad";
- else
- psmouse->name = "GlidePoint";
+ psmouse->name = model->flags & ALPS_DUALPOINT ?
+ "DualPoint TouchPad" : "GlidePoint";
psmouse->model = version;
}
return 0;
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
index 7baa09cca7c..e994849efb8 100644
--- a/drivers/input/mouse/amimouse.c
+++ b/drivers/input/mouse/amimouse.c
@@ -33,7 +33,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Amiga mouse driver");
MODULE_LICENSE("GPL");
-static int amimouse_used = 0;
static int amimouse_lastx, amimouse_lasty;
static struct input_dev amimouse_dev;
@@ -81,16 +80,12 @@ static int amimouse_open(struct input_dev *dev)
{
unsigned short joy0dat;
- if (amimouse_used++)
- return 0;
-
joy0dat = custom.joy0dat;
amimouse_lastx = joy0dat & 0xff;
amimouse_lasty = joy0dat >> 8;
if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) {
- amimouse_used--;
printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
return -EBUSY;
}
@@ -100,8 +95,7 @@ static int amimouse_open(struct input_dev *dev)
static void amimouse_close(struct input_dev *dev)
{
- if (!--amimouse_used)
- free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
+ free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
}
static int __init amimouse_init(void)
diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
index ca4e9688662..1f62c013401 100644
--- a/drivers/input/mouse/inport.c
+++ b/drivers/input/mouse/inport.c
@@ -17,18 +17,18 @@
/*
* 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
+ * 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
- *
+ *
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -87,29 +87,23 @@ MODULE_PARM_DESC(irq, "IRQ number (5=default)");
__obsolete_setup("inport_irq=");
-static int inport_used;
-
static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int inport_open(struct input_dev *dev)
{
- if (!inport_used++) {
- if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
- return -EBUSY;
- outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
- outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
- }
+ if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
+ return -EBUSY;
+ outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+ outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
return 0;
}
static void inport_close(struct input_dev *dev)
{
- if (!--inport_used) {
- outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
- outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
- free_irq(inport_irq, NULL);
- }
+ outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+ outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
+ free_irq(inport_irq, NULL);
}
static struct input_dev inport_dev = {
@@ -120,11 +114,11 @@ static struct input_dev inport_dev = {
.close = inport_close,
.name = INPORT_NAME,
.phys = "isa023c/input0",
- .id = {
- .bustype = BUS_ISA,
- .vendor = INPORT_VENDOR,
- .product = 0x0001,
- .version = 0x0100,
+ .id = {
+ .bustype = BUS_ISA,
+ .vendor = INPORT_VENDOR,
+ .product = 0x0001,
+ .version = 0x0100,
},
};
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
new file mode 100644
index 00000000000..bd9df9b2832
--- /dev/null
+++ b/drivers/input/mouse/lifebook.c
@@ -0,0 +1,134 @@
+/*
+ * Fujitsu B-series Lifebook PS/2 TouchScreen driver
+ *
+ * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Kenan Esau <kenan.esau@conan.de>
+ *
+ * TouchScreen detection, absolute mode setting and packet layout is taken from
+ * Harald Hoyer's description of the device.
+ *
+ * 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.
+ */
+
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/libps2.h>
+#include <linux/dmi.h>
+
+#include "psmouse.h"
+#include "lifebook.h"
+
+static struct dmi_system_id lifebook_dmi_table[] = {
+ {
+ .ident = "Lifebook B",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"),
+ },
+ },
+ { }
+};
+
+
+static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+{
+ unsigned char *packet = psmouse->packet;
+ struct input_dev *dev = &psmouse->dev;
+
+ if (psmouse->pktcnt != 3)
+ return PSMOUSE_GOOD_DATA;
+
+ input_regs(dev, regs);
+
+ /* calculate X and Y */
+ if ((packet[0] & 0x08) == 0x00) {
+ input_report_abs(dev, ABS_X,
+ (packet[1] | ((packet[0] & 0x30) << 4)));
+ input_report_abs(dev, ABS_Y,
+ 1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
+ } else {
+ input_report_rel(dev, REL_X,
+ ((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
+ input_report_rel(dev, REL_Y,
+ -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
+ }
+
+ input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
+ input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+ input_report_key(dev, BTN_TOUCH, packet[0] & 0x04);
+
+ input_sync(dev);
+
+ return PSMOUSE_FULL_PACKET;
+}
+
+static int lifebook_absolute_mode(struct psmouse *psmouse)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param;
+
+ if (psmouse_reset(psmouse))
+ return -1;
+
+ /*
+ Enable absolute output -- ps2_command fails always but if
+ you leave this call out the touchsreen will never send
+ absolute coordinates
+ */
+ param = 0x07;
+ ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
+
+ return 0;
+}
+
+static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+{
+ unsigned char params[] = { 0, 1, 2, 2, 3 };
+
+ if (resolution == 0 || resolution > 400)
+ resolution = 400;
+
+ ps2_command(&psmouse->ps2dev, &params[resolution / 100], PSMOUSE_CMD_SETRES);
+ psmouse->resolution = 50 << params[resolution / 100];
+}
+
+static void lifebook_disconnect(struct psmouse *psmouse)
+{
+ psmouse_reset(psmouse);
+}
+
+int lifebook_detect(struct psmouse *psmouse, int set_properties)
+{
+ if (!dmi_check_system(lifebook_dmi_table))
+ return -1;
+
+ if (set_properties) {
+ psmouse->vendor = "Fujitsu";
+ psmouse->name = "Lifebook TouchScreen";
+ }
+
+ return 0;
+}
+
+int lifebook_init(struct psmouse *psmouse)
+{
+ if (lifebook_absolute_mode(psmouse))
+ return -1;
+
+ psmouse->dev.evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
+ psmouse->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ psmouse->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ input_set_abs_params(&psmouse->dev, ABS_X, 0, 1024, 0, 0);
+ input_set_abs_params(&psmouse->dev, ABS_Y, 0, 1024, 0, 0);
+
+ psmouse->protocol_handler = lifebook_process_byte;
+ psmouse->set_resolution = lifebook_set_resolution;
+ psmouse->disconnect = lifebook_disconnect;
+ psmouse->reconnect = lifebook_absolute_mode;
+ psmouse->pktsize = 3;
+
+ return 0;
+}
+
diff --git a/drivers/input/mouse/lifebook.h b/drivers/input/mouse/lifebook.h
new file mode 100644
index 00000000000..be1c0943825
--- /dev/null
+++ b/drivers/input/mouse/lifebook.h
@@ -0,0 +1,17 @@
+/*
+ * Fujitsu B-series Lifebook PS/2 TouchScreen driver
+ *
+ * Copyright (c) 2005 Vojtech Pavlik
+ *
+ * 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.
+ */
+
+#ifndef _LIFEBOOK_H
+#define _LIFEBOOK_H
+
+int lifebook_detect(struct psmouse *psmouse, int set_properties);
+int lifebook_init(struct psmouse *psmouse);
+
+#endif
diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c
index 77eb83e87f6..8b524316722 100644
--- a/drivers/input/mouse/logibm.c
+++ b/drivers/input/mouse/logibm.c
@@ -18,18 +18,18 @@
/*
* 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
+ * 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
- *
+ *
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -77,16 +77,11 @@ MODULE_PARM_DESC(irq, "IRQ number (5=default)");
__obsolete_setup("logibm_irq=");
-static int logibm_used = 0;
-
static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int logibm_open(struct input_dev *dev)
{
- if (logibm_used++)
- return 0;
if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) {
- logibm_used--;
printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq);
return -EBUSY;
}
@@ -96,8 +91,6 @@ static int logibm_open(struct input_dev *dev)
static void logibm_close(struct input_dev *dev)
{
- if (--logibm_used)
- return;
outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
free_irq(logibm_irq, NULL);
}
@@ -167,7 +160,7 @@ static int __init logibm_init(void)
outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
input_register_device(&logibm_dev);
-
+
printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq);
return 0;
diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c
index 12dc0ef5020..e90c60cbbf0 100644
--- a/drivers/input/mouse/maplemouse.c
+++ b/drivers/input/mouse/maplemouse.c
@@ -1,6 +1,6 @@
/*
* $Id: maplemouse.c,v 1.2 2004/03/22 01:18:15 lethal Exp $
- * SEGA Dreamcast mouse driver
+ * SEGA Dreamcast mouse driver
* Based on drivers/usb/usbmouse.c
*/
@@ -15,80 +15,51 @@
MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>");
MODULE_DESCRIPTION("SEGA Dreamcast mouse driver");
-struct dc_mouse {
- struct input_dev dev;
- int open;
-};
-
-
static void dc_mouse_callback(struct mapleq *mq)
{
int buttons, relx, rely, relz;
struct maple_device *mapledev = mq->dev;
- struct dc_mouse *mouse = mapledev->private_data;
- struct input_dev *dev = &mouse->dev;
+ struct input_dev *dev = mapledev->private_data;
unsigned char *res = mq->recvbuf;
buttons = ~res[8];
- relx=*(unsigned short *)(res+12)-512;
- rely=*(unsigned short *)(res+14)-512;
- relz=*(unsigned short *)(res+16)-512;
+ relx = *(unsigned short *)(res + 12) - 512;
+ rely = *(unsigned short *)(res + 14) - 512;
+ relz = *(unsigned short *)(res + 16) - 512;
- input_report_key(dev, BTN_LEFT, buttons&4);
- input_report_key(dev, BTN_MIDDLE, buttons&9);
- input_report_key(dev, BTN_RIGHT, buttons&2);
+ input_report_key(dev, BTN_LEFT, buttons & 4);
+ input_report_key(dev, BTN_MIDDLE, buttons & 9);
+ input_report_key(dev, BTN_RIGHT, buttons & 2);
input_report_rel(dev, REL_X, relx);
input_report_rel(dev, REL_Y, rely);
input_report_rel(dev, REL_WHEEL, relz);
input_sync(dev);
}
-
-static int dc_mouse_open(struct input_dev *dev)
-{
- struct dc_mouse *mouse = dev->private;
- mouse->open++;
- return 0;
-}
-
-
-static void dc_mouse_close(struct input_dev *dev)
-{
- struct dc_mouse *mouse = dev->private;
- mouse->open--;
-}
-
-
static int dc_mouse_connect(struct maple_device *dev)
{
unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]);
- struct dc_mouse *mouse;
+ struct input_dev *input_dev;
- if (!(mouse = kmalloc(sizeof(struct dc_mouse), GFP_KERNEL)))
+ if (!(input_dev = kmalloc(sizeof(struct input_dev), GFP_KERNEL)))
return -1;
- memset(mouse, 0, sizeof(struct dc_mouse));
-
- dev->private_data = mouse;
- mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
- mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
+ dev->private_data = input_dev;
- init_input_dev(&mouse->dev);
+ memset(input_dev, 0, sizeof(struct dc_mouse));
+ init_input_dev(input_dev);
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+ input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+ input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
- mouse->dev.private = mouse;
- mouse->dev.open = dc_mouse_open;
- mouse->dev.close = dc_mouse_close;
- mouse->dev.event = NULL;
+ input_dev->name = dev->product_name;
+ input_dev->id.bustype = BUS_MAPLE;
- mouse->dev.name = dev->product_name;
- mouse->dev.id.bustype = BUS_MAPLE;
-
- input_register_device(&mouse->dev);
+ input_register_device(input_dev);
maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE);
- printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, mouse->dev.name);
+ printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, input_dev->name);
return 0;
}
@@ -96,10 +67,10 @@ static int dc_mouse_connect(struct maple_device *dev)
static void dc_mouse_disconnect(struct maple_device *dev)
{
- struct dc_mouse *mouse = dev->private_data;
+ struct input_dev *input_dev = dev->private_data;
- input_unregister_device(&mouse->dev);
- kfree(mouse);
+ input_unregister_device(input_dev);
+ kfree(input_dev);
}
diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c
index 0c74918fe25..93393d5c007 100644
--- a/drivers/input/mouse/pc110pad.c
+++ b/drivers/input/mouse/pc110pad.c
@@ -4,7 +4,7 @@
* Copyright (c) 2000-2001 Vojtech Pavlik
*
* Based on the work of:
- * Alan Cox Robin O'Leary
+ * Alan Cox Robin O'Leary
*/
/*
@@ -56,7 +56,6 @@ static int pc110pad_io = 0x15e0;
static struct input_dev pc110pad_dev;
static int pc110pad_data[3];
static int pc110pad_count;
-static int pc110pad_used;
static char *pc110pad_name = "IBM PC110 TouchPad";
static char *pc110pad_phys = "isa15e0/input0";
@@ -74,7 +73,7 @@ static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs)
if (pc110pad_count < 3)
return IRQ_HANDLED;
-
+
input_regs(&pc110pad_dev, regs);
input_report_key(&pc110pad_dev, BTN_TOUCH,
pc110pad_data[0] & 0x01);
@@ -90,15 +89,11 @@ static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs)
static void pc110pad_close(struct input_dev *dev)
{
- if (!--pc110pad_used)
- outb(PC110PAD_OFF, pc110pad_io + 2);
+ outb(PC110PAD_OFF, pc110pad_io + 2);
}
static int pc110pad_open(struct input_dev *dev)
{
- if (pc110pad_used++)
- return 0;
-
pc110pad_interrupt(0,NULL,NULL);
pc110pad_interrupt(0,NULL,NULL);
pc110pad_interrupt(0,NULL,NULL);
@@ -145,7 +140,7 @@ static int __init pc110pad_init(void)
pc110pad_dev.absmax[ABS_X] = 0x1ff;
pc110pad_dev.absmax[ABS_Y] = 0x0ff;
-
+
pc110pad_dev.open = pc110pad_open;
pc110pad_dev.close = pc110pad_close;
@@ -156,17 +151,17 @@ static int __init pc110pad_init(void)
pc110pad_dev.id.product = 0x0001;
pc110pad_dev.id.version = 0x0100;
- input_register_device(&pc110pad_dev);
+ input_register_device(&pc110pad_dev);
printk(KERN_INFO "input: %s at %#x irq %d\n",
pc110pad_name, pc110pad_io, pc110pad_irq);
-
+
return 0;
}
-
+
static void __exit pc110pad_exit(void)
{
- input_unregister_device(&pc110pad_dev);
+ input_unregister_device(&pc110pad_dev);
outb(PC110PAD_OFF, pc110pad_io + 2);
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 019034b21a0..19785a6c5ab 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -24,6 +24,7 @@
#include "synaptics.h"
#include "logips2pp.h"
#include "alps.h"
+#include "lifebook.h"
#define DRIVER_DESC "PS/2 mouse driver"
@@ -31,10 +32,9 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-static unsigned int psmouse_max_proto = -1U;
+static unsigned int psmouse_max_proto = PSMOUSE_AUTO;
static int psmouse_set_maxproto(const char *val, struct kernel_param *kp);
static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp);
-static char *psmouse_proto_abbrev[] = { NULL, "bare", NULL, NULL, NULL, "imps", "exps", NULL, NULL, NULL };
#define param_check_proto_abbrev(name, p) __param_check(name, p, unsigned int)
#define param_set_proto_abbrev psmouse_set_maxproto
#define param_get_proto_abbrev psmouse_get_maxproto
@@ -57,6 +57,7 @@ static unsigned int psmouse_resetafter;
module_param_named(resetafter, psmouse_resetafter, uint, 0644);
MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
+PSMOUSE_DEFINE_ATTR(protocol);
PSMOUSE_DEFINE_ATTR(rate);
PSMOUSE_DEFINE_ATTR(resolution);
PSMOUSE_DEFINE_ATTR(resetafter);
@@ -67,7 +68,23 @@ __obsolete_setup("psmouse_smartscroll=");
__obsolete_setup("psmouse_resetafter=");
__obsolete_setup("psmouse_rate=");
-static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "ThinkPS/2", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2" };
+/*
+ * psmouse_sem protects all operations changing state of mouse
+ * (connecting, disconnecting, changing rate or resolution via
+ * sysfs). We could use a per-device semaphore but since there
+ * rarely more than one PS/2 mouse connected and since semaphore
+ * is taken in "slow" paths it is not worth it.
+ */
+static DECLARE_MUTEX(psmouse_sem);
+
+struct psmouse_protocol {
+ enum psmouse_type type;
+ char *name;
+ char *alias;
+ int maxproto;
+ int (*detect)(struct psmouse *, int);
+ int (*init)(struct psmouse *);
+};
/*
* psmouse_process_byte() analyzes the PS/2 data stream and reports
@@ -407,12 +424,15 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties)
*/
static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
{
- if (!psmouse->vendor) psmouse->vendor = "Generic";
- if (!psmouse->name) psmouse->name = "Mouse";
+ if (set_properties) {
+ if (!psmouse->vendor) psmouse->vendor = "Generic";
+ if (!psmouse->name) psmouse->name = "Mouse";
+ }
return 0;
}
+
/*
* psmouse_extensions() probes for any extensions to the basic PS/2 protocol
* the mouse may have.
@@ -424,6 +444,17 @@ static int psmouse_extensions(struct psmouse *psmouse,
int synaptics_hardware = 0;
/*
+ * We always check for lifebook because it does not disturb mouse
+ * (it only checks DMI information).
+ */
+ if (lifebook_detect(psmouse, set_properties) == 0) {
+ if (max_proto > PSMOUSE_IMEX) {
+ if (!set_properties || lifebook_init(psmouse) == 0)
+ return PSMOUSE_LIFEBOOK;
+ }
+ }
+
+/*
* Try Kensington ThinkingMouse (we try first, because synaptics probe
* upsets the thinkingmouse).
*/
@@ -506,6 +537,103 @@ static int psmouse_extensions(struct psmouse *psmouse,
return PSMOUSE_PS2;
}
+static struct psmouse_protocol psmouse_protocols[] = {
+ {
+ .type = PSMOUSE_PS2,
+ .name = "PS/2",
+ .alias = "bare",
+ .maxproto = 1,
+ .detect = ps2bare_detect,
+ },
+ {
+ .type = PSMOUSE_PS2PP,
+ .name = "PS2++",
+ .alias = "logitech",
+ .detect = ps2pp_init,
+ },
+ {
+ .type = PSMOUSE_THINKPS,
+ .name = "ThinkPS/2",
+ .alias = "thinkps",
+ .detect = thinking_detect,
+ },
+ {
+ .type = PSMOUSE_GENPS,
+ .name = "GenPS/2",
+ .alias = "genius",
+ .detect = genius_detect,
+ },
+ {
+ .type = PSMOUSE_IMPS,
+ .name = "ImPS/2",
+ .alias = "imps",
+ .maxproto = 1,
+ .detect = intellimouse_detect,
+ },
+ {
+ .type = PSMOUSE_IMEX,
+ .name = "ImExPS/2",
+ .alias = "exps",
+ .maxproto = 1,
+ .detect = im_explorer_detect,
+ },
+ {
+ .type = PSMOUSE_SYNAPTICS,
+ .name = "SynPS/2",
+ .alias = "synaptics",
+ .detect = synaptics_detect,
+ .init = synaptics_init,
+ },
+ {
+ .type = PSMOUSE_ALPS,
+ .name = "AlpsPS/2",
+ .alias = "alps",
+ .detect = alps_detect,
+ .init = alps_init,
+ },
+ {
+ .type = PSMOUSE_LIFEBOOK,
+ .name = "LBPS/2",
+ .alias = "lifebook",
+ .init = lifebook_init,
+ },
+ {
+ .type = PSMOUSE_AUTO,
+ .name = "auto",
+ .alias = "any",
+ .maxproto = 1,
+ },
+};
+
+static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++)
+ if (psmouse_protocols[i].type == type)
+ return &psmouse_protocols[i];
+
+ WARN_ON(1);
+ return &psmouse_protocols[0];
+}
+
+static struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len)
+{
+ struct psmouse_protocol *p;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) {
+ p = &psmouse_protocols[i];
+
+ if ((strlen(p->name) == len && !strncmp(p->name, name, len)) ||
+ (strlen(p->alias) == len && !strncmp(p->alias, name, len)))
+ return &psmouse_protocols[i];
+ }
+
+ return NULL;
+}
+
+
/*
* psmouse_probe() probes for a PS/2 mouse.
*/
@@ -653,30 +781,84 @@ static void psmouse_cleanup(struct serio *serio)
static void psmouse_disconnect(struct serio *serio)
{
- struct psmouse *psmouse, *parent;
+ struct psmouse *psmouse, *parent = NULL;
+ psmouse = serio_get_drvdata(serio);
+
+ device_remove_file(&serio->dev, &psmouse_attr_protocol);
device_remove_file(&serio->dev, &psmouse_attr_rate);
device_remove_file(&serio->dev, &psmouse_attr_resolution);
device_remove_file(&serio->dev, &psmouse_attr_resetafter);
- psmouse = serio_get_drvdata(serio);
+ down(&psmouse_sem);
+
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
parent = serio_get_drvdata(serio->parent);
- if (parent->pt_deactivate)
- parent->pt_deactivate(parent);
+ psmouse_deactivate(parent);
}
if (psmouse->disconnect)
psmouse->disconnect(psmouse);
+ if (parent && parent->pt_deactivate)
+ parent->pt_deactivate(parent);
+
psmouse_set_state(psmouse, PSMOUSE_IGNORE);
input_unregister_device(&psmouse->dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
kfree(psmouse);
+
+ if (parent)
+ psmouse_activate(parent);
+
+ up(&psmouse_sem);
+}
+
+static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto)
+{
+ memset(&psmouse->dev, 0, sizeof(struct input_dev));
+
+ init_input_dev(&psmouse->dev);
+
+ psmouse->dev.private = psmouse;
+ psmouse->dev.dev = &psmouse->ps2dev.serio->dev;
+
+ psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+ psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+
+ psmouse->set_rate = psmouse_set_rate;
+ psmouse->set_resolution = psmouse_set_resolution;
+ psmouse->protocol_handler = psmouse_process_byte;
+ psmouse->pktsize = 3;
+
+ if (proto && (proto->detect || proto->init)) {
+ if (proto->detect && proto->detect(psmouse, 1) < 0)
+ return -1;
+
+ if (proto->init && proto->init(psmouse) < 0)
+ return -1;
+
+ psmouse->type = proto->type;
+ }
+ else
+ psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
+
+ sprintf(psmouse->devname, "%s %s %s",
+ psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name);
+
+ psmouse->dev.name = psmouse->devname;
+ psmouse->dev.phys = psmouse->phys;
+ psmouse->dev.id.bustype = BUS_I8042;
+ psmouse->dev.id.vendor = 0x0002;
+ psmouse->dev.id.product = psmouse->type;
+ psmouse->dev.id.version = psmouse->model;
+
+ return 0;
}
/*
@@ -688,6 +870,8 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
struct psmouse *psmouse, *parent = NULL;
int retval;
+ down(&psmouse_sem);
+
/*
* If this is a pass-through port deactivate parent so the device
* connected to this port can be successfully identified
@@ -697,20 +881,14 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
psmouse_deactivate(parent);
}
- if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) {
+ if (!(psmouse = kcalloc(1, sizeof(struct psmouse), GFP_KERNEL))) {
retval = -ENOMEM;
goto out;
}
- memset(psmouse, 0, sizeof(struct psmouse));
-
ps2_init(&psmouse->ps2dev, serio);
sprintf(psmouse->phys, "%s/input0", serio->phys);
- psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
- psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
- psmouse->dev.private = psmouse;
- psmouse->dev.dev = &serio->dev;
+
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
serio_set_drvdata(serio, psmouse);
@@ -734,25 +912,10 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
psmouse->resolution = psmouse_resolution;
psmouse->resetafter = psmouse_resetafter;
psmouse->smartscroll = psmouse_smartscroll;
- psmouse->set_rate = psmouse_set_rate;
- psmouse->set_resolution = psmouse_set_resolution;
- psmouse->protocol_handler = psmouse_process_byte;
- psmouse->pktsize = 3;
- psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
-
- sprintf(psmouse->devname, "%s %s %s",
- psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
-
- psmouse->dev.name = psmouse->devname;
- psmouse->dev.phys = psmouse->phys;
- psmouse->dev.id.bustype = BUS_I8042;
- psmouse->dev.id.vendor = 0x0002;
- psmouse->dev.id.product = psmouse->type;
- psmouse->dev.id.version = psmouse->model;
+ psmouse_switch_protocol(psmouse, NULL);
input_register_device(&psmouse->dev);
-
printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
@@ -762,6 +925,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
if (parent && parent->pt_activate)
parent->pt_activate(parent);
+ device_create_file(&serio->dev, &psmouse_attr_protocol);
device_create_file(&serio->dev, &psmouse_attr_rate);
device_create_file(&serio->dev, &psmouse_attr_resolution);
device_create_file(&serio->dev, &psmouse_attr_resetafter);
@@ -771,10 +935,11 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
retval = 0;
out:
- /* If this is a pass-through port the parent awaits to be activated */
+ /* If this is a pass-through port the parent needs to be re-activated */
if (parent)
psmouse_activate(parent);
+ up(&psmouse_sem);
return retval;
}
@@ -791,6 +956,8 @@ static int psmouse_reconnect(struct serio *serio)
return -1;
}
+ down(&psmouse_sem);
+
if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
parent = serio_get_drvdata(serio->parent);
psmouse_deactivate(parent);
@@ -823,6 +990,7 @@ out:
if (parent)
psmouse_activate(parent);
+ up(&psmouse_sem);
return rc;
}
@@ -893,26 +1061,109 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun
if (serio->drv != &psmouse_drv) {
retval = -ENODEV;
- goto out;
+ goto out_unpin;
+ }
+
+ retval = down_interruptible(&psmouse_sem);
+ if (retval)
+ goto out_unpin;
+
+ if (psmouse->state == PSMOUSE_IGNORE) {
+ retval = -ENODEV;
+ goto out_up;
}
if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
parent = serio_get_drvdata(serio->parent);
psmouse_deactivate(parent);
}
+
psmouse_deactivate(psmouse);
retval = handler(psmouse, buf, count);
- psmouse_activate(psmouse);
+ if (retval != -ENODEV)
+ psmouse_activate(psmouse);
+
if (parent)
psmouse_activate(parent);
-out:
+ out_up:
+ up(&psmouse_sem);
+ out_unpin:
serio_unpin_driver(serio);
return retval;
}
+static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, char *buf)
+{
+ return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name);
+}
+
+static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *buf, size_t count)
+{
+ struct serio *serio = psmouse->ps2dev.serio;
+ struct psmouse *parent = NULL;
+ struct psmouse_protocol *proto;
+ int retry = 0;
+
+ if (!(proto = psmouse_protocol_by_name(buf, count)))
+ return -EINVAL;
+
+ if (psmouse->type == proto->type)
+ return count;
+
+ while (serio->child) {
+ if (++retry > 3) {
+ printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n");
+ return -EIO;
+ }
+
+ up(&psmouse_sem);
+ serio_unpin_driver(serio);
+ serio_unregister_child_port(serio);
+ serio_pin_driver_uninterruptible(serio);
+ down(&psmouse_sem);
+
+ if (serio->drv != &psmouse_drv)
+ return -ENODEV;
+
+ if (psmouse->type == proto->type)
+ return count; /* switched by other thread */
+ }
+
+ if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+ parent = serio_get_drvdata(serio->parent);
+ if (parent->pt_deactivate)
+ parent->pt_deactivate(parent);
+ }
+
+ if (psmouse->disconnect)
+ psmouse->disconnect(psmouse);
+
+ psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+ input_unregister_device(&psmouse->dev);
+
+ psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
+
+ if (psmouse_switch_protocol(psmouse, proto) < 0) {
+ psmouse_reset(psmouse);
+ /* default to PSMOUSE_PS2 */
+ psmouse_switch_protocol(psmouse, &psmouse_protocols[0]);
+ }
+
+ psmouse_initialize(psmouse);
+ psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+
+ input_register_device(&psmouse->dev);
+ printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
+
+ if (parent && parent->pt_activate)
+ parent->pt_activate(parent);
+
+ return count;
+}
+
static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf)
{
return sprintf(buf, "%d\n", psmouse->rate);
@@ -969,34 +1220,26 @@ static ssize_t psmouse_attr_set_resetafter(struct psmouse *psmouse, const char *
static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
{
- int i;
+ struct psmouse_protocol *proto;
if (!val)
return -EINVAL;
- if (!strncmp(val, "any", 3)) {
- *((unsigned int *)kp->arg) = -1U;
- return 0;
- }
+ proto = psmouse_protocol_by_name(val, strlen(val));
- for (i = 0; i < ARRAY_SIZE(psmouse_proto_abbrev); i++) {
- if (!psmouse_proto_abbrev[i])
- continue;
+ if (!proto || !proto->maxproto)
+ return -EINVAL;
- if (!strncmp(val, psmouse_proto_abbrev[i], strlen(psmouse_proto_abbrev[i]))) {
- *((unsigned int *)kp->arg) = i;
- return 0;
- }
- }
+ *((unsigned int *)kp->arg) = proto->type;
- return -EINVAL; \
+ return 0; \
}
static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
{
- return sprintf(buffer, "%s\n",
- psmouse_max_proto < ARRAY_SIZE(psmouse_proto_abbrev) ?
- psmouse_proto_abbrev[psmouse_max_proto] : "any");
+ int type = *((unsigned int *)kp->arg);
+
+ return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name);
}
static int __init psmouse_init(void)
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 79e17a0c466..86691cf4343 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -77,6 +77,8 @@ enum psmouse_type {
PSMOUSE_IMEX,
PSMOUSE_SYNAPTICS,
PSMOUSE_ALPS,
+ PSMOUSE_LIFEBOOK,
+ PSMOUSE_AUTO /* This one should always be last */
};
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
@@ -99,7 +101,7 @@ static ssize_t psmouse_do_set_##_name(struct device *d, struct device_attribute
{ \
return psmouse_attr_set_helper(d, b, s, psmouse_attr_set_##_name); \
} \
-static struct device_attribute psmouse_attr_##_name = \
+static struct device_attribute psmouse_attr_##_name = \
__ATTR(_name, S_IWUSR | S_IRUGO, \
psmouse_do_show_##_name, psmouse_do_set_##_name);
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
index 7280f68afce..8fe1212b8fd 100644
--- a/drivers/input/mouse/rpcmouse.c
+++ b/drivers/input/mouse/rpcmouse.c
@@ -59,7 +59,7 @@ static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
b = (short) (__raw_readl(0xe0310000) ^ 0x70);
dx = x - rpcmouse_lastx;
- dy = y - rpcmouse_lasty;
+ dy = y - rpcmouse_lasty;
rpcmouse_lastx = x;
rpcmouse_lasty = y;
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
index b2cb101c811..f024be9b44d 100644
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -1,7 +1,7 @@
/*
* Driver for DEC VSXXX-AA mouse (hockey-puck mouse, ball or two rollers)
- * DEC VSXXX-GA mouse (rectangular mouse, with ball)
- * DEC VSXXX-AB tablet (digitizer with hair cross or stylus)
+ * DEC VSXXX-GA mouse (rectangular mouse, with ball)
+ * DEC VSXXX-AB tablet (digitizer with hair cross or stylus)
*
* Copyright (C) 2003-2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
*
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 062848ac7e6..c6194a9dd17 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -220,6 +220,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
struct mousedev_list *list;
struct mousedev_motion *p;
unsigned long flags;
+ int wake_readers = 0;
list_for_each_entry(list, &mousedev->list, node) {
spin_lock_irqsave(&list->packet_lock, flags);
@@ -255,11 +256,14 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
spin_unlock_irqrestore(&list->packet_lock, flags);
- if (list->ready)
+ if (list->ready) {
kill_fasync(&list->fasync, SIGIO, POLL_IN);
+ wake_readers = 1;
+ }
}
- wake_up_interruptible(&mousedev->wait);
+ if (wake_readers)
+ wake_up_interruptible(&mousedev->wait);
}
static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index c978657068c..d4c990f7c85 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -29,6 +29,7 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ps2_init);
EXPORT_SYMBOL(ps2_sendbyte);
+EXPORT_SYMBOL(ps2_drain);
EXPORT_SYMBOL(ps2_command);
EXPORT_SYMBOL(ps2_schedule_command);
EXPORT_SYMBOL(ps2_handle_ack);
@@ -45,11 +46,11 @@ struct ps2work {
/*
- * ps2_sendbyte() sends a byte to the mouse, and waits for acknowledge.
- * It doesn't handle retransmission, though it could - because when there would
- * be need for retransmissions, the mouse has to be replaced anyway.
+ * ps2_sendbyte() sends a byte to the device and waits for acknowledge.
+ * It doesn't handle retransmission, though it could - because if there
+ * is a need for retransmissions device has to be replaced anyway.
*
- * ps2_sendbyte() can only be called from a process context
+ * ps2_sendbyte() can only be called from a process context.
*/
int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
@@ -72,6 +73,91 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
}
/*
+ * ps2_drain() waits for device to transmit requested number of bytes
+ * and discards them.
+ */
+
+void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout)
+{
+ if (maxbytes > sizeof(ps2dev->cmdbuf)) {
+ WARN_ON(1);
+ maxbytes = sizeof(ps2dev->cmdbuf);
+ }
+
+ down(&ps2dev->cmd_sem);
+
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags = PS2_FLAG_CMD;
+ ps2dev->cmdcnt = maxbytes;
+ serio_continue_rx(ps2dev->serio);
+
+ wait_event_timeout(ps2dev->wait,
+ !(ps2dev->flags & PS2_FLAG_CMD),
+ msecs_to_jiffies(timeout));
+ up(&ps2dev->cmd_sem);
+}
+
+/*
+ * ps2_is_keyboard_id() checks received ID byte against the list of
+ * known keyboard IDs.
+ */
+
+static inline int ps2_is_keyboard_id(char id_byte)
+{
+ static char keyboard_ids[] = {
+ 0xab, /* Regular keyboards */
+ 0xac, /* NCD Sun keyboard */
+ 0x2b, /* Trust keyboard, translated */
+ 0x5d, /* Trust keyboard */
+ 0x60, /* NMB SGI keyboard, translated */
+ 0x47, /* NMB SGI keyboard */
+ };
+
+ return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL;
+}
+
+/*
+ * ps2_adjust_timeout() is called after receiving 1st byte of command
+ * response and tries to reduce remaining timeout to speed up command
+ * completion.
+ */
+
+static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
+{
+ switch (command) {
+ case PS2_CMD_RESET_BAT:
+ /*
+ * Device has sent the first response byte after
+ * reset command, reset is thus done, so we can
+ * shorten the timeout.
+ * The next byte will come soon (keyboard) or not
+ * at all (mouse).
+ */
+ if (timeout > msecs_to_jiffies(100))
+ timeout = msecs_to_jiffies(100);
+ break;
+
+ case PS2_CMD_GETID:
+ /*
+ * If device behind the port is not a keyboard there
+ * won't be 2nd byte of ID response.
+ */
+ if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) {
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags = ps2dev->cmdcnt = 0;
+ serio_continue_rx(ps2dev->serio);
+ timeout = 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return timeout;
+}
+
+/*
* ps2_command() sends a command and its parameters to the mouse,
* then waits for the response and puts it in the param array.
*
@@ -86,6 +172,11 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
int rc = -1;
int i;
+ if (receive > sizeof(ps2dev->cmdbuf)) {
+ WARN_ON(1);
+ return -1;
+ }
+
down(&ps2dev->cmd_sem);
serio_pause_rx(ps2dev->serio);
@@ -101,10 +192,9 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
* ACKing the reset command, and so it can take a long
* time before the ACK arrrives.
*/
- if (command & 0xff)
- if (ps2_sendbyte(ps2dev, command & 0xff,
- command == PS2_CMD_RESET_BAT ? 1000 : 200))
- goto out;
+ if (ps2_sendbyte(ps2dev, command & 0xff,
+ command == PS2_CMD_RESET_BAT ? 1000 : 200))
+ goto out;
for (i = 0; i < send; i++)
if (ps2_sendbyte(ps2dev, param[i], 200))
@@ -120,33 +210,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
if (ps2dev->cmdcnt && timeout > 0) {
- if (command == PS2_CMD_RESET_BAT && timeout > msecs_to_jiffies(100)) {
- /*
- * Device has sent the first response byte
- * after a reset command, reset is thus done,
- * shorten the timeout. The next byte will come
- * soon (keyboard) or not at all (mouse).
- */
- timeout = msecs_to_jiffies(100);
- }
-
- if (command == PS2_CMD_GETID &&
- ps2dev->cmdbuf[receive - 1] != 0xab && /* Regular keyboards */
- ps2dev->cmdbuf[receive - 1] != 0xac && /* NCD Sun keyboard */
- ps2dev->cmdbuf[receive - 1] != 0x2b && /* Trust keyboard, translated */
- ps2dev->cmdbuf[receive - 1] != 0x5d && /* Trust keyboard */
- ps2dev->cmdbuf[receive - 1] != 0x60 && /* NMB SGI keyboard, translated */
- ps2dev->cmdbuf[receive - 1] != 0x47) { /* NMB SGI keyboard */
- /*
- * Device behind the port is not a keyboard
- * so we don't need to wait for the 2nd byte
- * of ID response.
- */
- serio_pause_rx(ps2dev->serio);
- ps2dev->flags = ps2dev->cmdcnt = 0;
- serio_continue_rx(ps2dev->serio);
- }
-
+ timeout = ps2_adjust_timeout(ps2dev, command, timeout);
wait_event_timeout(ps2dev->wait,
!(ps2dev->flags & PS2_FLAG_CMD), timeout);
}
@@ -160,7 +224,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
rc = 0;
-out:
+ out:
serio_pause_rx(ps2dev->serio);
ps2dev->flags = 0;
serio_continue_rx(ps2dev->serio);
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 341824c4852..f367695e69b 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -31,10 +31,9 @@
#include <linux/serio.h>
#include <linux/errno.h>
#include <linux/wait.h>
-#include <linux/completion.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
+#include <linux/kthread.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Serio abstraction core");
@@ -43,6 +42,7 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL(serio_interrupt);
EXPORT_SYMBOL(__serio_register_port);
EXPORT_SYMBOL(serio_unregister_port);
+EXPORT_SYMBOL(serio_unregister_child_port);
EXPORT_SYMBOL(__serio_unregister_port_delayed);
EXPORT_SYMBOL(__serio_register_driver);
EXPORT_SYMBOL(serio_unregister_driver);
@@ -68,6 +68,37 @@ static void serio_destroy_port(struct serio *serio);
static void serio_reconnect_port(struct serio *serio);
static void serio_disconnect_port(struct serio *serio);
+static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)
+{
+ int retval;
+
+ down(&serio->drv_sem);
+ retval = drv->connect(serio, drv);
+ up(&serio->drv_sem);
+
+ return retval;
+}
+
+static int serio_reconnect_driver(struct serio *serio)
+{
+ int retval = -1;
+
+ down(&serio->drv_sem);
+ if (serio->drv && serio->drv->reconnect)
+ retval = serio->drv->reconnect(serio);
+ up(&serio->drv_sem);
+
+ return retval;
+}
+
+static void serio_disconnect_driver(struct serio *serio)
+{
+ down(&serio->drv_sem);
+ if (serio->drv)
+ serio->drv->disconnect(serio);
+ up(&serio->drv_sem);
+}
+
static int serio_match_port(const struct serio_device_id *ids, struct serio *serio)
{
while (ids->type || ids->proto) {
@@ -91,7 +122,7 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
if (serio_match_port(drv->id_table, serio)) {
serio->dev.driver = &drv->driver;
- if (drv->connect(serio, drv)) {
+ if (serio_connect_driver(serio, drv)) {
serio->dev.driver = NULL;
goto out;
}
@@ -138,8 +169,7 @@ struct serio_event {
static DEFINE_SPINLOCK(serio_event_lock); /* protects serio_event_list */
static LIST_HEAD(serio_event_list);
static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
-static DECLARE_COMPLETION(serio_exited);
-static int serio_pid;
+static struct task_struct *serio_task;
static void serio_queue_event(void *object, struct module *owner,
enum serio_event_type event_type)
@@ -150,12 +180,12 @@ static void serio_queue_event(void *object, struct module *owner,
spin_lock_irqsave(&serio_event_lock, flags);
/*
- * Scan event list for the other events for the same serio port,
+ * Scan event list for the other events for the same serio port,
* starting with the most recent one. If event is the same we
* do not need add new one. If event is of different type we
* need to add this event and should not look further because
* we need to preseve sequence of distinct events.
- */
+ */
list_for_each_entry_reverse(event, &serio_event_list, node) {
if (event->object == object) {
if (event->type == event_type)
@@ -337,20 +367,15 @@ static struct serio *serio_get_pending_child(struct serio *parent)
static int serio_thread(void *nothing)
{
- lock_kernel();
- daemonize("kseriod");
- allow_signal(SIGTERM);
-
do {
serio_handle_events();
- wait_event_interruptible(serio_wait, !list_empty(&serio_event_list));
+ wait_event_interruptible(serio_wait,
+ kthread_should_stop() || !list_empty(&serio_event_list));
try_to_freeze();
- } while (!signal_pending(current));
+ } while (!kthread_should_stop());
printk(KERN_DEBUG "serio: kseriod exiting\n");
-
- unlock_kernel();
- complete_and_exit(&serio_exited, 0);
+ return 0;
}
@@ -557,7 +582,7 @@ static void serio_destroy_port(struct serio *serio)
static void serio_reconnect_port(struct serio *serio)
{
do {
- if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
+ if (serio_reconnect_driver(serio)) {
serio_disconnect_port(serio);
serio_find_driver(serio);
/* Ok, old children are now gone, we are done */
@@ -630,6 +655,19 @@ void serio_unregister_port(struct serio *serio)
}
/*
+ * Safely unregisters child port if one is present.
+ */
+void serio_unregister_child_port(struct serio *serio)
+{
+ down(&serio_sem);
+ if (serio->child) {
+ serio_disconnect_port(serio->child);
+ serio_destroy_port(serio->child);
+ }
+ up(&serio_sem);
+}
+
+/*
* Submits register request to kseriod for subsequent execution.
* Can be used when it is not obvious whether the serio_sem is
* taken or not and when delayed execution is feasible.
@@ -686,15 +724,14 @@ static int serio_driver_probe(struct device *dev)
struct serio *serio = to_serio_port(dev);
struct serio_driver *drv = to_serio_driver(dev->driver);
- return drv->connect(serio, drv);
+ return serio_connect_driver(serio, drv);
}
static int serio_driver_remove(struct device *dev)
{
struct serio *serio = to_serio_port(dev);
- struct serio_driver *drv = to_serio_driver(dev->driver);
- drv->disconnect(serio);
+ serio_disconnect_driver(serio);
return 0;
}
@@ -730,11 +767,9 @@ start_over:
static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
{
- down(&serio->drv_sem);
serio_pause_rx(serio);
serio->drv = drv;
serio_continue_rx(serio);
- up(&serio->drv_sem);
}
static int serio_bus_match(struct device *dev, struct device_driver *drv)
@@ -794,7 +829,7 @@ static int serio_resume(struct device *dev)
{
struct serio *serio = to_serio_port(dev);
- if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
+ if (serio_reconnect_driver(serio)) {
/*
* Driver re-probing can take a while, so better let kseriod
* deal with it.
@@ -848,9 +883,10 @@ irqreturn_t serio_interrupt(struct serio *serio,
static int __init serio_init(void)
{
- if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) {
+ serio_task = kthread_run(serio_thread, NULL, "kseriod");
+ if (IS_ERR(serio_task)) {
printk(KERN_ERR "serio: Failed to start kseriod\n");
- return -1;
+ return PTR_ERR(serio_task);
}
serio_bus.dev_attrs = serio_device_attrs;
@@ -866,8 +902,7 @@ static int __init serio_init(void)
static void __exit serio_exit(void)
{
bus_unregister(&serio_bus);
- kill_proc(serio_pid, SIGTERM, 1);
- wait_for_completion(&serio_exited);
+ kthread_stop(serio_task);
}
module_init(serio_init);
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index 546ce599334..3cdc9cab688 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -226,7 +226,7 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
input_set_abs_params(&elo->dev, ABS_Y, 96, 4000, 0, 0);
input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 255, 0, 0);
break;
-
+
case 1: /* 6-byte protocol */
input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 15, 0, 0);
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
index acb9137a022..bcfa1e36f95 100644
--- a/drivers/input/touchscreen/h3600_ts_input.c
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -89,9 +89,9 @@ MODULE_LICENSE("GPL");
#define H3600_SCANCODE_Q 4 /* 4 -> Q button */
#define H3600_SCANCODE_START 5 /* 5 -> start menu */
#define H3600_SCANCODE_UP 6 /* 6 -> up */
-#define H3600_SCANCODE_RIGHT 7 /* 7 -> right */
-#define H3600_SCANCODE_LEFT 8 /* 8 -> left */
-#define H3600_SCANCODE_DOWN 9 /* 9 -> down */
+#define H3600_SCANCODE_RIGHT 7 /* 7 -> right */
+#define H3600_SCANCODE_LEFT 8 /* 8 -> left */
+#define H3600_SCANCODE_DOWN 9 /* 9 -> down */
static char *h3600_name = "H3600 TouchScreen";
@@ -113,7 +113,7 @@ struct h3600_dev {
static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
{
- int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
+ int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
struct input_dev *dev = (struct input_dev *) dev_id;
input_regs(dev, regs);
@@ -125,7 +125,7 @@ static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *
static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
{
- int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
+ int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
struct input_dev *dev = (struct input_dev *) dev_id;
/*
@@ -145,8 +145,8 @@ static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *
static int flite_brightness = 25;
enum flite_pwr {
- FLITE_PWR_OFF = 0,
- FLITE_PWR_ON = 1
+ FLITE_PWR_OFF = 0,
+ FLITE_PWR_ON = 1
};
/*
@@ -157,9 +157,9 @@ unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
struct h3600_dev *ts = dev->private;
/* Must be in this order */
- ts->serio->write(ts->serio, 1);
+ ts->serio->write(ts->serio, 1);
ts->serio->write(ts->serio, pwr);
- ts->serio->write(ts->serio, brightness);
+ ts->serio->write(ts->serio, brightness);
return 0;
}
@@ -169,26 +169,26 @@ static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req,
{
struct input_dev *dev = (struct input_dev *) data;
- switch (req) {
- case PM_SUSPEND: /* enter D1-D3 */
- suspended = 1;
- h3600_flite_power(dev, FLITE_PWR_OFF);
- break;
- case PM_BLANK:
- if (!suspended)
- h3600_flite_power(dev, FLITE_PWR_OFF);
- break;
- case PM_RESUME: /* enter D0 */
- /* same as unblank */
- case PM_UNBLANK:
- if (suspended) {
- //initSerial();
- suspended = 0;
- }
- h3600_flite_power(dev, FLITE_PWR_ON);
- break;
- }
- return 0;
+ switch (req) {
+ case PM_SUSPEND: /* enter D1-D3 */
+ suspended = 1;
+ h3600_flite_power(dev, FLITE_PWR_OFF);
+ break;
+ case PM_BLANK:
+ if (!suspended)
+ h3600_flite_power(dev, FLITE_PWR_OFF);
+ break;
+ case PM_RESUME: /* enter D0 */
+ /* same as unblank */
+ case PM_UNBLANK:
+ if (suspended) {
+ //initSerial();
+ suspended = 0;
+ }
+ h3600_flite_power(dev, FLITE_PWR_ON);
+ break;
+ }
+ return 0;
}
#endif
@@ -199,25 +199,25 @@ static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req,
*/
static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
{
- struct input_dev *dev = &ts->dev;
+ struct input_dev *dev = &ts->dev;
static int touched = 0;
int key, down = 0;
input_regs(dev, regs);
- switch (ts->event) {
- /*
- Buttons - returned as a single byte
- 7 6 5 4 3 2 1 0
- S x x x N N N N
+ switch (ts->event) {
+ /*
+ Buttons - returned as a single byte
+ 7 6 5 4 3 2 1 0
+ S x x x N N N N
- S switch state ( 0=pressed 1=released)
- x Unused.
- NNNN switch number 0-15
+ S switch state ( 0=pressed 1=released)
+ x Unused.
+ NNNN switch number 0-15
- Note: This is true for non interrupt generated key events.
- */
- case KEYBD_ID:
+ Note: This is true for non interrupt generated key events.
+ */
+ case KEYBD_ID:
down = (ts->buf[0] & 0x80) ? 0 : 1;
switch (ts->buf[0] & 0x7f) {
@@ -229,40 +229,40 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
break;
case H3600_SCANCODE_CONTACTS:
key = KEY_PROG2;
- break;
+ break;
case H3600_SCANCODE_Q:
key = KEY_Q;
- break;
+ break;
case H3600_SCANCODE_START:
key = KEY_PROG3;
- break;
+ break;
case H3600_SCANCODE_UP:
key = KEY_UP;
- break;
+ break;
case H3600_SCANCODE_RIGHT:
key = KEY_RIGHT;
- break;
+ break;
case H3600_SCANCODE_LEFT:
key = KEY_LEFT;
- break;
+ break;
case H3600_SCANCODE_DOWN:
key = KEY_DOWN;
- break;
+ break;
default:
key = 0;
}
- if (key)
- input_report_key(dev, key, down);
- break;
- /*
- * Native touchscreen event data is formatted as shown below:-
- *
- * +-------+-------+-------+-------+
- * | Xmsb | Xlsb | Ymsb | Ylsb |
- * +-------+-------+-------+-------+
- * byte 0 1 2 3
- */
- case TOUCHS_ID:
+ if (key)
+ input_report_key(dev, key, down);
+ break;
+ /*
+ * Native touchscreen event data is formatted as shown below:-
+ *
+ * +-------+-------+-------+-------+
+ * | Xmsb | Xlsb | Ymsb | Ylsb |
+ * +-------+-------+-------+-------+
+ * byte 0 1 2 3
+ */
+ case TOUCHS_ID:
if (!touched) {
input_report_key(dev, BTN_TOUCH, 1);
touched = 1;
@@ -272,19 +272,19 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
unsigned short x, y;
x = ts->buf[0]; x <<= 8; x += ts->buf[1];
- y = ts->buf[2]; y <<= 8; y += ts->buf[3];
+ y = ts->buf[2]; y <<= 8; y += ts->buf[3];
- input_report_abs(dev, ABS_X, x);
- input_report_abs(dev, ABS_Y, y);
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
} else {
- input_report_key(dev, BTN_TOUCH, 0);
+ input_report_key(dev, BTN_TOUCH, 0);
touched = 0;
}
- break;
+ break;
default:
/* Send a non input event elsewhere */
break;
- }
+ }
input_sync(dev);
}
@@ -293,7 +293,7 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
* h3600ts_event() handles events from the input module.
*/
static int h3600ts_event(struct input_dev *dev, unsigned int type,
- unsigned int code, int value)
+ unsigned int code, int value)
{
struct h3600_dev *ts = dev->private;
@@ -332,41 +332,41 @@ static int state;
static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
unsigned int flags, struct pt_regs *regs)
{
- struct h3600_dev *ts = serio_get_drvdata(serio);
+ struct h3600_dev *ts = serio_get_drvdata(serio);
/*
- * We have a new frame coming in.
- */
+ * We have a new frame coming in.
+ */
switch (state) {
case STATE_SOF:
- if (data == CHAR_SOF)
- state = STATE_ID;
+ if (data == CHAR_SOF)
+ state = STATE_ID;
break;
- case STATE_ID:
+ case STATE_ID:
ts->event = (data & 0xf0) >> 4;
ts->len = (data & 0xf);
ts->idx = 0;
if (ts->event >= MAX_ID) {
state = STATE_SOF;
- break;
+ break;
}
ts->chksum = data;
- state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
+ state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
break;
case STATE_DATA:
ts->chksum += data;
ts->buf[ts->idx]= data;
- if(++ts->idx == ts->len)
- state = STATE_EOF;
+ if (++ts->idx == ts->len)
+ state = STATE_EOF;
break;
case STATE_EOF:
- state = STATE_SOF;
- if (data == CHAR_EOF || data == ts->chksum)
+ state = STATE_SOF;
+ if (data == CHAR_EOF || data == ts->chksum)
h3600ts_process_packet(ts, regs);
- break;
- default:
- printk("Error3\n");
- break;
+ break;
+ default:
+ printk("Error3\n");
+ break;
}
return IRQ_HANDLED;
@@ -390,10 +390,10 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
init_input_dev(&ts->dev);
/* Device specific stuff */
- set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
- set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
+ set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
+ set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
- if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
+ if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
"h3600_action", &ts->dev)) {
printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
@@ -401,7 +401,7 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
return -EBUSY;
}
- if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
+ if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
"h3600_suspend", &ts->dev)) {
free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
@@ -433,7 +433,7 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
sprintf(ts->phys, "%s/input0", serio->phys);
- ts->dev.event = h3600ts_event;
+ ts->dev.event = h3600ts_event;
ts->dev.private = ts;
ts->dev.name = h3600_name;
ts->dev.phys = ts->phys;
@@ -446,8 +446,8 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
err = serio_open(serio, drv);
if (err) {
- free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
- free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
+ free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
+ free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
serio_set_drvdata(serio, NULL);
kfree(ts);
return err;
diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c
index 2d14a57a05e..afaaebe5225 100644
--- a/drivers/input/touchscreen/mk712.c
+++ b/drivers/input/touchscreen/mk712.c
@@ -17,7 +17,7 @@
* found in Gateway AOL Connected Touchpad computers.
*
* Documentation for ICS MK712 can be found at:
- * http://www.icst.com/pdf/mk712.pdf
+ * http://www.icst.com/pdf/mk712.pdf
*/
/*
@@ -77,7 +77,6 @@ MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");
#define MK712_READ_ONE_POINT 0x20
#define MK712_POWERUP 0x40
-static int mk712_used = 0;
static struct input_dev mk712_dev;
static DEFINE_SPINLOCK(mk712_lock);
@@ -130,17 +129,14 @@ static int mk712_open(struct input_dev *dev)
spin_lock_irqsave(&mk712_lock, flags);
- if (!mk712_used++) {
+ outb(0, mk712_io + MK712_CONTROL); /* Reset */
- outb(0, mk712_io + MK712_CONTROL); /* Reset */
+ outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
+ MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
+ MK712_ENABLE_PERIODIC_CONVERSIONS |
+ MK712_POWERUP, mk712_io + MK712_CONTROL);
- outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
- MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
- MK712_ENABLE_PERIODIC_CONVERSIONS |
- MK712_POWERUP, mk712_io + MK712_CONTROL);
-
- outb(10, mk712_io + MK712_RATE); /* 187 points per second */
- }
+ outb(10, mk712_io + MK712_RATE); /* 187 points per second */
spin_unlock_irqrestore(&mk712_lock, flags);
@@ -153,8 +149,7 @@ static void mk712_close(struct input_dev *dev)
spin_lock_irqsave(&mk712_lock, flags);
- if (!--mk712_used)
- outb(0, mk712_io + MK712_CONTROL);
+ outb(0, mk712_io + MK712_CONTROL);
spin_unlock_irqrestore(&mk712_lock, flags);
}
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index dc00c85e3e3..ee750e9456d 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -486,6 +486,14 @@ static int avmcs_event(event_t event, int priority,
return 0;
} /* avmcs_event */
+static struct pcmcia_device_id avmcs_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),
+ PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430),
+ PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, avmcs_ids);
+
static struct pcmcia_driver avmcs_driver = {
.owner = THIS_MODULE,
.drv = {
@@ -493,6 +501,7 @@ static struct pcmcia_driver avmcs_driver = {
},
.attach = avmcs_attach,
.detach = avmcs_detach,
+ .id_table = avmcs_ids,
};
static int __init avmcs_init(void)
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
index 663a0bf703b..67c60e04a37 100644
--- a/drivers/isdn/hisax/avma1_cs.c
+++ b/drivers/isdn/hisax/avma1_cs.c
@@ -501,6 +501,13 @@ static int avma1cs_event(event_t event, int priority,
return 0;
} /* avma1cs_event */
+static struct pcmcia_device_id avma1cs_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
+ PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids);
+
static struct pcmcia_driver avma1cs_driver = {
.owner = THIS_MODULE,
.drv = {
@@ -508,6 +515,7 @@ static struct pcmcia_driver avma1cs_driver = {
},
.attach = avma1cs_attach,
.detach = avma1cs_detach,
+ .id_table = avma1cs_ids,
};
/*====================================================================*/
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
index bfc013225f4..9146be54704 100644
--- a/drivers/isdn/hisax/elsa_cs.c
+++ b/drivers/isdn/hisax/elsa_cs.c
@@ -508,6 +508,13 @@ static int elsa_cs_event(event_t event, int priority,
return 0;
} /* elsa_cs_event */
+static struct pcmcia_device_id elsa_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257),
+ PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, elsa_ids);
+
static struct pcmcia_driver elsa_cs_driver = {
.owner = THIS_MODULE,
.drv = {
@@ -515,6 +522,7 @@ static struct pcmcia_driver elsa_cs_driver = {
},
.attach = elsa_cs_attach,
.detach = elsa_cs_detach,
+ .id_table = elsa_ids,
};
static int __init init_elsa_cs(void)
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index 44965124147..058147a6957 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -616,6 +616,18 @@ static int sedlbauer_event(event_t event, int priority,
return 0;
} /* sedlbauer_event */
+static struct pcmcia_device_id sedlbauer_ids[] = {
+ PCMCIA_DEVICE_PROD_ID1234("SEDLBAUER", "speed star II", "V 3.1", "(c) 93 - 98 cb ", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a, 0x50d4149c),
+ PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D67", 0x81fb79f5, 0xe4e9bc12, 0x397b7e90),
+ PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D98", 0x81fb79f5, 0xe4e9bc12, 0x2e5c7fce),
+ PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (C) 93-94 VK", 0x81fb79f5, 0xe4e9bc12, 0x8db143fe),
+ PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (c) 93-95 VK", 0x81fb79f5, 0xe4e9bc12, 0xb391ab4c),
+ PCMCIA_DEVICE_PROD_ID12("HST High Soft Tech GmbH", "Saphir II B", 0xd79e0b84, 0x21d083ae),
+/* PCMCIA_DEVICE_PROD_ID1234("SEDLBAUER", 0x81fb79f5), */ /* too generic*/
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, sedlbauer_ids);
+
static struct pcmcia_driver sedlbauer_driver = {
.owner = THIS_MODULE,
.drv = {
@@ -623,6 +635,7 @@ static struct pcmcia_driver sedlbauer_driver = {
},
.attach = sedlbauer_attach,
.detach = sedlbauer_detach,
+ .id_table = sedlbauer_ids,
};
static int __init init_sedlbauer_cs(void)
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
index 63e8e20c17a..107376ff5b9 100644
--- a/drivers/isdn/hisax/teles_cs.c
+++ b/drivers/isdn/hisax/teles_cs.c
@@ -489,6 +489,12 @@ static int teles_cs_event(event_t event, int priority,
return 0;
} /* teles_cs_event */
+static struct pcmcia_device_id teles_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, teles_ids);
+
static struct pcmcia_driver teles_cs_driver = {
.owner = THIS_MODULE,
.drv = {
@@ -496,6 +502,7 @@ static struct pcmcia_driver teles_cs_driver = {
},
.attach = teles_attach,
.detach = teles_detach,
+ .id_table = teles_ids,
};
static int __init init_teles_cs(void)
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 8a7117a08cf..91691a6c004 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -86,33 +86,18 @@ config PMAC_SMU
on the "SMU" system control chip which replaces the old PMU.
If you don't know, say Y.
-config PMAC_PBOOK
- bool "Power management support for PowerBooks"
- depends on ADB_PMU
- ---help---
- This provides support for putting a PowerBook to sleep; it also
- enables media bay support. Power management works on the
- PB2400/3400/3500, Wallstreet, Lombard, and Bronze PowerBook G3 and
- the Titanium Powerbook G4, as well as the iBooks. You should get
- the power management daemon, pmud, to make it work and you must have
- the /dev/pmu device (see the pmud README).
-
- Get pmud from <ftp://ftp.samba.org/pub/ppclinux/pmud/>.
-
- If you have a PowerBook, you should say Y here.
-
- You may also want to compile the dma sound driver as a module and
- have it autoloaded. The act of removing the module shuts down the
- sound hardware for more power savings.
-
-config PM
- bool
- depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK
- default y
-
config PMAC_APM_EMU
tristate "APM emulation"
- depends on PMAC_PBOOK
+ depends on PPC_PMAC && PPC32 && PM
+
+config PMAC_MEDIABAY
+ bool "Support PowerBook hotswap media bay"
+ depends on PPC_PMAC && PPC32
+ help
+ This option adds support for older PowerBook's hotswap media bay
+ that can contains batteries, floppy drives, or IDE devices. PCI
+ devices are not fully supported in the bay as I never had one to
+ try with
# made a separate option since backlight may end up beeing used
# on non-powerbook machines (but only on PMU based ones AFAIK)
@@ -126,13 +111,6 @@ config PMAC_BACKLIGHT
events; also, the PowerBook button device will be enabled so you can
change the screen brightness.
-config MAC_SERIAL
- tristate "Support for PowerMac serial ports (OBSOLETE DRIVER)"
- depends on PPC_PMAC && BROKEN
- help
- This driver is obsolete. Use CONFIG_SERIAL_PMACZILOG in
- "Character devices --> Serial drivers --> PowerMac z85c30" option.
-
config ADB_MACIO
bool "Include MacIO (CHRP) ADB driver"
depends on ADB && PPC_CHRP && !PPC_PMAC64
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index c3a4705a829..f5ae171dbfe 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -6,8 +6,7 @@
obj-$(CONFIG_PPC_PMAC) += macio_asic.o
-obj-$(CONFIG_PMAC_PBOOK) += mediabay.o
-obj-$(CONFIG_MAC_SERIAL) += macserial.o
+obj-$(CONFIG_PMAC_MEDIABAY) += mediabay.o
obj-$(CONFIG_MAC_EMUMOUSEBTN) += mac_hid.o
obj-$(CONFIG_INPUT_ADBHID) += adbhid.o
obj-$(CONFIG_ANSLCD) += ans-lcd.o
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index 493e2afa191..c0dc1e3fa58 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -90,7 +90,7 @@ static int sleepy_trackpad;
static int autopoll_devs;
int __adb_probe_sync;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
static int adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
static struct pmu_sleep_notifier adb_sleep_notifier = {
adb_notify_sleep,
@@ -320,9 +320,9 @@ int __init adb_init(void)
printk(KERN_WARNING "Warning: no ADB interface detected\n");
adb_controller = NULL;
} else {
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
pmu_register_sleep_notifier(&adb_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
#ifdef CONFIG_PPC
if (machine_is_compatible("AAPL,PowerBook1998") ||
machine_is_compatible("PowerBook1,1"))
@@ -337,7 +337,7 @@ int __init adb_init(void)
__initcall(adb_init);
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
/*
* notify clients before sleep and reset bus afterwards
*/
@@ -378,7 +378,7 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
}
return PBOOK_SLEEP_OK;
}
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
static int
do_adb_reset_bus(void)
diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c
deleted file mode 100644
index 0be3ac6cc16..00000000000
--- a/drivers/macintosh/macserial.c
+++ /dev/null
@@ -1,3036 +0,0 @@
-/*
- * macserial.c: Serial port driver for Power Macintoshes.
- *
- * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
- *
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- *
- * Receive DMA code by Takashi Oe <toe@unlserve.unl.edu>.
- *
- * $Id: macserial.c,v 1.24.2.4 1999/10/19 04:36:42 paulus Exp $
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#ifdef CONFIG_SERIAL_CONSOLE
-#include <linux/console.h>
-#endif
-#include <linux/slab.h>
-#include <linux/bitops.h>
-
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/prom.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#ifdef CONFIG_KGDB
-#include <asm/kgdb.h>
-#endif
-#include <asm/dbdma.h>
-
-#include "macserial.h"
-
-#ifdef CONFIG_PMAC_PBOOK
-static int serial_notify_sleep(struct pmu_sleep_notifier *self, int when);
-static struct pmu_sleep_notifier serial_sleep_notifier = {
- serial_notify_sleep,
- SLEEP_LEVEL_MISC,
-};
-#endif
-
-#define SUPPORT_SERIAL_DMA
-#define MACSERIAL_VERSION "2.0"
-
-/*
- * It would be nice to dynamically allocate everything that
- * depends on NUM_SERIAL, so we could support any number of
- * Z8530s, but for now...
- */
-#define NUM_SERIAL 2 /* Max number of ZS chips supported */
-#define NUM_CHANNELS (NUM_SERIAL * 2) /* 2 channels per chip */
-
-/* On PowerMacs, the hardware takes care of the SCC recovery time,
- but we need the eieio to make sure that the accesses occur
- in the order we want. */
-#define RECOVERY_DELAY eieio()
-
-static struct tty_driver *serial_driver;
-
-struct mac_zschannel zs_channels[NUM_CHANNELS];
-
-struct mac_serial zs_soft[NUM_CHANNELS];
-int zs_channels_found;
-struct mac_serial *zs_chain; /* list of all channels */
-
-struct tty_struct zs_ttys[NUM_CHANNELS];
-
-static int is_powerbook;
-
-#ifdef CONFIG_SERIAL_CONSOLE
-static struct console sercons;
-#endif
-
-#ifdef CONFIG_KGDB
-struct mac_zschannel *zs_kgdbchan;
-static unsigned char scc_inittab[] = {
- 9, 0x80, /* reset A side (CHRA) */
- 13, 0, /* set baud rate divisor */
- 12, 1,
- 14, 1, /* baud rate gen enable, src=rtxc (BRENABL) */
- 11, 0x50, /* clocks = br gen (RCBR | TCBR) */
- 5, 0x6a, /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
- 4, 0x44, /* x16 clock, 1 stop (SB1 | X16CLK)*/
- 3, 0xc1, /* rx enable, 8 bits (RxENABLE | Rx8)*/
-};
-#endif
-#define ZS_CLOCK 3686400 /* Z8530 RTxC input clock rate */
-
-/* serial subtype definitions */
-#define SERIAL_TYPE_NORMAL 1
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/*
- * Debugging.
- */
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_POWER
-#undef SERIAL_DEBUG_THROTTLE
-#undef SERIAL_DEBUG_STOP
-#undef SERIAL_DEBUG_BAUDS
-
-#define RS_STROBE_TIME 10
-#define RS_ISR_PASS_LIMIT 256
-
-#define _INLINE_ inline
-
-#ifdef SERIAL_DEBUG_OPEN
-#define OPNDBG(fmt, arg...) printk(KERN_DEBUG fmt , ## arg)
-#else
-#define OPNDBG(fmt, arg...) do { } while (0)
-#endif
-#ifdef SERIAL_DEBUG_POWER
-#define PWRDBG(fmt, arg...) printk(KERN_DEBUG fmt , ## arg)
-#else
-#define PWRDBG(fmt, arg...) do { } while (0)
-#endif
-#ifdef SERIAL_DEBUG_BAUDS
-#define BAUDBG(fmt, arg...) printk(fmt , ## arg)
-#else
-#define BAUDBG(fmt, arg...) do { } while (0)
-#endif
-
-static void probe_sccs(void);
-static void change_speed(struct mac_serial *info, struct termios *old);
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
-static int set_scc_power(struct mac_serial * info, int state);
-static int setup_scc(struct mac_serial * info);
-static void dbdma_reset(volatile struct dbdma_regs *dma);
-static void dbdma_flush(volatile struct dbdma_regs *dma);
-static irqreturn_t rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs);
-static void dma_init(struct mac_serial * info);
-static void rxdma_start(struct mac_serial * info, int curr);
-static void rxdma_to_tty(struct mac_serial * info);
-
-/*
- * 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;
-static DECLARE_MUTEX(tmp_buf_sem);
-
-
-static inline int __pmac
-serial_paranoia_check(struct mac_serial *info,
- char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
- static const char badmagic[] = KERN_WARNING
- "Warning: bad magic number for serial struct %s in %s\n";
- static const char badinfo[] = KERN_WARNING
- "Warning: null mac_serial for %s in %s\n";
-
- if (!info) {
- printk(badinfo, name, routine);
- return 1;
- }
- if (info->magic != SERIAL_MAGIC) {
- printk(badmagic, name, routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-/*
- * Reading and writing Z8530 registers.
- */
-static inline unsigned char __pmac read_zsreg(struct mac_zschannel *channel,
- unsigned char reg)
-{
- unsigned char retval;
- unsigned long flags;
-
- /*
- * We have to make this atomic.
- */
- spin_lock_irqsave(&channel->lock, flags);
- if (reg != 0) {
- *channel->control = reg;
- RECOVERY_DELAY;
- }
- retval = *channel->control;
- RECOVERY_DELAY;
- spin_unlock_irqrestore(&channel->lock, flags);
- return retval;
-}
-
-static inline void __pmac write_zsreg(struct mac_zschannel *channel,
- unsigned char reg, unsigned char value)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&channel->lock, flags);
- if (reg != 0) {
- *channel->control = reg;
- RECOVERY_DELAY;
- }
- *channel->control = value;
- RECOVERY_DELAY;
- spin_unlock_irqrestore(&channel->lock, flags);
- return;
-}
-
-static inline unsigned char __pmac read_zsdata(struct mac_zschannel *channel)
-{
- unsigned char retval;
-
- retval = *channel->data;
- RECOVERY_DELAY;
- return retval;
-}
-
-static inline void write_zsdata(struct mac_zschannel *channel,
- unsigned char value)
-{
- *channel->data = value;
- RECOVERY_DELAY;
- return;
-}
-
-static inline void load_zsregs(struct mac_zschannel *channel,
- unsigned char *regs)
-{
- ZS_CLEARERR(channel);
- ZS_CLEARFIFO(channel);
- /* Load 'em up */
- write_zsreg(channel, R4, regs[R4]);
- write_zsreg(channel, R10, regs[R10]);
- write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
- write_zsreg(channel, R5, regs[R5] & ~TxENAB);
- write_zsreg(channel, R1, regs[R1]);
- write_zsreg(channel, R9, regs[R9]);
- write_zsreg(channel, R11, regs[R11]);
- write_zsreg(channel, R12, regs[R12]);
- write_zsreg(channel, R13, regs[R13]);
- write_zsreg(channel, R14, regs[R14]);
- write_zsreg(channel, R15, regs[R15]);
- write_zsreg(channel, R3, regs[R3]);
- write_zsreg(channel, R5, regs[R5]);
- return;
-}
-
-/* Sets or clears DTR/RTS on the requested line */
-static inline void zs_rtsdtr(struct mac_serial *ss, int set)
-{
- if (set)
- ss->curregs[5] |= (RTS | DTR);
- else
- ss->curregs[5] &= ~(RTS | DTR);
- write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
- return;
-}
-
-/* Utility routines for the Zilog */
-static inline int get_zsbaud(struct mac_serial *ss)
-{
- struct mac_zschannel *channel = ss->zs_channel;
- int brg;
-
- if ((ss->curregs[R11] & TCBR) == 0) {
- /* higher rates don't use the baud rate generator */
- return (ss->curregs[R4] & X32CLK)? ZS_CLOCK/32: ZS_CLOCK/16;
- }
- /* The baud rate is split up between two 8-bit registers in
- * what is termed 'BRG time constant' format in my docs for
- * the chip, it is a function of the clk rate the chip is
- * receiving which happens to be constant.
- */
- brg = (read_zsreg(channel, 13) << 8);
- brg |= read_zsreg(channel, 12);
- return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor)));
-}
-
-/* On receive, this clears errors and the receiver interrupts */
-static inline void rs_recv_clear(struct mac_zschannel *zsc)
-{
- write_zsreg(zsc, 0, ERR_RES);
- write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
-}
-
-/*
- * Reset a Descriptor-Based DMA channel.
- */
-static void dbdma_reset(volatile struct dbdma_regs *dma)
-{
- int i;
-
- out_le32(&dma->control, (WAKE|FLUSH|PAUSE|RUN) << 16);
-
- /*
- * Yes this looks peculiar, but apparently it needs to be this
- * way on some machines. (We need to make sure the DBDMA
- * engine has actually got the write above and responded
- * to it. - paulus)
- */
- for (i = 200; i > 0; --i)
- if (ld_le32(&dma->status) & RUN)
- udelay(1);
-}
-
-/*
- * Tells a DBDMA channel to stop and write any buffered data
- * it might have to memory.
- */
-static _INLINE_ void dbdma_flush(volatile struct dbdma_regs *dma)
-{
- int i = 0;
-
- out_le32(&dma->control, (FLUSH << 16) | FLUSH);
- while (((in_le32(&dma->status) & FLUSH) != 0) && (i++ < 100))
- udelay(1);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * 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.
- *
- * - 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 mac_serial *info,
- int event)
-{
- info->event |= 1 << event;
- schedule_work(&info->tqueue);
-}
-
-/* Work out the flag value for a z8530 status value. */
-static _INLINE_ int stat_to_flag(int stat)
-{
- int flag;
-
- if (stat & Rx_OVR) {
- flag = TTY_OVERRUN;
- } else if (stat & FRM_ERR) {
- flag = TTY_FRAME;
- } else if (stat & PAR_ERR) {
- flag = TTY_PARITY;
- } else
- flag = 0;
- return flag;
-}
-
-static _INLINE_ void receive_chars(struct mac_serial *info,
- struct pt_regs *regs)
-{
- struct tty_struct *tty = info->tty;
- unsigned char ch, stat, flag;
-
- while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) != 0) {
-
- stat = read_zsreg(info->zs_channel, R1);
- ch = read_zsdata(info->zs_channel);
-
-#ifdef CONFIG_KGDB
- if (info->kgdb_channel) {
- if (ch == 0x03 || ch == '$')
- breakpoint();
- if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
- write_zsreg(info->zs_channel, 0, ERR_RES);
- return;
- }
-#endif
- if (!tty)
- continue;
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- tty_flip_buffer_push(tty);
-
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
- static int flip_buf_ovf;
- if (++flip_buf_ovf <= 1)
- printk(KERN_WARNING "FB. overflow: %d\n",
- flip_buf_ovf);
- break;
- }
- tty->flip.count++;
- {
- static int flip_max_cnt;
- if (flip_max_cnt < tty->flip.count)
- flip_max_cnt = tty->flip.count;
- }
- flag = stat_to_flag(stat);
- if (flag)
- /* reset the error indication */
- write_zsreg(info->zs_channel, 0, ERR_RES);
- *tty->flip.flag_buf_ptr++ = flag;
- *tty->flip.char_buf_ptr++ = ch;
- }
- if (tty)
- tty_flip_buffer_push(tty);
-}
-
-static void transmit_chars(struct mac_serial *info)
-{
- if ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0)
- return;
- info->tx_active = 0;
-
- if (info->x_char && !info->power_wait) {
- /* Send next char */
- write_zsdata(info->zs_channel, info->x_char);
- info->x_char = 0;
- info->tx_active = 1;
- return;
- }
-
- if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped
- || info->power_wait) {
- write_zsreg(info->zs_channel, 0, RES_Tx_P);
- return;
- }
-
- /* Send char */
- write_zsdata(info->zs_channel, info->xmit_buf[info->xmit_tail++]);
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- info->tx_active = 1;
-
- if (info->xmit_cnt < WAKEUP_CHARS)
- rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-}
-
-static void powerup_done(unsigned long data)
-{
- struct mac_serial *info = (struct mac_serial *) data;
- unsigned long flags;
-
- spin_lock_irqsave(&info->lock, flags);
- info->power_wait = 0;
- transmit_chars(info);
- spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static _INLINE_ void status_handle(struct mac_serial *info)
-{
- unsigned char status;
-
- /* Get status from Read Register 0 */
- status = read_zsreg(info->zs_channel, 0);
-
- /* Check for DCD transitions */
- if (((status ^ info->read_reg_zero) & DCD) != 0
- && info->tty && !C_CLOCAL(info->tty)) {
- if (status & DCD) {
- wake_up_interruptible(&info->open_wait);
- } else {
- if (info->tty)
- tty_hangup(info->tty);
- }
- }
-
- /* Check for CTS transitions */
- if (info->tty && C_CRTSCTS(info->tty)) {
- /*
- * For some reason, on the Power Macintosh,
- * it seems that the CTS bit is 1 when CTS is
- * *negated* and 0 when it is asserted.
- * The DCD bit doesn't seem to be inverted
- * like this.
- */
- if ((status & CTS) == 0) {
- if (info->tx_stopped) {
-#ifdef SERIAL_DEBUG_FLOW
- printk(KERN_DEBUG "CTS up\n");
-#endif
- info->tx_stopped = 0;
- if (!info->tx_active)
- transmit_chars(info);
- }
- } else {
-#ifdef SERIAL_DEBUG_FLOW
- printk(KERN_DEBUG "CTS down\n");
-#endif
- info->tx_stopped = 1;
- }
- }
-
- /* Clear status condition... */
- write_zsreg(info->zs_channel, 0, RES_EXT_INT);
- info->read_reg_zero = status;
-}
-
-static _INLINE_ void receive_special_dma(struct mac_serial *info)
-{
- unsigned char stat, flag;
- volatile struct dbdma_regs *rd = &info->rx->dma;
- int where = RX_BUF_SIZE;
-
- spin_lock(&info->rx_dma_lock);
- if ((ld_le32(&rd->status) & ACTIVE) != 0)
- dbdma_flush(rd);
- if (in_le32(&rd->cmdptr)
- == virt_to_bus(info->rx_cmds[info->rx_cbuf] + 1))
- where -= in_le16(&info->rx->res_count);
- where--;
-
- stat = read_zsreg(info->zs_channel, R1);
-
- flag = stat_to_flag(stat);
- if (flag) {
- info->rx_flag_buf[info->rx_cbuf][where] = flag;
- /* reset the error indication */
- write_zsreg(info->zs_channel, 0, ERR_RES);
- }
-
- spin_unlock(&info->rx_dma_lock);
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-static irqreturn_t rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
- struct mac_serial *info = (struct mac_serial *) dev_id;
- unsigned char zs_intreg;
- int shift;
- unsigned long flags;
- int handled = 0;
-
- if (!(info->flags & ZILOG_INITIALIZED)) {
- printk(KERN_WARNING "rs_interrupt: irq %d, port not "
- "initialized\n", irq);
- disable_irq(irq);
- return IRQ_NONE;
- }
-
- /* NOTE: The read register 3, which holds the irq status,
- * does so for both channels on each chip. Although
- * the status value itself must be read from the A
- * channel and is only valid when read from channel A.
- * Yes... broken hardware...
- */
-#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
-
- if (info->zs_chan_a == info->zs_channel)
- shift = 3; /* Channel A */
- else
- shift = 0; /* Channel B */
-
- spin_lock_irqsave(&info->lock, flags);
- for (;;) {
- zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift;
-#ifdef SERIAL_DEBUG_INTR
- printk(KERN_DEBUG "rs_interrupt: irq %d, zs_intreg 0x%x\n",
- irq, (int)zs_intreg);
-#endif
-
- if ((zs_intreg & CHAN_IRQMASK) == 0)
- break;
- handled = 1;
-
- if (zs_intreg & CHBRxIP) {
- /* If we are doing DMA, we only ask for interrupts
- on characters with errors or special conditions. */
- if (info->dma_initted)
- receive_special_dma(info);
- else
- receive_chars(info, regs);
- }
- if (zs_intreg & CHBTxIP)
- transmit_chars(info);
- if (zs_intreg & CHBEXT)
- status_handle(info);
- }
- spin_unlock_irqrestore(&info->lock, flags);
- return IRQ_RETVAL(handled);
-}
-
-/* Transmit DMA interrupt - not used at present */
-static irqreturn_t rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
- return IRQ_HANDLED;
-}
-
-/*
- * Receive DMA interrupt.
- */
-static irqreturn_t rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct mac_serial *info = (struct mac_serial *) dev_id;
- volatile struct dbdma_cmd *cd;
-
- if (!info->dma_initted)
- return IRQ_NONE;
- spin_lock(&info->rx_dma_lock);
- /* First, confirm that this interrupt is, indeed, coming */
- /* from Rx DMA */
- cd = info->rx_cmds[info->rx_cbuf] + 2;
- if ((in_le16(&cd->xfer_status) & (RUN | ACTIVE)) != (RUN | ACTIVE)) {
- spin_unlock(&info->rx_dma_lock);
- return IRQ_NONE;
- }
- if (info->rx_fbuf != RX_NO_FBUF) {
- info->rx_cbuf = info->rx_fbuf;
- if (++info->rx_fbuf == info->rx_nbuf)
- info->rx_fbuf = 0;
- if (info->rx_fbuf == info->rx_ubuf)
- info->rx_fbuf = RX_NO_FBUF;
- }
- spin_unlock(&info->rx_dma_lock);
- return IRQ_HANDLED;
-}
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * ------------------------------------------------------------
- */
-static void rs_stop(struct tty_struct *tty)
-{
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-
-#ifdef SERIAL_DEBUG_STOP
- printk(KERN_DEBUG "rs_stop %ld....\n",
- tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_stop"))
- return;
-
-#if 0
- spin_lock_irqsave(&info->lock, flags);
- if (info->curregs[5] & TxENAB) {
- info->curregs[5] &= ~TxENAB;
- info->pendregs[5] &= ~TxENAB;
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- }
- spin_unlock_irqrestore(&info->lock, flags);
-#endif
-}
-
-static void rs_start(struct tty_struct *tty)
-{
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
- unsigned long flags;
-
-#ifdef SERIAL_DEBUG_STOP
- printk(KERN_DEBUG "rs_start %ld....\n",
- tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_start"))
- return;
-
- spin_lock_irqsave(&info->lock, flags);
-#if 0
- if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) {
- info->curregs[5] |= TxENAB;
- info->pendregs[5] = info->curregs[5];
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- }
-#else
- if (info->xmit_cnt && info->xmit_buf && !info->tx_active) {
- transmit_chars(info);
- }
-#endif
- spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static void do_softint(void *private_)
-{
- struct mac_serial *info = (struct mac_serial *) private_;
- struct tty_struct *tty;
-
- tty = info->tty;
- if (!tty)
- return;
-
- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
- tty_wakeup(tty);
-}
-
-static int startup(struct mac_serial * info)
-{
- int delay;
-
- OPNDBG("startup() (ttyS%d, irq %d)\n", info->line, info->irq);
-
- if (info->flags & ZILOG_INITIALIZED) {
- OPNDBG(" -> already inited\n");
- return 0;
- }
-
- if (!info->xmit_buf) {
- info->xmit_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
- if (!info->xmit_buf)
- return -ENOMEM;
- }
-
- OPNDBG("starting up ttyS%d (irq %d)...\n", info->line, info->irq);
-
- delay = set_scc_power(info, 1);
-
- setup_scc(info);
-
- if (delay) {
- unsigned long flags;
-
- /* delay is in ms */
- spin_lock_irqsave(&info->lock, flags);
- info->power_wait = 1;
- mod_timer(&info->powerup_timer,
- jiffies + (delay * HZ + 999) / 1000);
- spin_unlock_irqrestore(&info->lock, flags);
- }
-
- OPNDBG("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq);
-
- info->flags |= ZILOG_INITIALIZED;
- enable_irq(info->irq);
- if (info->dma_initted) {
- enable_irq(info->rx_dma_irq);
- }
-
- return 0;
-}
-
-static _INLINE_ void rxdma_start(struct mac_serial * info, int curr)
-{
- volatile struct dbdma_regs *rd = &info->rx->dma;
- volatile struct dbdma_cmd *cd = info->rx_cmds[curr];
-
-//printk(KERN_DEBUG "SCC: rxdma_start\n");
-
- st_le32(&rd->cmdptr, virt_to_bus(cd));
- out_le32(&rd->control, (RUN << 16) | RUN);
-}
-
-static void rxdma_to_tty(struct mac_serial *info)
-{
- struct tty_struct *tty = info->tty;
- volatile struct dbdma_regs *rd = &info->rx->dma;
- unsigned long flags;
- int residue, available, space, do_queue;
-
- if (!tty)
- return;
-
- do_queue = 0;
- spin_lock_irqsave(&info->rx_dma_lock, flags);
-more:
- space = TTY_FLIPBUF_SIZE - tty->flip.count;
- if (!space) {
- do_queue++;
- goto out;
- }
- residue = 0;
- if (info->rx_ubuf == info->rx_cbuf) {
- if ((ld_le32(&rd->status) & ACTIVE) != 0) {
- dbdma_flush(rd);
- if (in_le32(&rd->cmdptr)
- == virt_to_bus(info->rx_cmds[info->rx_cbuf]+1))
- residue = in_le16(&info->rx->res_count);
- }
- }
- available = RX_BUF_SIZE - residue - info->rx_done_bytes;
- if (available > space)
- available = space;
- if (available) {
- memcpy(tty->flip.char_buf_ptr,
- info->rx_char_buf[info->rx_ubuf] + info->rx_done_bytes,
- available);
- memcpy(tty->flip.flag_buf_ptr,
- info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes,
- available);
- tty->flip.char_buf_ptr += available;
- tty->flip.count += available;
- tty->flip.flag_buf_ptr += available;
- memset(info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes,
- 0, available);
- info->rx_done_bytes += available;
- do_queue++;
- }
- if (info->rx_done_bytes == RX_BUF_SIZE) {
- volatile struct dbdma_cmd *cd = info->rx_cmds[info->rx_ubuf];
-
- if (info->rx_ubuf == info->rx_cbuf)
- goto out;
- /* mark rx_char_buf[rx_ubuf] free */
- st_le16(&cd->command, DBDMA_NOP);
- cd++;
- st_le32(&cd->cmd_dep, 0);
- st_le32((unsigned int *)&cd->res_count, 0);
- cd++;
- st_le16(&cd->xfer_status, 0);
-
- if (info->rx_fbuf == RX_NO_FBUF) {
- info->rx_fbuf = info->rx_ubuf;
- if (!(ld_le32(&rd->status) & ACTIVE)) {
- dbdma_reset(&info->rx->dma);
- rxdma_start(info, info->rx_ubuf);
- info->rx_cbuf = info->rx_ubuf;
- }
- }
- info->rx_done_bytes = 0;
- if (++info->rx_ubuf == info->rx_nbuf)
- info->rx_ubuf = 0;
- if (info->rx_fbuf == info->rx_ubuf)
- info->rx_fbuf = RX_NO_FBUF;
- goto more;
- }
-out:
- spin_unlock_irqrestore(&info->rx_dma_lock, flags);
- if (do_queue)
- tty_flip_buffer_push(tty);
-}
-
-static void poll_rxdma(unsigned long private_)
-{
- struct mac_serial *info = (struct mac_serial *) private_;
- unsigned long flags;
-
- rxdma_to_tty(info);
- spin_lock_irqsave(&info->rx_dma_lock, flags);
- mod_timer(&info->poll_dma_timer, RX_DMA_TIMER);
- spin_unlock_irqrestore(&info->rx_dma_lock, flags);
-}
-
-static void dma_init(struct mac_serial * info)
-{
- int i, size;
- volatile struct dbdma_cmd *cd;
- unsigned char *p;
-
- info->rx_nbuf = 8;
-
- /* various mem set up */
- size = sizeof(struct dbdma_cmd) * (3 * info->rx_nbuf + 2)
- + (RX_BUF_SIZE * 2 + sizeof(*info->rx_cmds)
- + sizeof(*info->rx_char_buf) + sizeof(*info->rx_flag_buf))
- * info->rx_nbuf;
- info->dma_priv = kmalloc(size, GFP_KERNEL | GFP_DMA);
- if (info->dma_priv == NULL)
- return;
- memset(info->dma_priv, 0, size);
-
- info->rx_cmds = (volatile struct dbdma_cmd **)info->dma_priv;
- info->rx_char_buf = (unsigned char **) (info->rx_cmds + info->rx_nbuf);
- info->rx_flag_buf = info->rx_char_buf + info->rx_nbuf;
- p = (unsigned char *) (info->rx_flag_buf + info->rx_nbuf);
- for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE)
- info->rx_char_buf[i] = p;
- for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE)
- info->rx_flag_buf[i] = p;
-
- /* a bit of DMA programming */
- cd = info->rx_cmds[0] = (volatile struct dbdma_cmd *) DBDMA_ALIGN(p);
- st_le16(&cd->command, DBDMA_NOP);
- cd++;
- st_le16(&cd->req_count, RX_BUF_SIZE);
- st_le16(&cd->command, INPUT_MORE);
- st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[0]));
- cd++;
- st_le16(&cd->req_count, 4);
- st_le16(&cd->command, STORE_WORD | INTR_ALWAYS);
- st_le32(&cd->phy_addr, virt_to_bus(cd-2));
- st_le32(&cd->cmd_dep, DBDMA_STOP);
- for (i = 1; i < info->rx_nbuf; i++) {
- info->rx_cmds[i] = ++cd;
- st_le16(&cd->command, DBDMA_NOP);
- cd++;
- st_le16(&cd->req_count, RX_BUF_SIZE);
- st_le16(&cd->command, INPUT_MORE);
- st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[i]));
- cd++;
- st_le16(&cd->req_count, 4);
- st_le16(&cd->command, STORE_WORD | INTR_ALWAYS);
- st_le32(&cd->phy_addr, virt_to_bus(cd-2));
- st_le32(&cd->cmd_dep, DBDMA_STOP);
- }
- cd++;
- st_le16(&cd->command, DBDMA_NOP | BR_ALWAYS);
- st_le32(&cd->cmd_dep, virt_to_bus(info->rx_cmds[0]));
-
- /* setup DMA to our liking */
- dbdma_reset(&info->rx->dma);
- st_le32(&info->rx->dma.intr_sel, 0x10001);
- st_le32(&info->rx->dma.br_sel, 0x10001);
- out_le32(&info->rx->dma.wait_sel, 0x10001);
-
- /* set various flags */
- info->rx_ubuf = 0;
- info->rx_cbuf = 0;
- info->rx_fbuf = info->rx_ubuf + 1;
- if (info->rx_fbuf == info->rx_nbuf)
- info->rx_fbuf = RX_NO_FBUF;
- info->rx_done_bytes = 0;
-
- /* setup polling */
- init_timer(&info->poll_dma_timer);
- info->poll_dma_timer.function = (void *)&poll_rxdma;
- info->poll_dma_timer.data = (unsigned long)info;
-
- info->dma_initted = 1;
-}
-
-/*
- * FixZeroBug....Works around a bug in the SCC receving channel.
- * Taken from Darwin code, 15 Sept. 2000 -DanM
- *
- * The following sequence prevents a problem that is seen with O'Hare ASICs
- * (most versions -- also with some Heathrow and Hydra ASICs) where a zero
- * at the input to the receiver becomes 'stuck' and locks up the receiver.
- * This problem can occur as a result of a zero bit at the receiver input
- * coincident with any of the following events:
- *
- * The SCC is initialized (hardware or software).
- * A framing error is detected.
- * The clocking option changes from synchronous or X1 asynchronous
- * clocking to X16, X32, or X64 asynchronous clocking.
- * The decoding mode is changed among NRZ, NRZI, FM0, or FM1.
- *
- * This workaround attempts to recover from the lockup condition by placing
- * the SCC in synchronous loopback mode with a fast clock before programming
- * any of the asynchronous modes.
- */
-static void fix_zero_bug_scc(struct mac_serial * info)
-{
- write_zsreg(info->zs_channel, 9,
- (info->zs_channel == info->zs_chan_a? CHRA: CHRB));
- udelay(10);
- write_zsreg(info->zs_channel, 9,
- ((info->zs_channel == info->zs_chan_a? CHRA: CHRB) | NV));
-
- write_zsreg(info->zs_channel, 4, (X1CLK | EXTSYNC));
-
- /* I think this is wrong....but, I just copying code....
- */
- write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE));
-
- write_zsreg(info->zs_channel, 5, (8 & ~TxENAB));
- write_zsreg(info->zs_channel, 9, NV); /* Didn't we already do this? */
- write_zsreg(info->zs_channel, 11, (RCBR | TCBR));
- write_zsreg(info->zs_channel, 12, 0);
- write_zsreg(info->zs_channel, 13, 0);
- write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR));
- write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR | BRENABL));
- write_zsreg(info->zs_channel, 3, (8 | RxENABLE));
- write_zsreg(info->zs_channel, 0, RES_EXT_INT);
- write_zsreg(info->zs_channel, 0, RES_EXT_INT); /* to kill some time */
-
- /* The channel should be OK now, but it is probably receiving
- * loopback garbage.
- * Switch to asynchronous mode, disable the receiver,
- * and discard everything in the receive buffer.
- */
- write_zsreg(info->zs_channel, 9, NV);
- write_zsreg(info->zs_channel, 4, PAR_ENA);
- write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE));
-
- while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV) {
- (void)read_zsreg(info->zs_channel, 8);
- write_zsreg(info->zs_channel, 0, RES_EXT_INT);
- write_zsreg(info->zs_channel, 0, ERR_RES);
- }
-}
-
-static int setup_scc(struct mac_serial * info)
-{
- unsigned long flags;
-
- OPNDBG("setting up ttyS%d SCC...\n", info->line);
-
- spin_lock_irqsave(&info->lock, flags);
-
- /* Nice buggy HW ... */
- fix_zero_bug_scc(info);
-
- /*
- * Reset the chip.
- */
- write_zsreg(info->zs_channel, 9,
- (info->zs_channel == info->zs_chan_a? CHRA: CHRB));
- udelay(10);
- write_zsreg(info->zs_channel, 9, 0);
-
- /*
- * Clear the receive FIFO.
- */
- ZS_CLEARFIFO(info->zs_channel);
- info->xmit_fifo_size = 1;
-
- /*
- * Reset DMAs
- */
- if (info->has_dma)
- dma_init(info);
-
- /*
- * Clear the interrupt registers.
- */
- write_zsreg(info->zs_channel, 0, ERR_RES);
- write_zsreg(info->zs_channel, 0, RES_H_IUS);
-
- /*
- * Turn on RTS and DTR.
- */
- if (!info->is_irda)
- zs_rtsdtr(info, 1);
-
- /*
- * Finally, enable sequencing and interrupts
- */
- if (!info->dma_initted) {
- /* interrupt on ext/status changes, all received chars,
- transmit ready */
- info->curregs[1] = (info->curregs[1] & ~0x18)
- | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
- } else {
- /* interrupt on ext/status changes, W/Req pin is
- receive DMA request */
- info->curregs[1] = (info->curregs[1] & ~(0x18 | TxINT_ENAB))
- | (EXT_INT_ENAB | WT_RDY_RT | WT_FN_RDYFN);
- write_zsreg(info->zs_channel, 1, info->curregs[1]);
- /* enable W/Req pin */
- info->curregs[1] |= WT_RDY_ENAB;
- write_zsreg(info->zs_channel, 1, info->curregs[1]);
- /* enable interrupts on transmit ready and receive errors */
- info->curregs[1] |= INT_ERR_Rx | TxINT_ENAB;
- }
- info->pendregs[1] = info->curregs[1];
- info->curregs[3] |= (RxENABLE | Rx8);
- info->pendregs[3] = info->curregs[3];
- info->curregs[5] |= (TxENAB | Tx8);
- info->pendregs[5] = info->curregs[5];
- info->curregs[9] |= (NV | MIE);
- info->pendregs[9] = info->curregs[9];
- write_zsreg(info->zs_channel, 3, info->curregs[3]);
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- write_zsreg(info->zs_channel, 9, info->curregs[9]);
-
- if (info->tty)
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
- spin_unlock_irqrestore(&info->lock, flags);
-
- /*
- * Set the speed of the serial port
- */
- change_speed(info, 0);
-
- /* Save the current value of RR0 */
- info->read_reg_zero = read_zsreg(info->zs_channel, 0);
-
- if (info->dma_initted) {
- spin_lock_irqsave(&info->rx_dma_lock, flags);
- rxdma_start(info, 0);
- info->poll_dma_timer.expires = RX_DMA_TIMER;
- add_timer(&info->poll_dma_timer);
- spin_unlock_irqrestore(&info->rx_dma_lock, flags);
- }
-
- return 0;
-}
-
-/*
- * 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 mac_serial * info)
-{
- OPNDBG("Shutting down serial port %d (irq %d)....\n", info->line,
- info->irq);
-
- if (!(info->flags & ZILOG_INITIALIZED)) {
- OPNDBG("(already shutdown)\n");
- return;
- }
-
- if (info->has_dma) {
- del_timer(&info->poll_dma_timer);
- dbdma_reset(info->tx_dma);
- dbdma_reset(&info->rx->dma);
- disable_irq(info->tx_dma_irq);
- disable_irq(info->rx_dma_irq);
- }
- disable_irq(info->irq);
-
- info->pendregs[1] = info->curregs[1] = 0;
- write_zsreg(info->zs_channel, 1, 0); /* no interrupts */
-
- info->curregs[3] &= ~RxENABLE;
- info->pendregs[3] = info->curregs[3];
- write_zsreg(info->zs_channel, 3, info->curregs[3]);
-
- info->curregs[5] &= ~TxENAB;
- if (!info->tty || C_HUPCL(info->tty))
- info->curregs[5] &= ~DTR;
- info->pendregs[5] = info->curregs[5];
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
-
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
-
- set_scc_power(info, 0);
-
- if (info->xmit_buf) {
- free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = 0;
- }
-
- if (info->has_dma && info->dma_priv) {
- kfree(info->dma_priv);
- info->dma_priv = NULL;
- info->dma_initted = 0;
- }
-
- memset(info->curregs, 0, sizeof(info->curregs));
- memset(info->pendregs, 0, sizeof(info->pendregs));
-
- info->flags &= ~ZILOG_INITIALIZED;
-}
-
-/*
- * Turn power on or off to the SCC and associated stuff
- * (port drivers, modem, IR port, etc.)
- * Returns the number of milliseconds we should wait before
- * trying to use the port.
- */
-static int set_scc_power(struct mac_serial * info, int state)
-{
- int delay = 0;
-
- if (state) {
- PWRDBG("ttyS%d: powering up hardware\n", info->line);
- pmac_call_feature(
- PMAC_FTR_SCC_ENABLE,
- info->dev_node, info->port_type, 1);
- if (info->is_internal_modem) {
- pmac_call_feature(
- PMAC_FTR_MODEM_ENABLE,
- info->dev_node, 0, 1);
- delay = 2500; /* wait for 2.5s before using */
- } else if (info->is_irda)
- mdelay(50); /* Do better here once the problems
- * with blocking have been ironed out
- */
- } else {
- /* TODO: Make that depend on a timer, don't power down
- * immediately
- */
- PWRDBG("ttyS%d: shutting down hardware\n", info->line);
- if (info->is_internal_modem) {
- PWRDBG("ttyS%d: shutting down modem\n", info->line);
- pmac_call_feature(
- PMAC_FTR_MODEM_ENABLE,
- info->dev_node, 0, 0);
- }
- pmac_call_feature(
- PMAC_FTR_SCC_ENABLE,
- info->dev_node, info->port_type, 0);
- }
- return delay;
-}
-
-static void irda_rts_pulses(struct mac_serial *info, int w)
-{
- udelay(w);
- write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);
- udelay(2);
- write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
- udelay(8);
- write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);
- udelay(4);
- write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
-}
-
-/*
- * Set the irda codec on the imac to the specified baud rate.
- */
-static void irda_setup(struct mac_serial *info)
-{
- int code, speed, t;
-
- speed = info->tty->termios->c_cflag & CBAUD;
- if (speed < B2400 || speed > B115200)
- return;
- code = 0x4d + B115200 - speed;
-
- /* disable serial interrupts and receive DMA */
- write_zsreg(info->zs_channel, 1, info->curregs[1] & ~0x9f);
-
- /* wait for transmitter to drain */
- t = 10000;
- while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0
- || (read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
- if (--t <= 0) {
- printk(KERN_ERR "transmitter didn't drain\n");
- return;
- }
- udelay(10);
- }
- udelay(100);
-
- /* set to 8 bits, no parity, 19200 baud, RTS on, DTR off */
- write_zsreg(info->zs_channel, 4, X16CLK | SB1);
- write_zsreg(info->zs_channel, 11, TCBR | RCBR);
- t = BPS_TO_BRG(19200, ZS_CLOCK/16);
- write_zsreg(info->zs_channel, 12, t);
- write_zsreg(info->zs_channel, 13, t >> 8);
- write_zsreg(info->zs_channel, 14, BRENABL);
- write_zsreg(info->zs_channel, 3, Rx8 | RxENABLE);
- write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
-
- /* set TxD low for ~104us and pulse RTS */
- udelay(1000);
- write_zsdata(info->zs_channel, 0xfe);
- irda_rts_pulses(info, 150);
- irda_rts_pulses(info, 180);
- irda_rts_pulses(info, 50);
- udelay(100);
-
- /* assert DTR, wait 30ms, talk to the chip */
- write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS | DTR);
- mdelay(30);
- while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV)
- read_zsdata(info->zs_channel);
-
- write_zsdata(info->zs_channel, 1);
- t = 1000;
- while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) {
- if (--t <= 0) {
- printk(KERN_ERR "irda_setup timed out on 1st byte\n");
- goto out;
- }
- udelay(10);
- }
- t = read_zsdata(info->zs_channel);
- if (t != 4)
- printk(KERN_ERR "irda_setup 1st byte = %x\n", t);
-
- write_zsdata(info->zs_channel, code);
- t = 1000;
- while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) {
- if (--t <= 0) {
- printk(KERN_ERR "irda_setup timed out on 2nd byte\n");
- goto out;
- }
- udelay(10);
- }
- t = read_zsdata(info->zs_channel);
- if (t != code)
- printk(KERN_ERR "irda_setup 2nd byte = %x (%x)\n", t, code);
-
- /* Drop DTR again and do some more RTS pulses */
- out:
- udelay(100);
- write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
- irda_rts_pulses(info, 80);
-
- /* We should be right to go now. We assume that load_zsregs
- will get called soon to load up the correct baud rate etc. */
- info->curregs[5] = (info->curregs[5] | RTS) & ~DTR;
- info->pendregs[5] = info->curregs[5];
-}
-
-/*
- * 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 mac_serial *info, struct termios *old_termios)
-{
- unsigned cflag;
- int bits;
- int brg, baud;
- unsigned long flags;
-
- if (!info->tty || !info->tty->termios)
- return;
-
- cflag = info->tty->termios->c_cflag;
- baud = tty_get_baud_rate(info->tty);
- if (baud == 0) {
- if (old_termios) {
- info->tty->termios->c_cflag &= ~CBAUD;
- info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
- cflag = info->tty->termios->c_cflag;
- baud = tty_get_baud_rate(info->tty);
- }
- else
- baud = info->zs_baud;
- }
- if (baud > 230400)
- baud = 230400;
- else if (baud == 0)
- baud = 38400;
-
- spin_lock_irqsave(&info->lock, flags);
- info->zs_baud = baud;
- info->clk_divisor = 16;
-
- BAUDBG(KERN_DEBUG "set speed to %d bds, ", baud);
-
- switch (baud) {
- case ZS_CLOCK/16: /* 230400 */
- info->curregs[4] = X16CLK;
- info->curregs[11] = 0;
- break;
- case ZS_CLOCK/32: /* 115200 */
- info->curregs[4] = X32CLK;
- info->curregs[11] = 0;
- break;
- default:
- info->curregs[4] = X16CLK;
- info->curregs[11] = TCBR | RCBR;
- brg = BPS_TO_BRG(baud, ZS_CLOCK/info->clk_divisor);
- info->curregs[12] = (brg & 255);
- info->curregs[13] = ((brg >> 8) & 255);
- info->curregs[14] = BRENABL;
- }
-
- /* byte size and parity */
- info->curregs[3] &= ~RxNBITS_MASK;
- info->curregs[5] &= ~TxNBITS_MASK;
- switch (cflag & CSIZE) {
- case CS5:
- info->curregs[3] |= Rx5;
- info->curregs[5] |= Tx5;
- BAUDBG("5 bits, ");
- bits = 7;
- break;
- case CS6:
- info->curregs[3] |= Rx6;
- info->curregs[5] |= Tx6;
- BAUDBG("6 bits, ");
- bits = 8;
- break;
- case CS7:
- info->curregs[3] |= Rx7;
- info->curregs[5] |= Tx7;
- BAUDBG("7 bits, ");
- bits = 9;
- break;
- case CS8:
- default: /* defaults to 8 bits */
- info->curregs[3] |= Rx8;
- info->curregs[5] |= Tx8;
- BAUDBG("8 bits, ");
- bits = 10;
- break;
- }
- info->pendregs[3] = info->curregs[3];
- info->pendregs[5] = info->curregs[5];
-
- info->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
- if (cflag & CSTOPB) {
- info->curregs[4] |= SB2;
- bits++;
- BAUDBG("2 stop, ");
- } else {
- info->curregs[4] |= SB1;
- BAUDBG("1 stop, ");
- }
- if (cflag & PARENB) {
- bits++;
- info->curregs[4] |= PAR_ENA;
- BAUDBG("parity, ");
- }
- if (!(cflag & PARODD)) {
- info->curregs[4] |= PAR_EVEN;
- }
- info->pendregs[4] = info->curregs[4];
-
- if (!(cflag & CLOCAL)) {
- if (!(info->curregs[15] & DCDIE))
- info->read_reg_zero = read_zsreg(info->zs_channel, 0);
- info->curregs[15] |= DCDIE;
- } else
- info->curregs[15] &= ~DCDIE;
- if (cflag & CRTSCTS) {
- info->curregs[15] |= CTSIE;
- if ((read_zsreg(info->zs_channel, 0) & CTS) != 0)
- info->tx_stopped = 1;
- } else {
- info->curregs[15] &= ~CTSIE;
- info->tx_stopped = 0;
- }
- info->pendregs[15] = info->curregs[15];
-
- /* Calc timeout value. This is pretty broken with high baud rates with HZ=100.
- This code would love a larger HZ and a >1 fifo size, but this is not
- a priority. The resulting value must be >HZ/2
- */
- info->timeout = ((info->xmit_fifo_size*HZ*bits) / baud);
- info->timeout += HZ/50+1; /* Add .02 seconds of slop */
-
- BAUDBG("timeout=%d/%ds, base:%d\n", (int)info->timeout, (int)HZ,
- (int)info->baud_base);
-
- /* set the irda codec to the right rate */
- if (info->is_irda)
- irda_setup(info);
-
- /* Load up the new values */
- load_zsregs(info->zs_channel, info->curregs);
-
- spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
- return;
-
- spin_lock_irqsave(&info->lock, flags);
- if (!(info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped ||
- !info->xmit_buf))
- /* Enable transmitter */
- transmit_chars(info);
- spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static int rs_write(struct tty_struct * tty,
- const unsigned char *buf, int count)
-{
- int c, ret = 0;
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_write"))
- return 0;
-
- if (!tty || !info->xmit_buf || !tmp_buf)
- return 0;
-
- while (1) {
- spin_lock_irqsave(&info->lock, flags);
- c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- if (c <= 0) {
- spin_unlock_irqrestore(&info->lock, flags);
- break;
- }
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = ((info->xmit_head + c) &
- (SERIAL_XMIT_SIZE-1));
- info->xmit_cnt += c;
- spin_unlock_irqrestore(&info->lock, flags);
- buf += c;
- count -= c;
- ret += c;
- }
- spin_lock_irqsave(&info->lock, flags);
- if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
- && !info->tx_active)
- transmit_chars(info);
- spin_unlock_irqrestore(&info->lock, flags);
- return ret;
-}
-
-static int rs_write_room(struct tty_struct *tty)
-{
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
- int ret;
-
- if (serial_paranoia_check(info, tty->name, "rs_write_room"))
- return 0;
- ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
- return ret;
-}
-
-static int rs_chars_in_buffer(struct tty_struct *tty)
-{
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
- return 0;
- return info->xmit_cnt;
-}
-
-static void rs_flush_buffer(struct tty_struct *tty)
-{
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
- return;
- spin_lock_irqsave(&info->lock, flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- spin_unlock_irqrestore(&info->lock, flags);
- tty_wakeup(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * 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 mac_serial *info = (struct mac_serial *)tty->driver_data;
- unsigned long flags;
-#ifdef SERIAL_DEBUG_THROTTLE
- printk(KERN_DEBUG "throttle %ld....\n",tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_throttle"))
- return;
-
- if (I_IXOFF(tty)) {
- spin_lock_irqsave(&info->lock, flags);
- info->x_char = STOP_CHAR(tty);
- if (!info->tx_active)
- transmit_chars(info);
- spin_unlock_irqrestore(&info->lock, flags);
- }
-
- if (C_CRTSCTS(tty)) {
- /*
- * Here we want to turn off the RTS line. On Macintoshes,
- * the external serial ports using a DIN-8 or DIN-9
- * connector only have the DTR line (which is usually
- * wired to both RTS and DTR on an external modem in
- * the cable). RTS doesn't go out to the serial port
- * socket, it acts as an output enable for the transmit
- * data line. So in this case we don't drop RTS.
- *
- * Macs with internal modems generally do have both RTS
- * and DTR wired to the modem, so in that case we do
- * drop RTS.
- */
- if (info->is_internal_modem) {
- spin_lock_irqsave(&info->lock, flags);
- info->curregs[5] &= ~RTS;
- info->pendregs[5] &= ~RTS;
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- spin_unlock_irqrestore(&info->lock, flags);
- }
- }
-
-#ifdef CDTRCTS
- if (tty->termios->c_cflag & CDTRCTS) {
- spin_lock_irqsave(&info->lock, flags);
- info->curregs[5] &= ~DTR;
- info->pendregs[5] &= ~DTR;
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- spin_unlock_irqrestore(&info->lock, flags);
- }
-#endif /* CDTRCTS */
-}
-
-static void rs_unthrottle(struct tty_struct * tty)
-{
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
- unsigned long flags;
-#ifdef SERIAL_DEBUG_THROTTLE
- printk(KERN_DEBUG "unthrottle %s: %d....\n",
- tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
- return;
-
- if (I_IXOFF(tty)) {
- spin_lock_irqsave(&info->lock, flags);
- if (info->x_char)
- info->x_char = 0;
- else {
- info->x_char = START_CHAR(tty);
- if (!info->tx_active)
- transmit_chars(info);
- }
- spin_unlock_irqrestore(&info->lock, flags);
- }
-
- if (C_CRTSCTS(tty) && info->is_internal_modem) {
- /* Assert RTS line */
- spin_lock_irqsave(&info->lock, flags);
- info->curregs[5] |= RTS;
- info->pendregs[5] |= RTS;
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- spin_unlock_irqrestore(&info->lock, flags);
- }
-
-#ifdef CDTRCTS
- if (tty->termios->c_cflag & CDTRCTS) {
- /* Assert DTR line */
- spin_lock_irqsave(&info->lock, flags);
- info->curregs[5] |= DTR;
- info->pendregs[5] |= DTR;
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- spin_unlock_irqrestore(&info->lock, flags);
- }
-#endif
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct mac_serial * info,
- struct serial_struct __user * retinfo)
-{
- struct serial_struct tmp;
-
- if (!retinfo)
- return -EFAULT;
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->line;
- tmp.port = info->port;
- tmp.irq = info->irq;
- tmp.flags = info->flags;
- tmp.baud_base = info->baud_base;
- tmp.close_delay = info->close_delay;
- tmp.closing_wait = info->closing_wait;
- tmp.custom_divisor = info->custom_divisor;
- if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
- return -EFAULT;
- return 0;
-}
-
-static int set_serial_info(struct mac_serial * info,
- struct serial_struct __user * new_info)
-{
- struct serial_struct new_serial;
- struct mac_serial old_info;
- int retval = 0;
-
- if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
- return -EFAULT;
- old_info = *info;
-
- if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.baud_base != info->baud_base) ||
- (new_serial.type != info->type) ||
- (new_serial.close_delay != info->close_delay) ||
- ((new_serial.flags & ~ZILOG_USR_MASK) !=
- (info->flags & ~ZILOG_USR_MASK)))
- return -EPERM;
- info->flags = ((info->flags & ~ZILOG_USR_MASK) |
- (new_serial.flags & ZILOG_USR_MASK));
- info->custom_divisor = new_serial.custom_divisor;
- goto check_and_exit;
- }
-
- if (info->count > 1)
- return -EBUSY;
-
- /*
- * OK, past this point, all the error checking has been done.
- * At this point, we start making changes.....
- */
-
- info->baud_base = new_serial.baud_base;
- info->flags = ((info->flags & ~ZILOG_FLAGS) |
- (new_serial.flags & ZILOG_FLAGS));
- info->type = new_serial.type;
- info->close_delay = new_serial.close_delay;
- info->closing_wait = new_serial.closing_wait;
-
-check_and_exit:
- if (info->flags & ZILOG_INITIALIZED)
- retval = setup_scc(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 mac_serial * info, unsigned int *value)
-{
- unsigned char status;
- unsigned long flags;
-
- spin_lock_irqsave(&info->lock, flags);
- status = read_zsreg(info->zs_channel, 0);
- spin_unlock_irqrestore(&info->lock, flags);
- status = (status & Tx_BUF_EMP)? TIOCSER_TEMT: 0;
- return put_user(status,value);
-}
-
-static int rs_tiocmget(struct tty_struct *tty, struct file *file)
-{
- struct mac_serial * info = (struct mac_serial *)tty->driver_data;
- unsigned char control, status;
- unsigned long flags;
-
-#ifdef CONFIG_KGDB
- if (info->kgdb_channel)
- return -ENODEV;
-#endif
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
- return -ENODEV;
-
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
-
- spin_lock_irqsave(&info->lock, flags);
- control = info->curregs[5];
- status = read_zsreg(info->zs_channel, 0);
- spin_unlock_irqrestore(&info->lock, flags);
- return ((control & RTS) ? TIOCM_RTS: 0)
- | ((control & DTR) ? TIOCM_DTR: 0)
- | ((status & DCD) ? TIOCM_CAR: 0)
- | ((status & CTS) ? 0: TIOCM_CTS);
-}
-
-static int rs_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
-{
- struct mac_serial * info = (struct mac_serial *)tty->driver_data;
- unsigned int arg, bits;
- unsigned long flags;
-
-#ifdef CONFIG_KGDB
- if (info->kgdb_channel)
- return -ENODEV;
-#endif
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
- return -ENODEV;
-
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
-
- spin_lock_irqsave(&info->lock, flags);
- if (set & TIOCM_RTS)
- info->curregs[5] |= RTS;
- if (set & TIOCM_DTR)
- info->curregs[5] |= DTR;
- if (clear & TIOCM_RTS)
- info->curregs[5] &= ~RTS;
- if (clear & TIOCM_DTR)
- info->curregs[5] &= ~DTR;
-
- info->pendregs[5] = info->curregs[5];
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- spin_unlock_irqrestore(&info->lock, flags);
- return 0;
-}
-
-/*
- * rs_break - turn transmit break condition on/off
- */
-static void rs_break(struct tty_struct *tty, int break_state)
-{
- struct mac_serial *info = (struct mac_serial *) tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_break"))
- return;
-
- spin_lock_irqsave(&info->lock, flags);
- if (break_state == -1)
- info->curregs[5] |= SND_BRK;
- else
- info->curregs[5] &= ~SND_BRK;
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static int rs_ioctl(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg)
-{
- struct mac_serial * info = (struct mac_serial *)tty->driver_data;
-
-#ifdef CONFIG_KGDB
- if (info->kgdb_channel)
- return -ENODEV;
-#endif
- if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
- return -ENODEV;
-
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT)) {
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
- }
-
- switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(info,
- (struct serial_struct __user *) arg);
- case TIOCSSERIAL:
- return set_serial_info(info,
- (struct serial_struct __user *) arg);
- case TIOCSERGETLSR: /* Get line status register */
- return get_lsr_info(info, (unsigned int *) arg);
-
- case TIOCSERGSTRUCT:
- if (copy_to_user((struct mac_serial __user *) arg,
- info, sizeof(struct mac_serial)))
- return -EFAULT;
- return 0;
-
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
-{
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
- int was_stopped;
-
- if (tty->termios->c_cflag == old_termios->c_cflag)
- return;
- was_stopped = info->tx_stopped;
-
- change_speed(info, old_termios);
-
- if (was_stopped && !info->tx_stopped) {
- tty->hw_stopped = 0;
- rs_start(tty);
- }
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- *
- * This routine is called when the serial port gets closed.
- * Wait for the last remaining data to be sent.
- * ------------------------------------------------------------
- */
-static void rs_close(struct tty_struct *tty, struct file * filp)
-{
- struct mac_serial * info = (struct mac_serial *)tty->driver_data;
- unsigned long flags;
-
- if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
- return;
-
- spin_lock_irqsave(&info->lock, flags);
-
- if (tty_hung_up_p(filp)) {
- spin_unlock_irqrestore(&info->lock, flags);
- return;
- }
-
- OPNDBG("rs_close ttyS%d, count = %d\n", info->line, info->count);
- if ((tty->count == 1) && (info->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->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(KERN_ERR "rs_close: bad serial port count; tty->count "
- "is 1, info->count is %d\n", info->count);
- info->count = 1;
- }
- if (--info->count < 0) {
- printk(KERN_ERR "rs_close: bad serial port count for "
- "ttyS%d: %d\n", info->line, info->count);
- info->count = 0;
- }
- if (info->count) {
- spin_unlock_irqrestore(&info->lock, flags);
- return;
- }
- info->flags |= ZILOG_CLOSING;
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- OPNDBG("waiting end of Tx... (timeout:%d)\n", info->closing_wait);
- tty->closing = 1;
- if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) {
- spin_unlock_irqrestore(&info->lock, flags);
- tty_wait_until_sent(tty, info->closing_wait);
- spin_lock_irqsave(&info->lock, flags);
- }
-
- /*
- * At this point we stop accepting input. To do this, we
- * disable the receiver and receive interrupts.
- */
- info->curregs[3] &= ~RxENABLE;
- info->pendregs[3] = info->curregs[3];
- write_zsreg(info->zs_channel, 3, info->curregs[3]);
- info->curregs[1] &= ~(0x18); /* disable any rx ints */
- info->pendregs[1] = info->curregs[1];
- write_zsreg(info->zs_channel, 1, info->curregs[1]);
- ZS_CLEARFIFO(info->zs_channel);
- if (info->flags & ZILOG_INITIALIZED) {
- /*
- * Before we drop DTR, make sure the SCC transmitter
- * has completely drained.
- */
- OPNDBG("waiting end of Rx...\n");
- spin_unlock_irqrestore(&info->lock, flags);
- rs_wait_until_sent(tty, info->timeout);
- spin_lock_irqsave(&info->lock, flags);
- }
-
- shutdown(info);
- /* restore flags now since shutdown() will have disabled this port's
- specific irqs */
- spin_unlock_irqrestore(&info->lock, flags);
-
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- tty_ldisc_flush(tty);
- tty->closing = 0;
- info->event = 0;
- info->tty = 0;
-
- if (info->blocked_open) {
- if (info->close_delay) {
- msleep_interruptible(jiffies_to_msecs(info->close_delay));
- }
- wake_up_interruptible(&info->open_wait);
- }
- info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING);
- wake_up_interruptible(&info->close_wait);
-}
-
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
- struct mac_serial *info = (struct mac_serial *) tty->driver_data;
- unsigned long orig_jiffies, char_time;
-
- if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
- return;
-
-/* printk("rs_wait_until_sent, timeout:%d, tty_stopped:%d, tx_stopped:%d\n",
- timeout, tty->stopped, info->tx_stopped);
-*/
- 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.
- */
- if (info->timeout <= HZ/50) {
- printk(KERN_INFO "macserial: invalid info->timeout=%d\n",
- info->timeout);
- info->timeout = HZ/50+1;
- }
-
- char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
- char_time = char_time / 5;
- if (char_time > HZ) {
- printk(KERN_WARNING "macserial: char_time %ld >HZ !!!\n",
- char_time);
- char_time = 1;
- } else if (char_time == 0)
- char_time = 1;
- if (timeout)
- char_time = min_t(unsigned long, char_time, timeout);
- while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
- msleep_interruptible(jiffies_to_msecs(char_time));
- if (signal_pending(current))
- break;
- if (timeout && time_after(jiffies, orig_jiffies + timeout))
- break;
- }
- current->state = TASK_RUNNING;
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void rs_hangup(struct tty_struct *tty)
-{
- struct mac_serial * info = (struct mac_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_hangup"))
- return;
-
- rs_flush_buffer(tty);
- shutdown(info);
- info->event = 0;
- info->count = 0;
- info->flags &= ~ZILOG_NORMAL_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 mac_serial *info)
-{
- DECLARE_WAITQUEUE(wait,current);
- int retval;
- int do_clocal = 0;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (info->flags & ZILOG_CLOSING) {
- interruptible_sleep_on(&info->close_wait);
- return -EAGAIN;
- }
-
- /*
- * 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))) {
- info->flags |= ZILOG_NORMAL_ACTIVE;
- return 0;
- }
-
- 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, info->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);
- OPNDBG("block_til_ready before block: ttyS%d, count = %d\n",
- info->line, info->count);
- spin_lock_irq(&info->lock);
- if (!tty_hung_up_p(filp))
- info->count--;
- spin_unlock_irq(&info->lock);
- info->blocked_open++;
- while (1) {
- spin_lock_irq(&info->lock);
- if ((tty->termios->c_cflag & CBAUD) &&
- !info->is_irda)
- zs_rtsdtr(info, 1);
- spin_unlock_irq(&info->lock);
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(info->flags & ZILOG_INITIALIZED)) {
- retval = -EAGAIN;
- break;
- }
- if (!(info->flags & ZILOG_CLOSING) &&
- (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD)))
- break;
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- OPNDBG("block_til_ready blocking: ttyS%d, count = %d\n",
- info->line, info->count);
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp))
- info->count++;
- info->blocked_open--;
- OPNDBG("block_til_ready after blocking: ttyS%d, count = %d\n",
- info->line, info->count);
- if (retval)
- return retval;
- info->flags |= ZILOG_NORMAL_ACTIVE;
- return 0;
-}
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its ZILOG 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 mac_serial *info;
- int retval, line;
- unsigned long page;
-
- line = tty->index;
- if ((line < 0) || (line >= zs_channels_found)) {
- return -ENODEV;
- }
- info = zs_soft + line;
-
-#ifdef CONFIG_KGDB
- if (info->kgdb_channel) {
- return -ENODEV;
- }
-#endif
- if (serial_paranoia_check(info, tty->name, "rs_open"))
- return -ENODEV;
- OPNDBG("rs_open %s, count = %d, tty=%p\n", tty->name,
- info->count, tty);
-
- info->count++;
- tty->driver_data = info;
- info->tty = tty;
-
- if (!tmp_buf) {
- page = get_zeroed_page(GFP_KERNEL);
- if (!page)
- 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 & ZILOG_CLOSING)) {
- if (info->flags & ZILOG_CLOSING)
- interruptible_sleep_on(&info->close_wait);
- return -EAGAIN;
- }
-
- /*
- * Start up serial port
- */
-
- retval = startup(info);
- if (retval)
- return retval;
-
- retval = block_til_ready(tty, filp, info);
- if (retval) {
- OPNDBG("rs_open returning after block_til_ready with %d\n",
- retval);
- return retval;
- }
-
-#ifdef CONFIG_SERIAL_CONSOLE
- if (sercons.cflag && sercons.index == line) {
- tty->termios->c_cflag = sercons.cflag;
- sercons.cflag = 0;
- change_speed(info, 0);
- }
-#endif
-
- OPNDBG("rs_open %s successful...\n", tty->name);
- return 0;
-}
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void show_serial_version(void)
-{
- printk(KERN_INFO "PowerMac Z8530 serial driver version " MACSERIAL_VERSION "\n");
-}
-
-/*
- * Initialize one channel, both the mac_serial and mac_zschannel
- * structs. We use the dev_node field of the mac_serial struct.
- */
-static int
-chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan,
- struct mac_zschannel *zs_chan_a)
-{
- struct device_node *ch = zss->dev_node;
- char *conn;
- int len;
- struct slot_names_prop {
- int count;
- char name[1];
- } *slots;
-
- zss->irq = ch->intrs[0].line;
- zss->has_dma = 0;
-#if !defined(CONFIG_KGDB) && defined(SUPPORT_SERIAL_DMA)
- if (ch->n_addrs >= 3 && ch->n_intrs == 3)
- zss->has_dma = 1;
-#endif
- zss->dma_initted = 0;
-
- zs_chan->control = (volatile unsigned char *)
- ioremap(ch->addrs[0].address, 0x1000);
- zs_chan->data = zs_chan->control + 0x10;
- spin_lock_init(&zs_chan->lock);
- zs_chan->parent = zss;
- zss->zs_channel = zs_chan;
- zss->zs_chan_a = zs_chan_a;
-
- /* setup misc varariables */
- zss->kgdb_channel = 0;
-
- /* For now, we assume you either have a slot-names property
- * with "Modem" in it, or your channel is compatible with
- * "cobalt". Might need additional fixups
- */
- zss->is_internal_modem = device_is_compatible(ch, "cobalt");
- conn = get_property(ch, "AAPL,connector", &len);
- zss->is_irda = conn && (strcmp(conn, "infrared") == 0);
- zss->port_type = PMAC_SCC_ASYNC;
- /* 1999 Powerbook G3 has slot-names property instead */
- slots = (struct slot_names_prop *)get_property(ch, "slot-names", &len);
- if (slots && slots->count > 0) {
- if (strcmp(slots->name, "IrDA") == 0)
- zss->is_irda = 1;
- else if (strcmp(slots->name, "Modem") == 0)
- zss->is_internal_modem = 1;
- }
- if (zss->is_irda)
- zss->port_type = PMAC_SCC_IRDA;
- if (zss->is_internal_modem) {
- struct device_node* i2c_modem = find_devices("i2c-modem");
- if (i2c_modem) {
- char* mid = get_property(i2c_modem, "modem-id", NULL);
- if (mid) switch(*mid) {
- case 0x04 :
- case 0x05 :
- case 0x07 :
- case 0x08 :
- case 0x0b :
- case 0x0c :
- zss->port_type = PMAC_SCC_I2S1;
- }
- printk(KERN_INFO "macserial: i2c-modem detected, id: %d\n",
- mid ? (*mid) : 0);
- } else {
- printk(KERN_INFO "macserial: serial modem detected\n");
- }
- }
-
- while (zss->has_dma) {
- zss->dma_priv = NULL;
- /* it seems that the last two addresses are the
- DMA controllers */
- zss->tx_dma = (volatile struct dbdma_regs *)
- ioremap(ch->addrs[ch->n_addrs - 2].address, 0x100);
- zss->rx = (volatile struct mac_dma *)
- ioremap(ch->addrs[ch->n_addrs - 1].address, 0x100);
- zss->tx_dma_irq = ch->intrs[1].line;
- zss->rx_dma_irq = ch->intrs[2].line;
- spin_lock_init(&zss->rx_dma_lock);
- break;
- }
-
- init_timer(&zss->powerup_timer);
- zss->powerup_timer.function = powerup_done;
- zss->powerup_timer.data = (unsigned long) zss;
- return 0;
-}
-
-/*
- * /proc fs routines. TODO: Add status lines & error stats
- */
-static inline int
-line_info(char *buf, struct mac_serial *info)
-{
- int ret=0;
- unsigned char* connector;
- int lenp;
-
- ret += sprintf(buf, "%d: port:0x%X irq:%d", info->line, info->port, info->irq);
-
- connector = get_property(info->dev_node, "AAPL,connector", &lenp);
- if (connector)
- ret+=sprintf(buf+ret," con:%s ", connector);
- if (info->is_internal_modem) {
- if (!connector)
- ret+=sprintf(buf+ret," con:");
- ret+=sprintf(buf+ret,"%s", " (internal modem)");
- }
- if (info->is_irda) {
- if (!connector)
- ret+=sprintf(buf+ret," con:");
- ret+=sprintf(buf+ret,"%s", " (IrDA)");
- }
- ret+=sprintf(buf+ret,"\n");
-
- return ret;
-}
-
-int macserial_read_proc(char *page, char **start, off_t off, int count,
- int *eof, void *data)
-{
- int l, len = 0;
- off_t begin = 0;
- struct mac_serial *info;
-
- len += sprintf(page, "serinfo:1.0 driver:" MACSERIAL_VERSION "\n");
- for (info = zs_chain; info && len < 4000; info = info->zs_next) {
- l = line_info(page + len, info);
- 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);
-}
-
-/* Ask the PROM how many Z8530s we have and initialize their zs_channels */
-static void
-probe_sccs(void)
-{
- struct device_node *dev, *ch;
- struct mac_serial **pp;
- int n, chip, nchan;
- struct mac_zschannel *zs_chan;
- int chan_a_index;
-
- n = 0;
- pp = &zs_chain;
- zs_chan = zs_channels;
- for (dev = find_devices("escc"); dev != 0; dev = dev->next) {
- nchan = 0;
- chip = n;
- if (n >= NUM_CHANNELS) {
- printk(KERN_WARNING "Sorry, can't use %s: no more "
- "channels\n", dev->full_name);
- continue;
- }
- chan_a_index = 0;
- for (ch = dev->child; ch != 0; ch = ch->sibling) {
- if (nchan >= 2) {
- printk(KERN_WARNING "SCC: Only 2 channels per "
- "chip are supported\n");
- break;
- }
- if (ch->n_addrs < 1 || (ch ->n_intrs < 1)) {
- printk("Can't use %s: %d addrs %d intrs\n",
- ch->full_name, ch->n_addrs, ch->n_intrs);
- continue;
- }
-
- /* The channel with the higher address
- will be the A side. */
- if (nchan > 0 &&
- ch->addrs[0].address
- > zs_soft[n-1].dev_node->addrs[0].address)
- chan_a_index = 1;
-
- /* minimal initialization for now */
- zs_soft[n].dev_node = ch;
- *pp = &zs_soft[n];
- pp = &zs_soft[n].zs_next;
- ++nchan;
- ++n;
- }
- if (nchan == 0)
- continue;
-
- /* set up A side */
- if (chan_init(&zs_soft[chip + chan_a_index], zs_chan, zs_chan))
- continue;
- ++zs_chan;
-
- /* set up B side, if it exists */
- if (nchan > 1)
- if (chan_init(&zs_soft[chip + 1 - chan_a_index],
- zs_chan, zs_chan - 1))
- continue;
- ++zs_chan;
- }
- *pp = 0;
-
- zs_channels_found = n;
-#ifdef CONFIG_PMAC_PBOOK
- if (n)
- pmu_register_sleep_notifier(&serial_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-}
-
-static struct tty_operations serial_ops = {
- .open = rs_open,
- .close = rs_close,
- .write = rs_write,
- .flush_chars = rs_flush_chars,
- .write_room = rs_write_room,
- .chars_in_buffer = rs_chars_in_buffer,
- .flush_buffer = rs_flush_buffer,
- .ioctl = rs_ioctl,
- .throttle = rs_throttle,
- .unthrottle = rs_unthrottle,
- .set_termios = rs_set_termios,
- .stop = rs_stop,
- .start = rs_start,
- .hangup = rs_hangup,
- .break_ctl = rs_break,
- .wait_until_sent = rs_wait_until_sent,
- .read_proc = macserial_read_proc,
- .tiocmget = rs_tiocmget,
- .tiocmset = rs_tiocmset,
-};
-
-static int macserial_init(void)
-{
- int channel, i;
- struct mac_serial *info;
-
- /* Find out how many Z8530 SCCs we have */
- if (zs_chain == 0)
- probe_sccs();
-
- serial_driver = alloc_tty_driver(zs_channels_found);
- if (!serial_driver)
- return -ENOMEM;
-
- /* XXX assume it's a powerbook if we have a via-pmu
- *
- * This is OK for core99 machines as well.
- */
- is_powerbook = find_devices("via-pmu") != 0;
-
- /* Register the interrupt handler for each one
- * We also request the OF resources here as probe_sccs()
- * might be called too early for that
- */
- for (i = 0; i < zs_channels_found; ++i) {
- struct device_node* ch = zs_soft[i].dev_node;
- if (!request_OF_resource(ch, 0, NULL)) {
- printk(KERN_ERR "macserial: can't request IO resource !\n");
- put_tty_driver(serial_driver);
- return -ENODEV;
- }
- if (zs_soft[i].has_dma) {
- if (!request_OF_resource(ch, ch->n_addrs - 2, " (tx dma)")) {
- printk(KERN_ERR "macserial: can't request TX DMA resource !\n");
- zs_soft[i].has_dma = 0;
- goto no_dma;
- }
- if (!request_OF_resource(ch, ch->n_addrs - 1, " (rx dma)")) {
- release_OF_resource(ch, ch->n_addrs - 2);
- printk(KERN_ERR "macserial: can't request RX DMA resource !\n");
- zs_soft[i].has_dma = 0;
- goto no_dma;
- }
- if (request_irq(zs_soft[i].tx_dma_irq, rs_txdma_irq, 0,
- "SCC-txdma", &zs_soft[i]))
- printk(KERN_ERR "macserial: can't get irq %d\n",
- zs_soft[i].tx_dma_irq);
- disable_irq(zs_soft[i].tx_dma_irq);
- if (request_irq(zs_soft[i].rx_dma_irq, rs_rxdma_irq, 0,
- "SCC-rxdma", &zs_soft[i]))
- printk(KERN_ERR "macserial: can't get irq %d\n",
- zs_soft[i].rx_dma_irq);
- disable_irq(zs_soft[i].rx_dma_irq);
- }
-no_dma:
- if (request_irq(zs_soft[i].irq, rs_interrupt, 0,
- "SCC", &zs_soft[i]))
- printk(KERN_ERR "macserial: can't get irq %d\n",
- zs_soft[i].irq);
- disable_irq(zs_soft[i].irq);
- }
-
- show_serial_version();
-
- /* Initialize the tty_driver structure */
- /* Not all of this is exactly right for us. */
-
- serial_driver->owner = THIS_MODULE;
- serial_driver->driver_name = "macserial";
- serial_driver->devfs_name = "tts/";
- serial_driver->name = "ttyS";
- serial_driver->major = TTY_MAJOR;
- serial_driver->minor_start = 64;
- 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 =
- B38400 | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(serial_driver, &serial_ops);
-
- if (tty_register_driver(serial_driver))
- printk(KERN_ERR "Error: couldn't register serial driver\n");
-
- for (channel = 0; channel < zs_channels_found; ++channel) {
-#ifdef CONFIG_KGDB
- if (zs_soft[channel].kgdb_channel) {
- kgdb_interruptible(1);
- continue;
- }
-#endif
- zs_soft[channel].clk_divisor = 16;
-/* -- we are not sure the SCC is powered ON at this point
- zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
-*/
- zs_soft[channel].zs_baud = 38400;
-
- /* If console serial line, then enable interrupts. */
- if (zs_soft[channel].is_cons) {
- printk(KERN_INFO "macserial: console line, enabling "
- "interrupt %d\n", zs_soft[channel].irq);
- panic("macserial: console not supported yet !");
- write_zsreg(zs_soft[channel].zs_channel, R1,
- (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
- write_zsreg(zs_soft[channel].zs_channel, R9,
- (NV | MIE));
- }
- }
-
- for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
- {
- unsigned char* connector;
- int lenp;
-
-#ifdef CONFIG_KGDB
- if (info->kgdb_channel) {
- continue;
- }
-#endif
- info->magic = SERIAL_MAGIC;
- info->port = (int) info->zs_channel->control;
- info->line = i;
- info->tty = 0;
- info->custom_divisor = 16;
- info->timeout = 0;
- info->close_delay = 50;
- info->closing_wait = 3000;
- info->x_char = 0;
- info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
- INIT_WORK(&info->tqueue, do_softint, info);
- spin_lock_init(&info->lock);
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- info->timeout = HZ;
- printk(KERN_INFO "tty%02d at 0x%08x (irq = %d)", info->line,
- info->port, info->irq);
- printk(" is a Z8530 ESCC");
- connector = get_property(info->dev_node, "AAPL,connector", &lenp);
- if (connector)
- printk(", port = %s", connector);
- if (info->is_internal_modem)
- printk(" (internal modem)");
- if (info->is_irda)
- printk(" (IrDA)");
- printk("\n");
- }
- tmp_buf = 0;
-
- return 0;
-}
-
-void macserial_cleanup(void)
-{
- int i;
- unsigned long flags;
- struct mac_serial *info;
-
- for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
- set_scc_power(info, 0);
- spin_lock_irqsave(&info->lock, flags);
- for (i = 0; i < zs_channels_found; ++i) {
- free_irq(zs_soft[i].irq, &zs_soft[i]);
- if (zs_soft[i].has_dma) {
- free_irq(zs_soft[i].tx_dma_irq, &zs_soft[i]);
- free_irq(zs_soft[i].rx_dma_irq, &zs_soft[i]);
- }
- release_OF_resource(zs_soft[i].dev_node, 0);
- if (zs_soft[i].has_dma) {
- struct device_node* ch = zs_soft[i].dev_node;
- release_OF_resource(ch, ch->n_addrs - 2);
- release_OF_resource(ch, ch->n_addrs - 1);
- }
- }
- spin_unlock_irqrestore(&info->lock, flags);
- tty_unregister_driver(serial_driver);
- put_tty_driver(serial_driver);
-
- if (tmp_buf) {
- free_page((unsigned long) tmp_buf);
- tmp_buf = 0;
- }
-
-#ifdef CONFIG_PMAC_PBOOK
- if (zs_channels_found)
- pmu_unregister_sleep_notifier(&serial_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-}
-
-module_init(macserial_init);
-module_exit(macserial_cleanup);
-MODULE_LICENSE("GPL");
-
-#if 0
-/*
- * register_serial and unregister_serial allows for serial ports to be
- * configured at run-time, to support PCMCIA modems.
- */
-/* PowerMac: Unused at this time, just here to make things link. */
-int register_serial(struct serial_struct *req)
-{
- return -1;
-}
-
-void unregister_serial(int line)
-{
- return;
-}
-#endif
-
-/*
- * ------------------------------------------------------------
- * Serial console driver
- * ------------------------------------------------------------
- */
-#ifdef CONFIG_SERIAL_CONSOLE
-
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- */
-static void serial_console_write(struct console *co, const char *s,
- unsigned count)
-{
- struct mac_serial *info = zs_soft + co->index;
- int i;
-
- /* Turn of interrupts and enable the transmitter. */
- write_zsreg(info->zs_channel, R1, info->curregs[1] & ~TxINT_ENAB);
- write_zsreg(info->zs_channel, R5, info->curregs[5] | TxENAB | RTS | DTR);
-
- for (i=0; i<count; i++) {
- /* Wait for the transmit buffer to empty. */
- while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0) {
- eieio();
- }
-
- write_zsdata(info->zs_channel, s[i]);
- if (s[i] == 10) {
- while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP)
- == 0)
- eieio();
-
- write_zsdata(info->zs_channel, 13);
- }
- }
-
- /* Restore the values in the registers. */
- write_zsreg(info->zs_channel, R1, info->curregs[1]);
- /* Don't disable the transmitter. */
-}
-
-static struct tty_driver *serial_driver;
-
-static struct tty_driver *serial_console_device(struct console *c, int *index)
-{
- *index = c->index;
- return serial_driver;
-}
-
-/*
- * Setup initial baud/bits/parity. 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)
-{
- struct mac_serial *info;
- int baud = 38400;
- int bits = 8;
- int parity = 'n';
- int cflag = CREAD | HUPCL | CLOCAL;
- int brg;
- char *s;
- long flags;
-
- /* Find out how many Z8530 SCCs we have */
- if (zs_chain == 0)
- probe_sccs();
-
- if (zs_chain == 0)
- return -1;
-
- /* Do we have the device asked for? */
- if (co->index >= zs_channels_found)
- return -1;
- info = zs_soft + co->index;
-
- set_scc_power(info, 1);
-
- /* Reset the channel */
- write_zsreg(info->zs_channel, R9, CHRA);
-
- 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';
- }
-
- /*
- * Now construct a cflag setting.
- */
- switch(baud) {
- case 1200:
- cflag |= B1200;
- break;
- case 2400:
- cflag |= B2400;
- break;
- case 4800:
- cflag |= B4800;
- break;
- case 9600:
- cflag |= B9600;
- break;
- case 19200:
- cflag |= B19200;
- break;
- case 57600:
- cflag |= B57600;
- break;
- case 115200:
- cflag |= B115200;
- break;
- case 38400:
- default:
- cflag |= B38400;
- break;
- }
- switch(bits) {
- case 7:
- cflag |= CS7;
- break;
- default:
- case 8:
- cflag |= CS8;
- break;
- }
- switch(parity) {
- case 'o': case 'O':
- cflag |= PARENB | PARODD;
- break;
- case 'e': case 'E':
- cflag |= PARENB;
- break;
- }
- co->cflag = cflag;
-
- spin_lock_irqsave(&info->lock, flags);
- memset(info->curregs, 0, sizeof(info->curregs));
-
- info->zs_baud = baud;
- info->clk_divisor = 16;
- switch (info->zs_baud) {
- case ZS_CLOCK/16: /* 230400 */
- info->curregs[4] = X16CLK;
- info->curregs[11] = 0;
- break;
- case ZS_CLOCK/32: /* 115200 */
- info->curregs[4] = X32CLK;
- info->curregs[11] = 0;
- break;
- default:
- info->curregs[4] = X16CLK;
- info->curregs[11] = TCBR | RCBR;
- brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
- info->curregs[12] = (brg & 255);
- info->curregs[13] = ((brg >> 8) & 255);
- info->curregs[14] = BRENABL;
- }
-
- /* byte size and parity */
- info->curregs[3] &= ~RxNBITS_MASK;
- info->curregs[5] &= ~TxNBITS_MASK;
- switch (cflag & CSIZE) {
- case CS5:
- info->curregs[3] |= Rx5;
- info->curregs[5] |= Tx5;
- break;
- case CS6:
- info->curregs[3] |= Rx6;
- info->curregs[5] |= Tx6;
- break;
- case CS7:
- info->curregs[3] |= Rx7;
- info->curregs[5] |= Tx7;
- break;
- case CS8:
- default: /* defaults to 8 bits */
- info->curregs[3] |= Rx8;
- info->curregs[5] |= Tx8;
- break;
- }
- info->curregs[5] |= TxENAB | RTS | DTR;
- info->pendregs[3] = info->curregs[3];
- info->pendregs[5] = info->curregs[5];
-
- info->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
- if (cflag & CSTOPB) {
- info->curregs[4] |= SB2;
- } else {
- info->curregs[4] |= SB1;
- }
- if (cflag & PARENB) {
- info->curregs[4] |= PAR_ENA;
- if (!(cflag & PARODD)) {
- info->curregs[4] |= PAR_EVEN;
- }
- }
- info->pendregs[4] = info->curregs[4];
-
- if (!(cflag & CLOCAL)) {
- if (!(info->curregs[15] & DCDIE))
- info->read_reg_zero = read_zsreg(info->zs_channel, 0);
- info->curregs[15] |= DCDIE;
- } else
- info->curregs[15] &= ~DCDIE;
- if (cflag & CRTSCTS) {
- info->curregs[15] |= CTSIE;
- if ((read_zsreg(info->zs_channel, 0) & CTS) != 0)
- info->tx_stopped = 1;
- } else {
- info->curregs[15] &= ~CTSIE;
- info->tx_stopped = 0;
- }
- info->pendregs[15] = info->curregs[15];
-
- /* Load up the new values */
- load_zsregs(info->zs_channel, info->curregs);
-
- spin_unlock_irqrestore(&info->lock, flags);
-
- 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.
- */
-static void __init mac_scc_console_init(void)
-{
- register_console(&sercons);
-}
-console_initcall(mac_scc_console_init);
-
-#endif /* ifdef CONFIG_SERIAL_CONSOLE */
-
-#ifdef CONFIG_KGDB
-/* These are for receiving and sending characters under the kgdb
- * source level kernel debugger.
- */
-void putDebugChar(char kgdb_char)
-{
- struct mac_zschannel *chan = zs_kgdbchan;
- while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
- udelay(5);
- write_zsdata(chan, kgdb_char);
-}
-
-char getDebugChar(void)
-{
- struct mac_zschannel *chan = zs_kgdbchan;
- while((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
- eieio(); /*barrier();*/
- return read_zsdata(chan);
-}
-
-void kgdb_interruptible(int yes)
-{
- struct mac_zschannel *chan = zs_kgdbchan;
- int one, nine;
- nine = read_zsreg(chan, 9);
- if (yes == 1) {
- one = EXT_INT_ENAB|INT_ALL_Rx;
- nine |= MIE;
- printk("turning serial ints on\n");
- } else {
- one = RxINT_DISAB;
- nine &= ~MIE;
- printk("turning serial ints off\n");
- }
- write_zsreg(chan, 1, one);
- write_zsreg(chan, 9, nine);
-}
-
-/* This sets up the serial port we're using, and turns on
- * interrupts for that channel, so kgdb is usable once we're done.
- */
-static inline void kgdb_chaninit(struct mac_zschannel *ms, int intson, int bps)
-{
- int brg;
- int i, x;
- volatile char *sccc = ms->control;
- brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
- printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg);
- for (i = 20000; i != 0; --i) {
- x = *sccc; eieio();
- }
- for (i = 0; i < sizeof(scc_inittab); ++i) {
- write_zsreg(ms, scc_inittab[i], scc_inittab[i+1]);
- i++;
- }
-}
-
-/* This is called at boot time to prime the kgdb serial debugging
- * serial line. The 'tty_num' argument is 0 for /dev/ttya and 1
- * for /dev/ttyb which is determined in setup_arch() from the
- * boot command line flags.
- * XXX at the moment probably only channel A will work
- */
-void __init zs_kgdb_hook(int tty_num)
-{
- /* Find out how many Z8530 SCCs we have */
- if (zs_chain == 0)
- probe_sccs();
-
- set_scc_power(&zs_soft[tty_num], 1);
-
- zs_kgdbchan = zs_soft[tty_num].zs_channel;
- zs_soft[tty_num].change_needed = 0;
- zs_soft[tty_num].clk_divisor = 16;
- zs_soft[tty_num].zs_baud = 38400;
- zs_soft[tty_num].kgdb_channel = 1; /* This runs kgdb */
-
- /* Turn on transmitter/receiver at 8-bits/char */
- kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
- printk("KGDB: on channel %d initialized\n", tty_num);
- set_debug_traps(); /* init stub */
-}
-#endif /* ifdef CONFIG_KGDB */
-
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * notify clients before sleep and reset bus afterwards
- */
-int
-serial_notify_sleep(struct pmu_sleep_notifier *self, int when)
-{
- int i;
-
- switch (when) {
- case PBOOK_SLEEP_REQUEST:
- case PBOOK_SLEEP_REJECT:
- break;
-
- case PBOOK_SLEEP_NOW:
- for (i=0; i<zs_channels_found; i++) {
- struct mac_serial *info = &zs_soft[i];
- if (info->flags & ZILOG_INITIALIZED) {
- shutdown(info);
- info->flags |= ZILOG_SLEEPING;
- }
- }
- break;
- case PBOOK_WAKE:
- for (i=0; i<zs_channels_found; i++) {
- struct mac_serial *info = &zs_soft[i];
- if (info->flags & ZILOG_SLEEPING) {
- info->flags &= ~ZILOG_SLEEPING;
- startup(info);
- }
- }
- break;
- }
- return PBOOK_SLEEP_OK;
-}
-#endif /* CONFIG_PMAC_PBOOK */
diff --git a/drivers/macintosh/macserial.h b/drivers/macintosh/macserial.h
deleted file mode 100644
index bade11a7a5c..00000000000
--- a/drivers/macintosh/macserial.h
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
- * macserial.h: Definitions for the Macintosh Z8530 serial driver.
- *
- * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
- *
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-#ifndef _MACSERIAL_H
-#define _MACSERIAL_H
-
-#include <linux/spinlock.h>
-
-#define NUM_ZSREGS 16
-
-struct serial_struct {
- int type;
- int line;
- int port;
- int irq;
- int flags;
- int xmit_fifo_size;
- int custom_divisor;
- int baud_base;
- unsigned short close_delay;
- char reserved_char[2];
- int hub6;
- unsigned short closing_wait; /* time to wait before closing */
- unsigned short closing_wait2; /* no longer used... */
- int reserved[4];
-};
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output. 65535 means don't wait at all.
- */
-#define ZILOG_CLOSING_WAIT_INF 0
-#define ZILOG_CLOSING_WAIT_NONE 65535
-
-/*
- * Definitions for ZILOG_struct (and serial_struct) flags field
- */
-#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
- * on the callout port */
-#define ZILOG_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
-#define ZILOG_SAK 0x0004 /* Secure Attention Key (Orange book) */
-#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
-
-#define ZILOG_SPD_MASK 0x0030
-#define ZILOG_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
-
-#define ZILOG_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
-#define ZILOG_SPD_CUST 0x0030 /* Use user-specified divisor */
-
-#define ZILOG_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
-#define ZILOG_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
-#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
-#define ZILOG_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
-#define ZILOG_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
-
-#define ZILOG_FLAGS 0x0FFF /* Possible legal ZILOG flags */
-#define ZILOG_USR_MASK 0x0430 /* Legal flags that non-privileged
- * users can set or reset */
-
-/* Internal flags used only by kernel/chr_drv/serial.c */
-#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */
-#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
-#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
-#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
-#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */
-#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */
-#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */
-#define ZILOG_SLEEPING 0x01000000 /* have shut it down for sleep */
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-/*
- * This is our internal structure for each serial port's state.
- *
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-struct mac_serial;
-
-struct mac_zschannel {
- volatile unsigned char* control;
- volatile unsigned char* data;
- spinlock_t lock;
- /* Used for debugging */
- struct mac_serial* parent;
-};
-
-struct mac_dma {
- volatile struct dbdma_regs dma;
- volatile unsigned short res_count;
- volatile unsigned short command;
- volatile unsigned int buf_addr;
-};
-
-struct mac_serial {
- struct mac_serial *zs_next; /* For IRQ servicing chain */
- struct mac_zschannel *zs_channel; /* Channel registers */
- struct mac_zschannel *zs_chan_a; /* A side registers */
- unsigned char read_reg_zero;
- struct device_node* dev_node;
- spinlock_t lock;
-
- char soft_carrier; /* Use soft carrier on this channel */
- char break_abort; /* Is serial console in, so process brk/abrt */
- char kgdb_channel; /* Kgdb is running on this channel */
- char is_cons; /* Is this our console. */
- char is_internal_modem; /* is connected to an internal modem */
- char is_irda; /* is connected to an IrDA codec */
- int port_type; /* Port type for pmac_feature */
- unsigned char tx_active; /* character is being xmitted */
- unsigned char tx_stopped; /* output is suspended */
- unsigned char power_wait; /* waiting for power-up delay to expire */
-
- /* We need to know the current clock divisor
- * to read the bps rate the chip has currently
- * loaded.
- */
- unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */
- int zs_baud;
-
- /* Current write register values */
- unsigned char curregs[NUM_ZSREGS];
-
- /* Values we need to set next opportunity */
- unsigned char pendregs[NUM_ZSREGS];
-
- char change_needed;
-
- int magic;
- int baud_base;
- int port;
- int irq;
- int flags; /* defined in tty.h */
- int type; /* UART type */
- struct tty_struct *tty;
- int read_status_mask;
- int ignore_status_mask;
- int timeout;
- int xmit_fifo_size;
- int custom_divisor;
- int x_char; /* xon/xoff character */
- int close_delay;
- unsigned short closing_wait;
- unsigned short closing_wait2;
- unsigned long event;
- unsigned long last_active;
- int line;
- int count; /* # of fd on device */
- int blocked_open; /* # of blocked opens */
- unsigned char *xmit_buf;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
- struct work_struct tqueue;
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
-
- volatile struct dbdma_regs *tx_dma;
- int tx_dma_irq;
- volatile struct dbdma_cmd *tx_cmds;
- volatile struct mac_dma *rx;
- int rx_dma_irq;
- volatile struct dbdma_cmd **rx_cmds;
- unsigned char **rx_char_buf;
- unsigned char **rx_flag_buf;
-#define RX_BUF_SIZE 256
- int rx_nbuf;
- int rx_done_bytes;
- int rx_ubuf;
- int rx_fbuf;
-#define RX_NO_FBUF (-1)
- int rx_cbuf;
- spinlock_t rx_dma_lock;
- int has_dma;
- int dma_initted;
- void *dma_priv;
- struct timer_list poll_dma_timer;
-#define RX_DMA_TIMER (jiffies + 10*HZ/1000)
-
- struct timer_list powerup_timer;
-};
-
-
-#define SERIAL_MAGIC 0x5301
-
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP 0
-
-#endif /* __KERNEL__ */
-
-/* Conversion routines to/from brg time constants from/to bits
- * per second.
- */
-#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
-#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-
-/* The Zilog register set */
-
-#define FLAG 0x7e
-
-/* Write Register 0 */
-#define R0 0 /* Register selects */
-#define R1 1
-#define R2 2
-#define R3 3
-#define R4 4
-#define R5 5
-#define R6 6
-#define R7 7
-#define R8 8
-#define R9 9
-#define R10 10
-#define R11 11
-#define R12 12
-#define R13 13
-#define R14 14
-#define R15 15
-
-#define NULLCODE 0 /* Null Code */
-#define POINT_HIGH 0x8 /* Select upper half of registers */
-#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */
-#define SEND_ABORT 0x18 /* HDLC Abort */
-#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */
-#define RES_Tx_P 0x28 /* Reset TxINT Pending */
-#define ERR_RES 0x30 /* Error Reset */
-#define RES_H_IUS 0x38 /* Reset highest IUS */
-
-#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */
-#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */
-#define RES_EOM_L 0xC0 /* Reset EOM latch */
-
-/* Write Register 1 */
-
-#define EXT_INT_ENAB 0x1 /* Ext Int Enable */
-#define TxINT_ENAB 0x2 /* Tx Int Enable */
-#define PAR_SPEC 0x4 /* Parity is special condition */
-
-#define RxINT_DISAB 0 /* Rx Int Disable */
-#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
-#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */
-#define INT_ERR_Rx 0x18 /* Int on error only */
-
-#define WT_RDY_RT 0x20 /* W/Req reflects recv if 1, xmit if 0 */
-#define WT_FN_RDYFN 0x40 /* W/Req pin is DMA request if 1, wait if 0 */
-#define WT_RDY_ENAB 0x80 /* Enable W/Req pin */
-
-/* Write Register #2 (Interrupt Vector) */
-
-/* Write Register 3 */
-
-#define RxENABLE 0x1 /* Rx Enable */
-#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
-#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
-#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
-#define ENT_HM 0x10 /* Enter Hunt Mode */
-#define AUTO_ENAB 0x20 /* Auto Enables */
-#define Rx5 0x0 /* Rx 5 Bits/Character */
-#define Rx7 0x40 /* Rx 7 Bits/Character */
-#define Rx6 0x80 /* Rx 6 Bits/Character */
-#define Rx8 0xc0 /* Rx 8 Bits/Character */
-#define RxNBITS_MASK 0xc0
-
-/* Write Register 4 */
-
-#define PAR_ENA 0x1 /* Parity Enable */
-#define PAR_EVEN 0x2 /* Parity Even/Odd* */
-
-#define SYNC_ENAB 0 /* Sync Modes Enable */
-#define SB1 0x4 /* 1 stop bit/char */
-#define SB15 0x8 /* 1.5 stop bits/char */
-#define SB2 0xc /* 2 stop bits/char */
-#define SB_MASK 0xc
-
-#define MONSYNC 0 /* 8 Bit Sync character */
-#define BISYNC 0x10 /* 16 bit sync character */
-#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */
-#define EXTSYNC 0x30 /* External Sync Mode */
-
-#define X1CLK 0x0 /* x1 clock mode */
-#define X16CLK 0x40 /* x16 clock mode */
-#define X32CLK 0x80 /* x32 clock mode */
-#define X64CLK 0xC0 /* x64 clock mode */
-#define XCLK_MASK 0xC0
-
-/* Write Register 5 */
-
-#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
-#define RTS 0x2 /* RTS */
-#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
-#define TxENAB 0x8 /* Tx Enable */
-#define SND_BRK 0x10 /* Send Break */
-#define Tx5 0x0 /* Tx 5 bits (or less)/character */
-#define Tx7 0x20 /* Tx 7 bits/character */
-#define Tx6 0x40 /* Tx 6 bits/character */
-#define Tx8 0x60 /* Tx 8 bits/character */
-#define TxNBITS_MASK 0x60
-#define DTR 0x80 /* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 7' (Some enhanced feature control) */
-#define ENEXREAD 0x40 /* Enable read of some write registers */
-
-/* Write Register 8 (transmit buffer) */
-
-/* Write Register 9 (Master interrupt control) */
-#define VIS 1 /* Vector Includes Status */
-#define NV 2 /* No Vector */
-#define DLC 4 /* Disable Lower Chain */
-#define MIE 8 /* Master Interrupt Enable */
-#define STATHI 0x10 /* Status high */
-#define NORESET 0 /* No reset on write to R9 */
-#define CHRB 0x40 /* Reset channel B */
-#define CHRA 0x80 /* Reset channel A */
-#define FHWRES 0xc0 /* Force hardware reset */
-
-/* Write Register 10 (misc control bits) */
-#define BIT6 1 /* 6 bit/8bit sync */
-#define LOOPMODE 2 /* SDLC Loop mode */
-#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */
-#define MARKIDLE 8 /* Mark/flag on idle */
-#define GAOP 0x10 /* Go active on poll */
-#define NRZ 0 /* NRZ mode */
-#define NRZI 0x20 /* NRZI mode */
-#define FM1 0x40 /* FM1 (transition = 1) */
-#define FM0 0x60 /* FM0 (transition = 0) */
-#define CRCPS 0x80 /* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode control) */
-#define TRxCXT 0 /* TRxC = Xtal output */
-#define TRxCTC 1 /* TRxC = Transmit clock */
-#define TRxCBR 2 /* TRxC = BR Generator Output */
-#define TRxCDP 3 /* TRxC = DPLL output */
-#define TRxCOI 4 /* TRxC O/I */
-#define TCRTxCP 0 /* Transmit clock = RTxC pin */
-#define TCTRxCP 8 /* Transmit clock = TRxC pin */
-#define TCBR 0x10 /* Transmit clock = BR Generator output */
-#define TCDPLL 0x18 /* Transmit clock = DPLL output */
-#define RCRTxCP 0 /* Receive clock = RTxC pin */
-#define RCTRxCP 0x20 /* Receive clock = TRxC pin */
-#define RCBR 0x40 /* Receive clock = BR Generator output */
-#define RCDPLL 0x60 /* Receive clock = DPLL output */
-#define RTxCX 0x80 /* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (lower byte of baud rate generator time constant) */
-
-/* Write Register 13 (upper byte of baud rate generator time constant) */
-
-/* Write Register 14 (Misc control bits) */
-#define BRENABL 1 /* Baud rate generator enable */
-#define BRSRC 2 /* Baud rate generator source */
-#define DTRREQ 4 /* DTR/Request function */
-#define AUTOECHO 8 /* Auto Echo */
-#define LOOPBAK 0x10 /* Local loopback */
-#define SEARCH 0x20 /* Enter search mode */
-#define RMC 0x40 /* Reset missing clock */
-#define DISDPLL 0x60 /* Disable DPLL */
-#define SSBR 0x80 /* Set DPLL source = BR generator */
-#define SSRTxC 0xa0 /* Set DPLL source = RTxC */
-#define SFMM 0xc0 /* Set FM mode */
-#define SNRZI 0xe0 /* Set NRZI mode */
-
-/* Write Register 15 (external/status interrupt control) */
-#define EN85C30 1 /* Enable some 85c30-enhanced registers */
-#define ZCIE 2 /* Zero count IE */
-#define ENSTFIFO 4 /* Enable status FIFO (SDLC) */
-#define DCDIE 8 /* DCD IE */
-#define SYNCIE 0x10 /* Sync/hunt IE */
-#define CTSIE 0x20 /* CTS IE */
-#define TxUIE 0x40 /* Tx Underrun/EOM IE */
-#define BRKIE 0x80 /* Break/Abort IE */
-
-
-/* Read Register 0 */
-#define Rx_CH_AV 0x1 /* Rx Character Available */
-#define ZCOUNT 0x2 /* Zero count */
-#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
-#define DCD 0x8 /* DCD */
-#define SYNC_HUNT 0x10 /* Sync/hunt */
-#define CTS 0x20 /* CTS */
-#define TxEOM 0x40 /* Tx underrun */
-#define BRK_ABRT 0x80 /* Break/Abort */
-
-/* Read Register 1 */
-#define ALL_SNT 0x1 /* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define RES3 0x8 /* 0/3 */
-#define RES4 0x4 /* 0/4 */
-#define RES5 0xc /* 0/5 */
-#define RES6 0x2 /* 0/6 */
-#define RES7 0xa /* 0/7 */
-#define RES8 0x6 /* 0/8 */
-#define RES18 0xe /* 1/8 */
-#define RES28 0x0 /* 2/8 */
-/* Special Rx Condition Interrupts */
-#define PAR_ERR 0x10 /* Parity error */
-#define Rx_OVR 0x20 /* Rx Overrun Error */
-#define FRM_ERR 0x40 /* CRC/Framing Error */
-#define END_FR 0x80 /* End of Frame (SDLC) */
-
-/* Read Register 2 (channel b only) - Interrupt vector */
-#define CHB_Tx_EMPTY 0x00
-#define CHB_EXT_STAT 0x02
-#define CHB_Rx_AVAIL 0x04
-#define CHB_SPECIAL 0x06
-#define CHA_Tx_EMPTY 0x08
-#define CHA_EXT_STAT 0x0a
-#define CHA_Rx_AVAIL 0x0c
-#define CHA_SPECIAL 0x0e
-#define STATUS_MASK 0x06
-
-/* Read Register 3 (interrupt pending register) ch a only */
-#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
-#define CHBTxIP 0x2 /* Channel B Tx IP */
-#define CHBRxIP 0x4 /* Channel B Rx IP */
-#define CHAEXT 0x8 /* Channel A Ext/Stat IP */
-#define CHATxIP 0x10 /* Channel A Tx IP */
-#define CHARxIP 0x20 /* Channel A Rx IP */
-
-/* Read Register 8 (receive data register) */
-
-/* Read Register 10 (misc status bits) */
-#define ONLOOP 2 /* On loop */
-#define LOOPSEND 0x10 /* Loop sending */
-#define CLK2MIS 0x40 /* Two clocks missing */
-#define CLK1MIS 0x80 /* One clock missing */
-
-/* Read Register 12 (lower byte of baud rate generator constant) */
-
-/* Read Register 13 (upper byte of baud rate generator constant) */
-
-/* Read Register 15 (value of WR 15) */
-
-/* Misc macros */
-#define ZS_CLEARERR(channel) (write_zsreg(channel, 0, ERR_RES))
-#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \
- garbage = read_zsdata(channel); \
- garbage = read_zsdata(channel); \
- garbage = read_zsdata(channel); \
- } while(0)
-
-#endif /* !(_MACSERIAL_H) */
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index b941ee22099..4a0a0ad2d03 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -63,6 +63,10 @@
#include <asm/backlight.h>
#endif
+#ifdef CONFIG_PPC32
+#include <asm/open_pic.h>
+#endif
+
/* Some compile options */
#undef SUSPEND_USES_PMU
#define DEBUG_SLEEP
@@ -151,10 +155,10 @@ static spinlock_t pmu_lock;
static u8 pmu_intr_mask;
static int pmu_version;
static int drop_interrupts;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
static int option_lid_wakeup = 1;
static int sleep_in_progress;
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
static unsigned long async_req_locks;
static unsigned int pmu_irq_stats[11];
@@ -164,7 +168,6 @@ static struct proc_dir_entry *proc_pmu_irqstats;
static struct proc_dir_entry *proc_pmu_options;
static int option_server_mode;
-#ifdef CONFIG_PMAC_PBOOK
int pmu_battery_count;
int pmu_cur_battery;
unsigned int pmu_power_flags;
@@ -172,7 +175,6 @@ struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES];
static int query_batt_timer = BATTERY_POLLING_COUNT;
static struct adb_request batt_req;
static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES];
-#endif /* CONFIG_PMAC_PBOOK */
#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
extern int disable_kernel_backlight;
@@ -206,11 +208,9 @@ static int proc_get_irqstats(char *page, char **start, off_t off,
static int pmu_set_backlight_level(int level, void* data);
static int pmu_set_backlight_enable(int on, int level, void* data);
#endif /* CONFIG_PMAC_BACKLIGHT */
-#ifdef CONFIG_PMAC_PBOOK
static void pmu_pass_intr(unsigned char *data, int len);
static int proc_get_batt(char *page, char **start, off_t off,
int count, int *eof, void *data);
-#endif /* CONFIG_PMAC_PBOOK */
static int proc_read_options(char *page, char **start, off_t off,
int count, int *eof, void *data);
static int proc_write_options(struct file *file, const char __user *buffer,
@@ -403,8 +403,12 @@ static int __init via_pmu_start(void)
bright_req_1.complete = 1;
bright_req_2.complete = 1;
-#ifdef CONFIG_PMAC_PBOOK
batt_req.complete = 1;
+
+#ifdef CONFIG_PPC32
+ if (pmu_kind == PMU_KEYLARGO_BASED)
+ openpic_set_irq_priority(vias->intrs[0].line,
+ OPENPIC_PRIORITY_DEFAULT + 1);
#endif
if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU",
@@ -458,7 +462,7 @@ static int __init via_pmu_dev_init(void)
register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
#endif /* CONFIG_PMAC_BACKLIGHT */
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PPC32
if (machine_is_compatible("AAPL,3400/2400") ||
machine_is_compatible("AAPL,3500")) {
int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
@@ -486,20 +490,19 @@ static int __init via_pmu_dev_init(void)
pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
}
}
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PPC32 */
+
/* Create /proc/pmu */
proc_pmu_root = proc_mkdir("pmu", NULL);
if (proc_pmu_root) {
-#ifdef CONFIG_PMAC_PBOOK
- int i;
+ long i;
for (i=0; i<pmu_battery_count; i++) {
char title[16];
- sprintf(title, "battery_%d", i);
+ sprintf(title, "battery_%ld", i);
proc_pmu_batt[i] = create_proc_read_entry(title, 0, proc_pmu_root,
proc_get_batt, (void *)i);
}
-#endif /* CONFIG_PMAC_PBOOK */
proc_pmu_info = create_proc_read_entry("info", 0, proc_pmu_root,
proc_get_info, NULL);
@@ -619,8 +622,6 @@ static void pmu_set_server_mode(int server_mode)
pmu_wait_complete(&req);
}
-#ifdef CONFIG_PMAC_PBOOK
-
/* This new version of the code for 2400/3400/3500 powerbooks
* is inspired from the implementation in gkrellm-pmu
*/
@@ -803,8 +804,6 @@ query_battery_state(void)
2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1);
}
-#endif /* CONFIG_PMAC_PBOOK */
-
static int __pmac
proc_get_info(char *page, char **start, off_t off,
int count, int *eof, void *data)
@@ -813,11 +812,9 @@ proc_get_info(char *page, char **start, off_t off,
p += sprintf(p, "PMU driver version : %d\n", PMU_DRIVER_VERSION);
p += sprintf(p, "PMU firmware version : %02x\n", pmu_version);
-#ifdef CONFIG_PMAC_PBOOK
p += sprintf(p, "AC Power : %d\n",
((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0));
p += sprintf(p, "Battery count : %d\n", pmu_battery_count);
-#endif /* CONFIG_PMAC_PBOOK */
return p - page;
}
@@ -849,12 +846,11 @@ proc_get_irqstats(char *page, char **start, off_t off,
return p - page;
}
-#ifdef CONFIG_PMAC_PBOOK
static int __pmac
proc_get_batt(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
- int batnum = (int)data;
+ long batnum = (long)data;
char *p = page;
p += sprintf(p, "\n");
@@ -873,7 +869,6 @@ proc_get_batt(char *page, char **start, off_t off,
return p - page;
}
-#endif /* CONFIG_PMAC_PBOOK */
static int __pmac
proc_read_options(char *page, char **start, off_t off,
@@ -881,11 +876,11 @@ proc_read_options(char *page, char **start, off_t off,
{
char *p = page;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
if (pmu_kind == PMU_KEYLARGO_BASED &&
pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif
if (pmu_kind == PMU_KEYLARGO_BASED)
p += sprintf(p, "server_mode=%d\n", option_server_mode);
@@ -922,12 +917,12 @@ proc_write_options(struct file *file, const char __user *buffer,
*(val++) = 0;
while(*val == ' ')
val++;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
if (pmu_kind == PMU_KEYLARGO_BASED &&
pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
if (!strcmp(label, "lid_wakeup"))
option_lid_wakeup = ((*val) == '1');
-#endif /* CONFIG_PMAC_PBOOK */
+#endif
if (pmu_kind == PMU_KEYLARGO_BASED && !strcmp(label, "server_mode")) {
int new_value;
new_value = ((*val) == '1');
@@ -1422,7 +1417,6 @@ next:
}
/* Tick interrupt */
else if ((1 << pirq) & PMU_INT_TICK) {
-#ifdef CONFIG_PMAC_PBOOK
/* Environement or tick interrupt, query batteries */
if (pmu_battery_count) {
if ((--query_batt_timer) == 0) {
@@ -1437,7 +1431,6 @@ next:
pmu_pass_intr(data, len);
} else {
pmu_pass_intr(data, len);
-#endif /* CONFIG_PMAC_PBOOK */
}
goto next;
}
@@ -2052,7 +2045,7 @@ pmu_i2c_simple_write(int bus, int addr, u8* data, int len)
return -1;
}
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
static LIST_HEAD(sleep_notifiers);
@@ -2705,6 +2698,8 @@ powerbook_sleep_3400(void)
return 0;
}
+#endif /* CONFIG_PM */
+
/*
* Support for /dev/pmu device
*/
@@ -2884,11 +2879,11 @@ static int __pmac
pmu_ioctl(struct inode * inode, struct file *filp,
u_int cmd, u_long arg)
{
- struct pmu_private *pp = filp->private_data;
__u32 __user *argp = (__u32 __user *)arg;
- int error;
+ int error = -EINVAL;
switch (cmd) {
+#ifdef CONFIG_PM
case PMU_IOC_SLEEP:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
@@ -2910,12 +2905,13 @@ pmu_ioctl(struct inode * inode, struct file *filp,
error = -ENOSYS;
}
sleep_in_progress = 0;
- return error;
+ break;
case PMU_IOC_CAN_SLEEP:
if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0)
return put_user(0, argp);
else
return put_user(1, argp);
+#endif /* CONFIG_PM */
#ifdef CONFIG_PMAC_BACKLIGHT
/* Backlight should have its own device or go via
@@ -2936,11 +2932,13 @@ pmu_ioctl(struct inode * inode, struct file *filp,
error = get_user(value, argp);
if (!error)
error = set_backlight_level(value);
- return error;
+ break;
}
#ifdef CONFIG_INPUT_ADBHID
case PMU_IOC_GRAB_BACKLIGHT: {
+ struct pmu_private *pp = filp->private_data;
unsigned long flags;
+
if (pp->backlight_locker)
return 0;
pp->backlight_locker = 1;
@@ -2956,7 +2954,7 @@ pmu_ioctl(struct inode * inode, struct file *filp,
case PMU_IOC_HAS_ADB:
return put_user(pmu_has_adb, argp);
}
- return -EINVAL;
+ return error;
}
static struct file_operations pmu_device_fops __pmacdata = {
@@ -2972,14 +2970,16 @@ static struct miscdevice pmu_device __pmacdata = {
PMU_MINOR, "pmu", &pmu_device_fops
};
-void pmu_device_init(void)
+static int pmu_device_init(void)
{
if (!via)
- return;
+ return 0;
if (misc_register(&pmu_device) < 0)
printk(KERN_ERR "via-pmu: cannot register misc device.\n");
+ return 0;
}
-#endif /* CONFIG_PMAC_PBOOK */
+device_initcall(pmu_device_init);
+
#ifdef DEBUG_SLEEP
static inline void __pmac
@@ -3147,12 +3147,12 @@ EXPORT_SYMBOL(pmu_i2c_combined_read);
EXPORT_SYMBOL(pmu_i2c_stdsub_write);
EXPORT_SYMBOL(pmu_i2c_simple_read);
EXPORT_SYMBOL(pmu_i2c_simple_write);
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
EXPORT_SYMBOL(pmu_register_sleep_notifier);
EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
EXPORT_SYMBOL(pmu_enable_irled);
EXPORT_SYMBOL(pmu_battery_count);
EXPORT_SYMBOL(pmu_batteries);
EXPORT_SYMBOL(pmu_power_flags);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index f9383e7f34f..1b70f8b0feb 100644
--- a/drivers/media/video/Kconfig