summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/ac.c8
-rw-r--r--drivers/acpi/bay.c19
-rw-r--r--drivers/acpi/dispatcher/dsfield.c5
-rw-r--r--drivers/acpi/dispatcher/dsmethod.c2
-rw-r--r--drivers/acpi/dock.c5
-rw-r--r--drivers/acpi/ec.c2
-rw-r--r--drivers/acpi/executer/exconfig.c10
-rw-r--r--drivers/acpi/executer/exmutex.c4
-rw-r--r--drivers/acpi/glue.c9
-rw-r--r--drivers/acpi/hardware/hwsleep.c8
-rw-r--r--drivers/acpi/numa.c31
-rw-r--r--drivers/acpi/parser/psargs.c4
-rw-r--r--drivers/acpi/processor_core.c1
-rw-r--r--drivers/acpi/processor_idle.c13
-rw-r--r--drivers/acpi/sleep/main.c5
-rw-r--r--drivers/acpi/sleep/proc.c11
-rw-r--r--drivers/acpi/system.c15
-rw-r--r--drivers/acpi/tables/tbinstal.c25
-rw-r--r--drivers/acpi/tables/tbxface.c2
-rw-r--r--drivers/acpi/thermal.c11
-rw-r--r--drivers/acpi/utilities/utmisc.c2
-rw-r--r--drivers/acpi/video.c3
-rw-r--r--drivers/ata/Kconfig10
-rw-r--r--drivers/ata/ahci.c191
-rw-r--r--drivers/ata/ata_piix.c16
-rw-r--r--drivers/ata/libata-acpi.c167
-rw-r--r--drivers/ata/libata-core.c46
-rw-r--r--drivers/ata/libata-eh.c207
-rw-r--r--drivers/ata/libata-pmp.c51
-rw-r--r--drivers/ata/libata-scsi.c25
-rw-r--r--drivers/ata/libata-sff.c145
-rw-r--r--drivers/ata/libata.h2
-rw-r--r--drivers/ata/pata_ali.c10
-rw-r--r--drivers/ata/pata_amd.c14
-rw-r--r--drivers/ata/pata_at32.c2
-rw-r--r--drivers/ata/pata_bf54x.c5
-rw-r--r--drivers/ata/pata_cypress.c8
-rw-r--r--drivers/ata/pata_icside.c2
-rw-r--r--drivers/ata/pata_legacy.c50
-rw-r--r--drivers/ata/pata_ns87410.c6
-rw-r--r--drivers/ata/pata_ns87415.c4
-rw-r--r--drivers/ata/pata_pcmcia.c2
-rw-r--r--drivers/ata/pata_qdi.c16
-rw-r--r--drivers/ata/pata_rb532_cf.c4
-rw-r--r--drivers/ata/pata_scc.c5
-rw-r--r--drivers/ata/pata_sis.c1
-rw-r--r--drivers/ata/pata_sl82c105.c2
-rw-r--r--drivers/ata/pata_via.c14
-rw-r--r--drivers/ata/pata_winbond.c6
-rw-r--r--drivers/ata/sata_fsl.c224
-rw-r--r--drivers/ata/sata_mv.c279
-rw-r--r--drivers/ata/sata_promise.c148
-rw-r--r--drivers/ata/sata_sil24.c12
-rw-r--r--drivers/ata/sata_uli.c1
-rw-r--r--drivers/atm/eni.h1
-rw-r--r--drivers/atm/fore200e.h1
-rw-r--r--drivers/atm/fore200e_mkfirm.c2
-rw-r--r--drivers/atm/he.c11
-rw-r--r--drivers/atm/he.h15
-rw-r--r--drivers/atm/idt77252.c7
-rw-r--r--drivers/atm/idt77252.h4
-rw-r--r--drivers/atm/iphase.c27
-rw-r--r--drivers/atm/iphase.h3
-rw-r--r--drivers/atm/nicstarmac.copyright2
-rw-r--r--drivers/auxdisplay/Kconfig2
-rw-r--r--drivers/auxdisplay/cfag12864b.c4
-rw-r--r--drivers/auxdisplay/cfag12864bfb.c4
-rw-r--r--drivers/auxdisplay/ks0108.c4
-rw-r--r--drivers/base/core.c109
-rw-r--r--drivers/base/node.c4
-rw-r--r--drivers/block/brd.c2
-rw-r--r--drivers/block/cciss.c81
-rw-r--r--drivers/block/viodasd.c2
-rw-r--r--drivers/block/virtio_blk.c7
-rw-r--r--drivers/cdrom/viocd.c2
-rw-r--r--drivers/char/Kconfig12
-rw-r--r--drivers/char/agp/agp.h6
-rw-r--r--drivers/char/agp/alpha-agp.c4
-rw-r--r--drivers/char/agp/amd-k7-agp.c4
-rw-r--r--drivers/char/agp/amd64-agp.c4
-rw-r--r--drivers/char/agp/ati-agp.c8
-rw-r--r--drivers/char/agp/backend.c16
-rw-r--r--drivers/char/agp/compat_ioctl.c2
-rw-r--r--drivers/char/agp/efficeon-agp.c6
-rw-r--r--drivers/char/agp/frontend.c12
-rw-r--r--drivers/char/agp/generic.c35
-rw-r--r--drivers/char/agp/hp-agp.c6
-rw-r--r--drivers/char/agp/i460-agp.c2
-rw-r--r--drivers/char/agp/intel-agp.c239
-rw-r--r--drivers/char/agp/nvidia-agp.c4
-rw-r--r--drivers/char/agp/parisc-agp.c6
-rw-r--r--drivers/char/agp/sgi-agp.c8
-rw-r--r--drivers/char/agp/sworks-agp.c6
-rw-r--r--drivers/char/agp/uninorth-agp.c10
-rw-r--r--drivers/char/agp/via-agp.c13
-rw-r--r--drivers/char/drm/ati_pcigart.c8
-rw-r--r--drivers/char/drm/drm.h19
-rw-r--r--drivers/char/drm/drmP.h91
-rw-r--r--drivers/char/drm/drm_drv.c7
-rw-r--r--drivers/char/drm/drm_fops.c7
-rw-r--r--drivers/char/drm/drm_irq.c381
-rw-r--r--drivers/char/drm/drm_lock.c35
-rw-r--r--drivers/char/drm/drm_pciids.h17
-rw-r--r--drivers/char/drm/drm_sysfs.c2
-rw-r--r--drivers/char/drm/i915_dma.c160
-rw-r--r--drivers/char/drm/i915_drm.h45
-rw-r--r--drivers/char/drm/i915_drv.c24
-rw-r--r--drivers/char/drm/i915_drv.h126
-rw-r--r--drivers/char/drm/i915_irq.c601
-rw-r--r--drivers/char/drm/mga_drv.c7
-rw-r--r--drivers/char/drm/mga_drv.h6
-rw-r--r--drivers/char/drm/mga_irq.c69
-rw-r--r--drivers/char/drm/r128_drv.c7
-rw-r--r--drivers/char/drm/r128_drv.h9
-rw-r--r--drivers/char/drm/r128_irq.c55
-rw-r--r--drivers/char/drm/r300_cmdbuf.c117
-rw-r--r--drivers/char/drm/r300_reg.h242
-rw-r--r--drivers/char/drm/radeon_cp.c1148
-rw-r--r--drivers/char/drm/radeon_drm.h8
-rw-r--r--drivers/char/drm/radeon_drv.c8
-rw-r--r--drivers/char/drm/radeon_drv.h270
-rw-r--r--drivers/char/drm/radeon_irq.c171
-rw-r--r--drivers/char/drm/radeon_microcode.h1844
-rw-r--r--drivers/char/drm/radeon_state.c17
-rw-r--r--drivers/char/drm/via_drv.c6
-rw-r--r--drivers/char/drm/via_drv.h7
-rw-r--r--drivers/char/drm/via_irq.c81
-rw-r--r--drivers/char/generic_nvram.c2
-rw-r--r--drivers/char/hw_random/Kconfig9
-rw-r--r--drivers/char/hw_random/Makefile1
-rw-r--r--drivers/char/hw_random/intel-rng.c2
-rw-r--r--drivers/char/hw_random/virtio-rng.c155
-rw-r--r--drivers/char/ip2/Makefile4
-rw-r--r--drivers/char/ip2/ip2main.c23
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c3
-rw-r--r--drivers/char/keyboard.c7
-rw-r--r--drivers/char/pcmcia/ipwireless/hardware.c24
-rw-r--r--drivers/char/rtc.c3
-rw-r--r--drivers/char/sysrq.c1
-rw-r--r--drivers/char/tpm/tpm_tis.c1
-rw-r--r--drivers/char/tty_io.c2
-rw-r--r--drivers/char/tty_ioctl.c7
-rw-r--r--drivers/char/viocons.c2
-rw-r--r--drivers/char/viotape.c2
-rw-r--r--drivers/char/vt.c15
-rw-r--r--drivers/connector/connector.c40
-rw-r--r--drivers/cpufreq/cpufreq.c10
-rw-r--r--drivers/cpufreq/freq_table.c5
-rw-r--r--drivers/cpuidle/cpuidle.c40
-rw-r--r--drivers/dma/iop-adma.c6
-rw-r--r--drivers/edac/mpc85xx_edac.c3
-rw-r--r--drivers/firewire/Kconfig32
-rw-r--r--drivers/firewire/fw-cdev.c23
-rw-r--r--drivers/firewire/fw-ohci.c110
-rw-r--r--drivers/firewire/fw-sbp2.c3
-rw-r--r--drivers/firewire/fw-transaction.c52
-rw-r--r--drivers/firmware/edd.c2
-rw-r--r--drivers/gpio/Kconfig14
-rw-r--r--drivers/gpio/gpiolib.c6
-rw-r--r--drivers/gpio/mcp23s08.c2
-rw-r--r--drivers/gpio/pca953x.c3
-rw-r--r--drivers/hid/hid-debug.c2
-rw-r--r--drivers/hid/hid-input.c7
-rw-r--r--drivers/hid/usbhid/hid-quirks.c49
-rw-r--r--drivers/hid/usbhid/usbkbd.c2
-rw-r--r--drivers/hid/usbhid/usbmouse.c2
-rw-r--r--drivers/hwmon/Kconfig14
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/abituguru3.c18
-rw-r--r--drivers/hwmon/adt7473.c3
-rw-r--r--drivers/hwmon/hdaps.c8
-rw-r--r--drivers/hwmon/i5k_amb.c39
-rw-r--r--drivers/hwmon/ibmaem.c1111
-rw-r--r--drivers/hwmon/lm75.c20
-rw-r--r--drivers/hwmon/lm85.c25
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c28
-rw-r--r--drivers/ide/Kconfig1
-rw-r--r--drivers/ide/arm/bast-ide.c1
-rw-r--r--drivers/ide/arm/ide_arm.c1
-rw-r--r--drivers/ide/arm/palm_bk3710.c61
-rw-r--r--drivers/ide/ide-generic.c10
-rw-r--r--drivers/ide/ide-pnp.c1
-rw-r--r--drivers/ide/ide-probe.c21
-rw-r--r--drivers/ide/ide-proc.c3
-rw-r--r--drivers/ide/ide-taskfile.c6
-rw-r--r--drivers/ide/ide.c24
-rw-r--r--drivers/ide/legacy/buddha.c2
-rw-r--r--drivers/ide/legacy/falconide.c2
-rw-r--r--drivers/ide/legacy/gayle.c6
-rw-r--r--drivers/ide/legacy/ide-cs.c44
-rw-r--r--drivers/ide/legacy/macide.c2
-rw-r--r--drivers/ide/legacy/q40ide.c2
-rw-r--r--drivers/ide/pci/cmd640.c2
-rw-r--r--drivers/ide/pci/delkin_cb.c28
-rw-r--r--drivers/ide/pci/it8213.c3
-rw-r--r--drivers/ide/pci/ns87415.c6
-rw-r--r--drivers/ide/pci/opti621.c221
-rw-r--r--drivers/ide/pci/sis5513.c5
-rw-r--r--drivers/ide/ppc/mpc8xx.c4
-rw-r--r--drivers/ide/ppc/pmac.c60
-rw-r--r--drivers/ieee1394/Kconfig118
-rw-r--r--drivers/ieee1394/sbp2.c20
-rw-r--r--drivers/infiniband/core/mad.c4
-rw-r--r--drivers/infiniband/core/umem.c2
-rw-r--r--drivers/infiniband/core/user_mad.c14
-rw-r--r--drivers/infiniband/core/uverbs_main.c13
-rw-r--r--drivers/infiniband/hw/amso1100/c2_rnic.c3
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c4
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_reqs.c6
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h5
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mad.c4
-rw-r--r--drivers/infiniband/hw/ipath/ipath_sdma.c16
-rw-r--r--drivers/infiniband/hw/ipath/ipath_uc.c4
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.c3
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c15
-rw-r--r--drivers/infiniband/hw/mthca/mthca_main.c14
-rw-r--r--drivers/infiniband/hw/mthca/mthca_memfree.c6
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.c4
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c6
-rw-r--r--drivers/input/ff-core.c18
-rw-r--r--drivers/input/keyboard/aaed2000_kbd.c2
-rw-r--r--drivers/input/keyboard/atkbd.c2
-rw-r--r--drivers/input/keyboard/corgikbd.c2
-rw-r--r--drivers/input/keyboard/jornada680_kbd.c2
-rw-r--r--drivers/input/keyboard/jornada720_kbd.c2
-rw-r--r--drivers/input/keyboard/pxa27x_keypad.c38
-rw-r--r--drivers/input/keyboard/spitzkbd.c2
-rw-r--r--drivers/input/misc/Kconfig1
-rw-r--r--drivers/input/misc/apanel.c1
-rw-r--r--drivers/input/mouse/appletouch.c49
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h14
-rw-r--r--drivers/input/serio/i8042.c41
-rw-r--r--drivers/input/tablet/gtco.c17
-rw-r--r--drivers/input/touchscreen/jornada720_ts.c2
-rw-r--r--drivers/input/touchscreen/wm9713.c22
-rw-r--r--drivers/input/touchscreen/wm97xx-core.c25
-rw-r--r--drivers/isdn/capi/capiutil.c6
-rw-r--r--drivers/isdn/hardware/eicon/divasmain.c1
-rw-r--r--drivers/isdn/hardware/eicon/divasproc.c4
-rw-r--r--drivers/isdn/hysdn/Kconfig2
-rw-r--r--drivers/isdn/hysdn/boardergo.c14
-rw-r--r--drivers/isdn/hysdn/hycapi.c6
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c29
-rw-r--r--drivers/isdn/i4l/isdn_common.c4
-rw-r--r--drivers/isdn/sc/ioctl.c1
-rw-r--r--drivers/leds/led-class.c6
-rw-r--r--drivers/lguest/lguest_device.c25
-rw-r--r--drivers/lguest/x86/core.c15
-rw-r--r--drivers/macintosh/mediabay.c7
-rw-r--r--drivers/macintosh/smu.c5
-rw-r--r--drivers/macintosh/therm_adt746x.c13
-rw-r--r--drivers/md/bitmap.c17
-rw-r--r--drivers/md/dm-crypt.c1
-rw-r--r--drivers/md/md.c87
-rw-r--r--drivers/md/multipath.c3
-rw-r--r--drivers/md/raid1.c29
-rw-r--r--drivers/md/raid10.c16
-rw-r--r--drivers/md/raid5.c68
-rw-r--r--drivers/media/Makefile7
-rw-r--r--drivers/media/common/ir-keymaps.c38
-rw-r--r--drivers/media/common/tuners/Kconfig1
-rw-r--r--drivers/media/common/tuners/mxl5005s.c4
-rw-r--r--drivers/media/common/tuners/tda18271-common.c14
-rw-r--r--drivers/media/common/tuners/tda18271-fe.c53
-rw-r--r--drivers/media/common/tuners/tda827x.c4
-rw-r--r--drivers/media/common/tuners/tea5761.c2
-rw-r--r--drivers/media/common/tuners/tuner-i2c.h8
-rw-r--r--drivers/media/common/tuners/tuner-simple.c6
-rw-r--r--drivers/media/common/tuners/tuner-xc2028.c87
-rw-r--r--drivers/media/common/tuners/xc5000.c30
-rw-r--r--drivers/media/common/tuners/xc5000_priv.h1
-rw-r--r--drivers/media/dvb/b2c2/flexcop-usb.c2
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c46
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c12
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig2
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c21
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-firmware.c2
-rw-r--r--drivers/media/dvb/dvb-usb/gl861.c27
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk.c10
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.c7
-rw-r--r--drivers/media/dvb/dvb-usb/umt-010.c2
-rw-r--r--drivers/media/dvb/frontends/au8522.c29
-rw-r--r--drivers/media/dvb/frontends/dib0070.h15
-rw-r--r--drivers/media/dvb/frontends/dib7000p.h15
-rw-r--r--drivers/media/dvb/frontends/or51132.c6
-rw-r--r--drivers/media/dvb/frontends/stv0299.c15
-rw-r--r--drivers/media/dvb/frontends/tda10023.c20
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c29
-rw-r--r--drivers/media/dvb/ttpci/Kconfig1
-rw-r--r--drivers/media/dvb/ttpci/av7110.c9
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.c34
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.c5
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c2
-rw-r--r--drivers/media/dvb/ttusb-dec/Kconfig2
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusb_dec.c25
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusbdecfe.c10
-rw-r--r--drivers/media/video/Kconfig10
-rw-r--r--drivers/media/video/Makefile2
-rw-r--r--drivers/media/video/au0828/Kconfig2
-rw-r--r--drivers/media/video/au0828/au0828-cards.c18
-rw-r--r--drivers/media/video/au0828/au0828-dvb.c6
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c5
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c2
-rw-r--r--drivers/media/video/bt8xx/bttv-risc.c8
-rw-r--r--drivers/media/video/btcx-risc.c2
-rw-r--r--drivers/media/video/btcx-risc.h4
-rw-r--r--drivers/media/video/cx18/Kconfig4
-rw-r--r--drivers/media/video/cx18/cx18-av-core.c154
-rw-r--r--drivers/media/video/cx18/cx18-av-core.h16
-rw-r--r--drivers/media/video/cx18/cx18-cards.c88
-rw-r--r--drivers/media/video/cx18/cx18-cards.h50
-rw-r--r--drivers/media/video/cx18/cx18-controls.c6
-rw-r--r--drivers/media/video/cx18/cx18-driver.c26
-rw-r--r--drivers/media/video/cx18/cx18-driver.h9
-rw-r--r--drivers/media/video/cx18/cx18-dvb.c17
-rw-r--r--drivers/media/video/cx18/cx18-fileops.c13
-rw-r--r--drivers/media/video/cx18/cx18-gpio.c57
-rw-r--r--drivers/media/video/cx18/cx18-gpio.h1
-rw-r--r--drivers/media/video/cx18/cx18-i2c.c2
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c12
-rw-r--r--drivers/media/video/cx18/cx18-irq.c12
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c8
-rw-r--r--drivers/media/video/cx18/cx18-streams.c37
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c8
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c2
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c6
-rw-r--r--drivers/media/video/cx88/cx88-cards.c13
-rw-r--r--drivers/media/video/cx88/cx88-core.c8
-rw-r--r--drivers/media/video/em28xx/em28xx-audio.c18
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c4
-rw-r--r--drivers/media/video/em28xx/em28xx-dvb.c10
-rw-r--r--drivers/media/video/em28xx/em28xx-reg.h1
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c32
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h10
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c2
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.c8
-rw-r--r--drivers/media/video/ivtv/ivtv-queue.c2
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c30
-rw-r--r--drivers/media/video/ivtv/ivtv-version.h4
-rw-r--r--drivers/media/video/ivtv/ivtv-yuv.c2
-rw-r--r--drivers/media/video/ivtv/ivtv-yuv.h2
-rw-r--r--drivers/media/video/ov7670.c4
-rw-r--r--drivers/media/video/pxa_camera.c4
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c8
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c56
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c43
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c40
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c9
-rw-r--r--drivers/media/video/soc_camera.c16
-rw-r--r--drivers/media/video/tuner-core.c60
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.c2
-rw-r--r--drivers/media/video/uvc/Makefile3
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c1256
-rw-r--r--drivers/media/video/uvc/uvc_driver.c1955
-rw-r--r--drivers/media/video/uvc/uvc_isight.c134
-rw-r--r--drivers/media/video/uvc/uvc_queue.c477
-rw-r--r--drivers/media/video/uvc/uvc_status.c207
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c1105
-rw-r--r--drivers/media/video/uvc/uvc_video.c934
-rw-r--r--drivers/media/video/uvc/uvcvideo.h796
-rw-r--r--drivers/media/video/videobuf-core.c3
-rw-r--r--drivers/media/video/videodev.c245
-rw-r--r--drivers/media/video/vivi.c7
-rw-r--r--drivers/media/video/zoran.h4
-rw-r--r--drivers/media/video/zoran_device.c2
-rw-r--r--drivers/media/video/zoran_driver.c10
-rw-r--r--drivers/message/fusion/mptbase.c11
-rw-r--r--drivers/message/fusion/mptfc.c2
-rw-r--r--drivers/message/fusion/mptsas.c2
-rw-r--r--drivers/message/fusion/mptscsih.c8
-rw-r--r--drivers/message/fusion/mptspi.c9
-rw-r--r--drivers/mfd/Kconfig2
-rw-r--r--drivers/misc/fujitsu-laptop.c6
-rw-r--r--drivers/misc/kgdbts.c33
-rw-r--r--drivers/misc/thinkpad_acpi.c496
-rw-r--r--drivers/mmc/card/Kconfig12
-rw-r--r--drivers/mmc/card/Makefile1
-rw-r--r--drivers/mmc/card/block.c2
-rw-r--r--drivers/mmc/card/mmc_test.c892
-rw-r--r--drivers/mmc/host/Kconfig2
-rw-r--r--drivers/mmc/host/at91_mci.c5
-rw-r--r--drivers/mmc/host/omap.c12
-rw-r--r--drivers/mmc/host/pxamci.c13
-rw-r--r--drivers/mmc/host/sdhci.c34
-rw-r--r--drivers/mmc/host/wbsd.c21
-rw-r--r--drivers/mtd/devices/m25p80.c4
-rw-r--r--drivers/mtd/maps/ck804xrom.c18
-rw-r--r--drivers/mtd/maps/omap_nor.c2
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c2
-rw-r--r--drivers/mtd/onenand/generic.c2
-rw-r--r--drivers/mtd/redboot.c2
-rw-r--r--drivers/net/3c509.c17
-rw-r--r--drivers/net/3c59x.c5
-rw-r--r--drivers/net/7990.c6
-rw-r--r--drivers/net/Kconfig4
-rw-r--r--drivers/net/atlx/atl1.c21
-rw-r--r--drivers/net/au1000_eth.c7
-rw-r--r--drivers/net/bfin_mac.c1
-rw-r--r--drivers/net/bnx2.c9
-rw-r--r--drivers/net/bnx2.h1
-rw-r--r--drivers/net/bnx2x.c5
-rw-r--r--drivers/net/bnx2x.h3
-rw-r--r--drivers/net/bnx2x_init.h3
-rw-r--r--drivers/net/bonding/bond_sysfs.c12
-rw-r--r--drivers/net/cassini.c11
-rw-r--r--drivers/net/cpmac.c234
-rw-r--r--drivers/net/cs89x0.c10
-rw-r--r--drivers/net/dm9000.c2
-rw-r--r--drivers/net/e100.c2
-rw-r--r--drivers/net/e1000/e1000_ethtool.c2
-rw-r--r--drivers/net/e1000e/netdev.c7
-rw-r--r--drivers/net/ehea/ehea.h8
-rw-r--r--drivers/net/ehea/ehea_main.c64
-rw-r--r--drivers/net/enc28j60.c87
-rw-r--r--drivers/net/fec_mpc52xx.c2
-rw-r--r--drivers/net/forcedeth.c36
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c2
-rw-r--r--drivers/net/fs_enet/mac-fcc.c3
-rw-r--r--drivers/net/hamradio/baycom_epp.c2
-rw-r--r--drivers/net/hamradio/dmascc.c2
-rw-r--r--drivers/net/hamradio/scc.c3
-rw-r--r--drivers/net/ibm_newemac/Kconfig1
-rw-r--r--drivers/net/ibm_newemac/core.c8
-rw-r--r--drivers/net/igb/igb_main.c3
-rw-r--r--drivers/net/ipg.c20
-rw-r--r--drivers/net/irda/Kconfig1
-rw-r--r--drivers/net/irda/irda-usb.c2
-rw-r--r--drivers/net/irda/irda-usb.h4
-rw-r--r--drivers/net/irda/nsc-ircc.c1
-rw-r--r--drivers/net/irda/via-ircc.c3
-rw-r--r--drivers/net/ixgbe/ixgbe_82598.c4
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c3
-rw-r--r--drivers/net/myri10ge/myri10ge.c4
-rw-r--r--drivers/net/netxen/netxen_nic.h18
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c6
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c112
-rw-r--r--drivers/net/netxen/netxen_nic_init.c46
-rw-r--r--drivers/net/netxen/netxen_nic_isr.c4
-rw-r--r--drivers/net/netxen/netxen_nic_main.c137
-rw-r--r--drivers/net/netxen/netxen_nic_niu.c22
-rw-r--r--drivers/net/pasemi_mac.c2
-rw-r--r--drivers/net/pcmcia/axnet_cs.c2
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c4
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c3
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c12
-rw-r--r--drivers/net/pcnet32.c4
-rw-r--r--drivers/net/phy/Kconfig2
-rw-r--r--drivers/net/phy/phy_device.c1
-rw-r--r--drivers/net/pppoe.c37
-rw-r--r--drivers/net/pppol2tp.c144
-rw-r--r--drivers/net/qla3xxx.c2
-rw-r--r--drivers/net/r6040.c4
-rw-r--r--drivers/net/s2io-regs.h2
-rw-r--r--drivers/net/s2io.c531
-rw-r--r--drivers/net/s2io.h26
-rw-r--r--drivers/net/sb1250-mac.c67
-rw-r--r--drivers/net/sc92031.c8
-rw-r--r--drivers/net/sfc/bitfield.h7
-rw-r--r--drivers/net/sfc/boards.c9
-rw-r--r--drivers/net/sfc/efx.c84
-rw-r--r--drivers/net/sfc/falcon.c91
-rw-r--r--drivers/net/sfc/falcon.h5
-rw-r--r--drivers/net/sfc/falcon_hwdefs.h4
-rw-r--r--drivers/net/sfc/falcon_io.h29
-rw-r--r--drivers/net/sfc/falcon_xmac.c12
-rw-r--r--drivers/net/sfc/net_driver.h44
-rw-r--r--drivers/net/sfc/rx.c48
-rw-r--r--drivers/net/sfc/selftest.c14
-rw-r--r--drivers/net/sfc/sfe4001.c14
-rw-r--r--drivers/net/sfc/tenxpress.c4
-rw-r--r--drivers/net/sfc/tx.c11
-rw-r--r--drivers/net/sfc/workarounds.h2
-rw-r--r--drivers/net/sfc/xfp_phy.c4
-rw-r--r--drivers/net/sky2.c32
-rw-r--r--drivers/net/smc911x.c24
-rw-r--r--drivers/net/smc91x.c17
-rw-r--r--drivers/net/smc91x.h8
-rw-r--r--drivers/net/sunhme.c4
-rw-r--r--drivers/net/tc35815.c4
-rw-r--r--drivers/net/tg3.c33
-rw-r--r--drivers/net/tokenring/3c359.h2
-rw-r--r--drivers/net/tokenring/olympic.h2
-rw-r--r--drivers/net/tulip/tulip_core.c12
-rw-r--r--drivers/net/tulip/uli526x.c16
-rw-r--r--drivers/net/tun.c21
-rw-r--r--drivers/net/ucc_geth.c9
-rw-r--r--drivers/net/ucc_geth_ethtool.c3
-rw-r--r--drivers/net/usb/asix.c4
-rw-r--r--drivers/net/usb/catc.c5
-rw-r--r--drivers/net/usb/cdc_subset.c2
-rw-r--r--drivers/net/usb/kaweth.c2
-rw-r--r--drivers/net/usb/rndis_host.c6
-rw-r--r--drivers/net/virtio_net.c91
-rw-r--r--drivers/net/wan/hdlc.c19
-rw-r--r--drivers/net/wan/hdlc_cisco.c82
-rw-r--r--drivers/net/wan/hdlc_fr.c1
-rw-r--r--drivers/net/wan/x25_asy.c3
-rw-r--r--drivers/net/wireless/airo.c3
-rw-r--r--drivers/net/wireless/ath5k/base.c2
-rw-r--r--drivers/net/wireless/ath5k/hw.c6
-rw-r--r--drivers/net/wireless/b43/Kconfig2
-rw-r--r--drivers/net/wireless/b43/b43.h2
-rw-r--r--drivers/net/wireless/b43/dma.c65
-rw-r--r--drivers/net/wireless/b43/leds.c3
-rw-r--r--drivers/net/wireless/b43/main.c98
-rw-r--r--drivers/net/wireless/b43legacy/Kconfig2
-rw-r--r--drivers/net/wireless/b43legacy/dma.c2
-rw-r--r--drivers/net/wireless/b43legacy/main.c23
-rw-r--r--drivers/net/wireless/hostap/hostap_80211_rx.c8
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c21
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c19
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c13
-rw-r--r--drivers/net/wireless/ipw2200.c204
-rw-r--r--drivers/net/wireless/ipw2200.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.c5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-rs.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c36
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c42
-rw-r--r--drivers/net/wireless/libertas/cmd.c5
-rw-r--r--drivers/net/wireless/libertas/debugfs.c4
-rw-r--r--drivers/net/wireless/libertas/ethtool.c27
-rw-r--r--drivers/net/wireless/libertas/if_usb.c1
-rw-r--r--drivers/net/wireless/libertas/main.c4
-rw-r--r--drivers/net/wireless/libertas/scan.c4
-rw-r--r--drivers/net/wireless/orinoco_cs.c1
-rw-r--r--drivers/net/wireless/p54/p54usb.c1
-rw-r--r--drivers/net/wireless/prism54/islpci_eth.c2
-rw-r--r--drivers/net/wireless/rndis_wlan.c65
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig19
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c11
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c11
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c43
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h6
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c46
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c5
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c3
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c6
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c9
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c46
-rw-r--r--drivers/net/wireless/rtl8180_grf5101.c2
-rw-r--r--drivers/net/wireless/rtl8180_max2820.c5
-rw-r--r--drivers/net/wireless/rtl8180_sa2400.c2
-rw-r--r--drivers/net/wireless/rtl8187_dev.c14
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c5
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c3
-rw-r--r--drivers/net/xen-netfront.c6
-rw-r--r--drivers/of/of_i2c.c1
-rw-r--r--drivers/pci/access.c14
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c17
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c7
-rw-r--r--drivers/pci/hotplug/pciehp.h11
-rw-r--r--drivers/pci/hotplug/pciehp_core.c6
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c36
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c129
-rw-r--r--drivers/pci/hotplug/rpadlpar_sysfs.c8
-rw-r--r--drivers/pci/hotplug/shpchp_core.c4
-rw-r--r--drivers/pci/pci-driver.c2
-rw-r--r--drivers/pci/pci-sysfs.c89
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--drivers/pci/pcie/aspm.c20
-rw-r--r--drivers/pci/quirks.c43
-rw-r--r--drivers/pcmcia/electra_cf.c1
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c46
-rw-r--r--drivers/pnp/quirks.c2
-rw-r--r--drivers/pnp/system.c2
-rw-r--r--drivers/power/power_supply_core.c6
-rw-r--r--drivers/power/power_supply_sysfs.c2
-rw-r--r--drivers/rapidio/rio-driver.c2
-rw-r--r--drivers/rtc/Kconfig19
-rw-r--r--drivers/rtc/Makefile2
-rw-r--r--drivers/rtc/interface.c102
-rw-r--r--drivers/rtc/rtc-at32ap700x.c7
-rw-r--r--drivers/rtc/rtc-cmos.c31
-rw-r--r--drivers/rtc/rtc-ds1374.c2
-rw-r--r--drivers/rtc/rtc-fm3130.c501
-rw-r--r--drivers/rtc/rtc-pcf8563.c1
-rw-r--r--drivers/rtc/rtc-ppc.c69
-rw-r--r--drivers/rtc/rtc-sa1100.c4
-rw-r--r--drivers/rtc/rtc-x1205.c111
-rw-r--r--drivers/s390/block/dasd.c28
-rw-r--r--drivers/s390/char/raw3270.c9
-rw-r--r--drivers/s390/char/sclp_config.c2
-rw-r--r--drivers/s390/char/sclp_vt220.c28
-rw-r--r--drivers/s390/char/tape.h3
-rw-r--r--drivers/s390/char/tape_3590.c2
-rw-r--r--drivers/s390/char/tape_block.c4
-rw-r--r--drivers/s390/char/tape_core.c16
-rw-r--r--drivers/s390/char/vmlogrdr.c9
-rw-r--r--drivers/s390/cio/blacklist.c6
-rw-r--r--drivers/s390/cio/cio.c20
-rw-r--r--drivers/s390/kvm/kvm_virtio.c58
-rw-r--r--drivers/s390/net/qeth_core_main.c49
-rw-r--r--drivers/s390/net/qeth_core_offl.c6
-rw-r--r--drivers/s390/net/qeth_core_sys.c12
-rw-r--r--drivers/s390/net/qeth_l2_main.c41
-rw-r--r--drivers/s390/net/qeth_l3_main.c75
-rw-r--r--drivers/s390/net/qeth_l3_sys.c24
-rw-r--r--drivers/s390/s390mach.c1
-rw-r--r--drivers/sbus/char/bpp.c6
-rw-r--r--drivers/scsi/3w-9xxx.c6
-rw-r--r--drivers/scsi/aha152x.c4
-rw-r--r--drivers/scsi/atp870u.c2
-rw-r--r--drivers/scsi/ch.c7
-rw-r--r--drivers/scsi/dpt/dptsig.h3
-rw-r--r--drivers/scsi/esp_scsi.c22
-rw-r--r--drivers/scsi/hosts.c9
-rw-r--r--drivers/scsi/hptiop.c12
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c2
-rw-r--r--drivers/scsi/ibmvscsi/viosrp.h3
-rw-r--r--drivers/scsi/ipr.c6
-rw-r--r--drivers/scsi/mac_esp.c2
-rw-r--r--drivers/scsi/osst.c3
-rw-r--r--drivers/scsi/qla1280.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c13
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h3
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h4
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c63
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c12
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c19
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c30
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/scsi_lib.c9
-rw-r--r--drivers/scsi/scsi_sysfs.c7
-rw-r--r--drivers/scsi/ses.c2
-rw-r--r--drivers/scsi/sg.c11
-rw-r--r--drivers/scsi/sr.c3
-rw-r--r--drivers/scsi/st.c12
-rw-r--r--drivers/serial/8250.c4
-rw-r--r--drivers/serial/8250_pci.c7
-rw-r--r--drivers/serial/Kconfig2
-rw-r--r--drivers/serial/atmel_serial.c2
-rw-r--r--drivers/serial/bfin_5xx.c80
-rw-r--r--drivers/serial/sb1250-duart.c2
-rw-r--r--drivers/serial/serial_core.c19
-rw-r--r--drivers/serial/sh-sci.c8
-rw-r--r--drivers/serial/sunhv.c1
-rw-r--r--drivers/serial/ucc_uart.c2
-rw-r--r--drivers/spi/spidev.c176
-rw-r--r--drivers/ssb/driver_pcicore.c9
-rw-r--r--drivers/ssb/main.c12
-rw-r--r--drivers/thermal/Kconfig9
-rw-r--r--drivers/thermal/thermal_sys.c4
-rw-r--r--drivers/uio/uio.c7
-rw-r--r--drivers/usb/c67x00/c67x00-ll-hpi.c12
-rw-r--r--drivers/usb/class/Kconfig11
-rw-r--r--drivers/usb/class/Makefile1
-rw-r--r--drivers/usb/class/cdc-acm.c3
-rw-r--r--drivers/usb/class/cdc-wdm.c740
-rw-r--r--drivers/usb/core/generic.c5
-rw-r--r--drivers/usb/core/hcd.c53
-rw-r--r--drivers/usb/core/hcd.h4
-rw-r--r--drivers/usb/core/hub.c85
-rw-r--r--drivers/usb/core/quirks.c7
-rw-r--r--drivers/usb/core/sysfs.c44
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.c2
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c3
-rw-r--r--drivers/usb/host/Kconfig8
-rw-r--r--drivers/usb/host/ehci-au1xxx.c1
-rw-r--r--drivers/usb/host/ehci-fsl.c7
-rw-r--r--drivers/usb/host/ehci-hub.c16
-rw-r--r--drivers/usb/host/ehci-ixp4xx.c4
-rw-r--r--drivers/usb/host/ehci-orion.c10
-rw-r--r--drivers/usb/host/ehci-pci.c4
-rw-r--r--drivers/usb/host/ehci-ppc-of.c2
-rw-r--r--drivers/usb/host/ehci-ppc-soc.c1
-rw-r--r--drivers/usb/host/ehci-ps3.c1
-rw-r--r--drivers/usb/host/ehci-sched.c67
-rw-r--r--drivers/usb/host/ehci.h24
-rw-r--r--drivers/usb/host/isp1760-hcd.c8
-rw-r--r--drivers/usb/host/isp1760-if.c4
-rw-r--r--drivers/usb/host/ohci-at91.c1
-rw-r--r--drivers/usb/host/ohci-au1xxx.c3
-rw-r--r--drivers/usb/host/ohci-ep93xx.c1
-rw-r--r--drivers/usb/host/ohci-hcd.c15
-rw-r--r--drivers/usb/host/ohci-hub.c53
-rw-r--r--drivers/usb/host/ohci-lh7a404.c3
-rw-r--r--drivers/usb/host/ohci-omap.c1
-rw-r--r--drivers/usb/host/ohci-pci.c1
-rw-r--r--drivers/usb/host/ohci-pnx4008.c1
-rw-r--r--drivers/usb/host/ohci-pnx8550.c1
-rw-r--r--drivers/usb/host/ohci-ppc-of.c1
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c1
-rw-r--r--drivers/usb/host/ohci-ps3.c1
-rw-r--r--drivers/usb/host/ohci-pxa27x.c1
-rw-r--r--drivers/usb/host/ohci-q.c12
-rw-r--r--drivers/usb/host/ohci-s3c2410.c3
-rw-r--r--drivers/usb/host/ohci-sa1111.c3
-rw-r--r--drivers/usb/host/ohci-sh.c1
-rw-r--r--drivers/usb/host/ohci-sm501.c1
-rw-r--r--drivers/usb/host/ohci-ssb.c1
-rw-r--r--drivers/usb/host/u132-hcd.c11
-rw-r--r--drivers/usb/misc/Kconfig12
-rw-r--r--drivers/usb/misc/Makefile1
-rw-r--r--drivers/usb/misc/isight_firmware.c140
-rw-r--r--drivers/usb/misc/phidgetkit.c6
-rw-r--r--drivers/usb/misc/phidgetmotorcontrol.c7
-rw-r--r--drivers/usb/misc/phidgetservo.c6
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c2
-rw-r--r--drivers/usb/serial/ch341.c1
-rw-r--r--drivers/usb/serial/ftdi_sio.c266
-rw-r--r--drivers/usb/serial/ftdi_sio.h276
-rw-r--r--drivers/usb/serial/ipaq.c7
-rw-r--r--drivers/usb/serial/option.c42
-rw-r--r--drivers/usb/serial/pl2303.c3
-rw-r--r--drivers/usb/serial/pl2303.h3
-rw-r--r--drivers/usb/storage/unusual_devs.h18
-rw-r--r--drivers/video/Kconfig3
-rw-r--r--drivers/video/aty/atyfb_base.c2
-rw-r--r--drivers/video/aty/radeon_base.c4
-rw-r--r--drivers/video/cirrusfb.c6
-rw-r--r--drivers/video/console/fbcon.c4
-rw-r--r--drivers/video/display/display-sysfs.c10
-rw-r--r--drivers/video/fb_defio.c20
-rw-r--r--drivers/video/fsl-diu-fb.c29
-rw-r--r--drivers/video/hgafb.c26
-rw-r--r--drivers/video/leo.c58
-rw-r--r--drivers/video/matrox/matroxfb_base.h2
-rw-r--r--drivers/video/modedb.c2
-rw-r--r--drivers/video/pxafb.c59
-rw-r--r--drivers/video/s3c2410fb.c130
-rw-r--r--drivers/video/s3c2410fb.h20
-rw-r--r--drivers/video/sis/sis_main.c2
-rw-r--r--drivers/video/sm501fb.c8
-rw-r--r--drivers/video/w100fb.c1
-rw-r--r--drivers/virtio/virtio.c10
-rw-r--r--drivers/virtio/virtio_pci.c7
-rw-r--r--drivers/virtio/virtio_ring.c8
-rw-r--r--drivers/watchdog/Kconfig13
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/bfin_wdt.c111
-rw-r--r--drivers/watchdog/booke_wdt.c88
-rw-r--r--drivers/watchdog/geodewdt.c308
-rw-r--r--drivers/watchdog/hpwdt.c155
-rw-r--r--drivers/watchdog/iTCO_wdt.c14
-rw-r--r--drivers/watchdog/w83697hf_wdt.c38
-rw-r--r--drivers/xen/events.c2
742 files changed, 22772 insertions, 8056 deletions
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 5b73f6a2cd86..831883b7d6c9 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -233,6 +233,9 @@ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
device = ac->device;
switch (event) {
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Unsupported event [0x%x]\n", event));
case ACPI_AC_NOTIFY_STATUS:
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
@@ -244,11 +247,6 @@ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
#ifdef CONFIG_ACPI_SYSFS_POWER
kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
#endif
- break;
- default:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Unsupported event [0x%x]\n", event));
- break;
}
return;
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
index d2fc94161848..61b6c5beb2d3 100644
--- a/drivers/acpi/bay.c
+++ b/drivers/acpi/bay.c
@@ -301,16 +301,20 @@ static int bay_add(acpi_handle handle, int id)
*/
pdev->dev.uevent_suppress = 0;
- if (acpi_bay_add_fs(new_bay)) {
- platform_device_unregister(new_bay->pdev);
- goto bay_add_err;
- }
-
/* register for events on this device */
status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
bay_notify, new_bay);
if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Error installing bay notify handler\n");
+ printk(KERN_INFO PREFIX "Error installing bay notify handler\n");
+ platform_device_unregister(new_bay->pdev);
+ goto bay_add_err;
+ }
+
+ if (acpi_bay_add_fs(new_bay)) {
+ acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ bay_notify);
+ platform_device_unregister(new_bay->pdev);
+ goto bay_add_err;
}
/* if we are on a dock station, we should register for dock
@@ -373,6 +377,9 @@ static int __init bay_init(void)
INIT_LIST_HEAD(&drive_bays);
+ if (acpi_disabled)
+ return -ENODEV;
+
/* look for dockable drive bays */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_bay, &bays, NULL);
diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c
index c78078315be9..f988a5e7d2b4 100644
--- a/drivers/acpi/dispatcher/dsfield.c
+++ b/drivers/acpi/dispatcher/dsfield.c
@@ -450,10 +450,6 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- if (!arg) {
- return_ACPI_STATUS(AE_AML_NO_OPERAND);
- }
-
/* Creating new namespace node(s), should not already exist */
flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
@@ -467,6 +463,7 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
/*
* Walk the list of entries in the field_list
+ * Note: field_list can be of zero length. In this case, Arg will be NULL.
*/
while (arg) {
/*
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
index e48a3ea03117..2509809a36cf 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -565,7 +565,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
acpi_os_release_mutex(method_desc->method.
mutex->mutex.os_mutex);
- method_desc->method.mutex->mutex.thread_id = 0;
+ method_desc->method.mutex->mutex.thread_id = NULL;
}
}
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index fa44fb96fc34..bb7c51f712bd 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -834,7 +834,7 @@ static int dock_add(acpi_handle handle)
goto dock_add_err;
}
- printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_DESCRIPTION);
+ printk(KERN_INFO PREFIX "%s\n", ACPI_DOCK_DRIVER_DESCRIPTION);
return 0;
@@ -917,6 +917,9 @@ static int __init dock_init(void)
dock_station = NULL;
+ if (acpi_disabled)
+ return 0;
+
/* look for a dock station */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, find_dock, &num, NULL);
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 0924992187e8..5622aee996b2 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -194,7 +194,7 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
while (time_before(jiffies, delay)) {
if (acpi_ec_check_status(ec, event))
return 0;
- udelay(ACPI_EC_UDELAY);
+ msleep(1);
}
}
pr_err(PREFIX "acpi_ec_wait timeout, status = 0x%2.2x, event = %s\n",
diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c
index 24da921d13e3..39d742190584 100644
--- a/drivers/acpi/executer/exconfig.c
+++ b/drivers/acpi/executer/exconfig.c
@@ -375,9 +375,15 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
goto cleanup;
}
+ /*
+ * Add the table to the namespace.
+ *
+ * Note: We load the table objects relative to the root of the namespace.
+ * This appears to go against the ACPI specification, but we do it for
+ * compatibility with other ACPI implementations.
+ */
status =
- acpi_ex_add_table(table_index, walk_state->scope_info->scope.node,
- &ddb_handle);
+ acpi_ex_add_table(table_index, acpi_gbl_root_node, &ddb_handle);
if (ACPI_FAILURE(status)) {
/* On error, table_ptr was deallocated above */
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
index c873ab40cd0e..a8bf3d713e28 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/executer/exmutex.c
@@ -326,7 +326,7 @@ acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc)
/* Clear mutex info */
- obj_desc->mutex.thread_id = 0;
+ obj_desc->mutex.thread_id = NULL;
return_ACPI_STATUS(status);
}
@@ -463,7 +463,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)
/* Mark mutex unowned */
obj_desc->mutex.owner_thread = NULL;
- obj_desc->mutex.thread_id = 0;
+ obj_desc->mutex.thread_id = NULL;
/* Update Thread sync_level (Last mutex is the important one) */
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 06f8634fe58b..9b227d4dc9c9 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -272,6 +272,12 @@ static u32 rtc_handler(void *context)
static inline void rtc_wake_setup(void)
{
acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
+ /*
+ * After the RTC handler is installed, the Fixed_RTC event should
+ * be disabled. Only when the RTC alarm is set will it be enabled.
+ */
+ acpi_clear_event(ACPI_EVENT_RTC);
+ acpi_disable_event(ACPI_EVENT_RTC, 0);
}
static void rtc_wake_on(struct device *dev)
@@ -327,6 +333,9 @@ static int __init acpi_rtc_init(void)
{
struct device *dev = get_rtc_dev();
+ if (acpi_disabled)
+ return 0;
+
if (dev) {
rtc_wake_setup();
rtc_info.wake_on = rtc_wake_on;
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index d9937e05ec6a..dba3cfbe8cba 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -223,15 +223,17 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
break;
}
- /* Set the system indicators to show the desired sleep state. */
-
+ /*
+ * Set the system indicators to show the desired sleep state.
+ * _SST is an optional method (return no error if not found)
+ */
status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
ACPI_EXCEPTION((AE_INFO, status,
"While executing method _SST"));
}
- return_ACPI_STATUS(status);
+ return_ACPI_STATUS(AE_OK);
}
ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep)
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 5d59cb33b1a5..658e5f3abae0 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -140,19 +140,42 @@ acpi_table_print_srat_entry(struct acpi_subtable_header *header)
}
}
+/*
+ * A lot of BIOS fill in 10 (= no distance) everywhere. This messes
+ * up the NUMA heuristics which wants the local node to have a smaller
+ * distance than the others.
+ * Do some quick checks here and only use the SLIT if it passes.
+ */
+static __init int slit_valid(struct acpi_table_slit *slit)
+{
+ int i, j;
+ int d = slit->locality_count;
+ for (i = 0; i < d; i++) {
+ for (j = 0; j < d; j++) {
+ u8 val = slit->entry[d*i + j];
+ if (i == j) {
+ if (val != LOCAL_DISTANCE)
+ return 0;
+ } else if (val <= LOCAL_DISTANCE)
+ return 0;
+ }
+ }
+ return 1;
+}
+
static int __init acpi_parse_slit(struct acpi_table_header *table)
{
struct acpi_table_slit *slit;
- u32 localities;
if (!table)
return -EINVAL;
slit = (struct acpi_table_slit *)table;
- /* downcast just for %llu vs %lu for i386/ia64 */
- localities = (u32) slit->locality_count;
-
+ if (!slit_valid(slit)) {
+ printk(KERN_INFO "ACPI: SLIT table looks invalid. Not used.\n");
+ return -EINVAL;
+ }
acpi_numa_slit_init(slit);
return 0;
diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c
index f1e8bf65e24e..e94463778845 100644
--- a/drivers/acpi/parser/psargs.c
+++ b/drivers/acpi/parser/psargs.c
@@ -268,7 +268,7 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state,
*/
if (ACPI_SUCCESS(status) &&
possible_method_call && (node->type == ACPI_TYPE_METHOD)) {
- if (walk_state->op->common.aml_opcode == AML_UNLOAD_OP) {
+ if (walk_state->opcode == AML_UNLOAD_OP) {
/*
* acpi_ps_get_next_namestring has increased the AML pointer,
* so we need to restore the saved AML pointer for method call.
@@ -691,7 +691,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
/* To support super_name arg of Unload */
- if (walk_state->op->common.aml_opcode == AML_UNLOAD_OP) {
+ if (walk_state->opcode == AML_UNLOAD_OP) {
status =
acpi_ps_get_next_namepath(walk_state,
parser_state, arg,
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 386e5aa48834..9dd0fa93b9e1 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -86,7 +86,6 @@ static int acpi_processor_info_open_fs(struct inode *inode, struct file *file);
static void acpi_processor_notify(acpi_handle handle, u32 event, void *data);
static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu);
static int acpi_processor_handle_eject(struct acpi_processor *pr);
-extern int acpi_processor_tstate_has_changed(struct acpi_processor *pr);
static const struct acpi_device_id processor_device_ids[] = {
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 2dd2c1f3a01c..556ee1585192 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -1669,6 +1669,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
return -EINVAL;
}
+ dev->cpu = pr->id;
for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
dev->states[i].name[0] = '\0';
dev->states[i].desc[0] = '\0';
@@ -1738,7 +1739,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
int acpi_processor_cst_has_changed(struct acpi_processor *pr)
{
- int ret;
+ int ret = 0;
if (boot_option_idle_override)
return 0;
@@ -1756,8 +1757,10 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
cpuidle_pause_and_lock();
cpuidle_disable_device(&pr->power.dev);
acpi_processor_get_power_info(pr);
- acpi_processor_setup_cpuidle(pr);
- ret = cpuidle_enable_device(&pr->power.dev);
+ if (pr->flags.power) {
+ acpi_processor_setup_cpuidle(pr);
+ ret = cpuidle_enable_device(&pr->power.dev);
+ }
cpuidle_resume_and_unlock();
return ret;
@@ -1813,7 +1816,6 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
if (pr->flags.power) {
#ifdef CONFIG_CPU_IDLE
acpi_processor_setup_cpuidle(pr);
- pr->power.dev.cpu = pr->id;
if (cpuidle_register_device(&pr->power.dev))
return -EIO;
#endif
@@ -1850,8 +1852,7 @@ int acpi_processor_power_exit(struct acpi_processor *pr,
return 0;
#ifdef CONFIG_CPU_IDLE
- if (pr->flags.power)
- cpuidle_unregister_device(&pr->power.dev);
+ cpuidle_unregister_device(&pr->power.dev);
#endif
pr->flags.power_setup_done = 0;
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index c3b0cd88d09f..495c63a3e0af 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -36,9 +36,8 @@ static int acpi_sleep_prepare(u32 acpi_state)
if (!acpi_wakeup_address) {
return -EFAULT;
}
- acpi_set_firmware_waking_vector((acpi_physical_address)
- virt_to_phys((void *)
- acpi_wakeup_address));
+ acpi_set_firmware_waking_vector(
+ (acpi_physical_address)acpi_wakeup_address);
}
ACPI_FLUSH_CPU_CACHE();
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 8a5fe8710513..4ebbba2b6b19 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -315,8 +315,11 @@ acpi_system_write_alarm(struct file *file,
cmos_bcd_write(day, acpi_gbl_FADT.day_alarm, rtc_control);
if (acpi_gbl_FADT.month_alarm)
cmos_bcd_write(mo, acpi_gbl_FADT.month_alarm, rtc_control);
- if (acpi_gbl_FADT.century)
+ if (acpi_gbl_FADT.century) {
+ if (adjust)
+ yr += cmos_bcd_read(acpi_gbl_FADT.century, rtc_control) * 100;
cmos_bcd_write(yr / 100, acpi_gbl_FADT.century, rtc_control);
+ }
/* enable the rtc alarm interrupt */
rtc_control |= RTC_AIE;
CMOS_WRITE(rtc_control, RTC_CONTROL);
@@ -495,6 +498,12 @@ static int __init acpi_sleep_proc_init(void)
acpi_root_dir, &acpi_system_alarm_fops);
acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
+ /*
+ * Disable the RTC event after installing RTC handler.
+ * Only when RTC alarm is set will it be enabled.
+ */
+ acpi_clear_event(ACPI_EVENT_RTC);
+ acpi_disable_event(ACPI_EVENT_RTC, 0);
#endif /* HAVE_ACPI_LEGACY_ALARM */
/* 'wakeup device' [R/W] */
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 769f24855eb6..5bd2dec9a7ac 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -77,7 +77,6 @@ static ssize_t acpi_table_show(struct kobject *kobj,
container_of(bin_attr, struct acpi_table_attr, attr);
struct acpi_table_header *table_header = NULL;
acpi_status status;
- ssize_t ret_count = count;
status =
acpi_get_table(table_attr->name, table_attr->instance,
@@ -85,18 +84,8 @@ static ssize_t acpi_table_show(struct kobject *kobj,
if (ACPI_FAILURE(status))
return -ENODEV;
- if (offset >= table_header->length) {
- ret_count = 0;
- goto end;
- }
-
- if (offset + ret_count > table_header->length)
- ret_count = table_header->length - offset;
-
- memcpy(buf, ((char *)table_header) + offset, ret_count);
-
- end:
- return ret_count;
+ return memory_read_from_buffer(buf, count, &offset,
+ table_header, table_header->length);
}
static void acpi_table_attr_init(struct acpi_table_attr *table_attr,
diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
index 402f93e1ff20..5336ce88f89f 100644
--- a/drivers/acpi/tables/tbinstal.c
+++ b/drivers/acpi/tables/tbinstal.c
@@ -123,24 +123,13 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc,
}
}
- /* The table must be either an SSDT or a PSDT or an OEMx */
-
- if (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT)&&
- !ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)&&
- strncmp(table_desc->pointer->signature, "OEM", 3)) {
- /* Check for a printable name */
- if (acpi_ut_valid_acpi_name(
- *(u32 *) table_desc->pointer->signature)) {
- ACPI_ERROR((AE_INFO, "Table has invalid signature "
- "[%4.4s], must be SSDT or PSDT",
- table_desc->pointer->signature));
- } else {
- ACPI_ERROR((AE_INFO, "Table has invalid signature "
- "(0x%8.8X), must be SSDT or PSDT",
- *(u32 *) table_desc->pointer->signature));
- }
- return_ACPI_STATUS(AE_BAD_SIGNATURE);
- }
+ /*
+ * Originally, we checked the table signature for "SSDT" or "PSDT" here.
+ * Next, we added support for OEMx tables, signature "OEM".
+ * Valid tables were encountered with a null signature, so we've just
+ * given up on validating the signature, since it seems to be a waste
+ * of code. The original code was removed (05/2008).
+ */
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
index fb57b93c2495..0e319604d3e7 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/tables/tbxface.c
@@ -540,7 +540,7 @@ static acpi_status acpi_tb_load_namespace(void)
acpi_tb_print_table_header(0, table);
if (no_auto_ssdt == 0) {
- printk(KERN_WARNING "ACPI: DSDT override uses original SSDTs unless \"acpi_no_auto_ssdt\"");
+ printk(KERN_WARNING "ACPI: DSDT override uses original SSDTs unless \"acpi_no_auto_ssdt\"\n");
}
}
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 504385b1f211..84c795fb9b1e 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -364,10 +364,17 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
if (flag & ACPI_TRIPS_CRITICAL) {
status = acpi_evaluate_integer(tz->device->handle,
"_CRT", NULL, &tz->trips.critical.temperature);
- if (ACPI_FAILURE(status)) {
+ /*
+ * Treat freezing temperatures as invalid as well; some
+ * BIOSes return really low values and cause reboots at startup.
+ * Below zero (Celcius) values clearly aren't right for sure..
+ * ... so lets discard those as invalid.
+ */
+ if (ACPI_FAILURE(status) ||
+ tz->trips.critical.temperature <= 2732) {
tz->trips.critical.flags.valid = 0;
ACPI_EXCEPTION((AE_INFO, status,
- "No critical threshold"));
+ "No or invalid critical threshold"));
return -ENODEV;
} else {
tz->trips.critical.flags.valid = 1;
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
index e4ba7192cd15..1f057b71db1a 100644
--- a/drivers/acpi/utilities/utmisc.c
+++ b/drivers/acpi/utilities/utmisc.c
@@ -1048,6 +1048,7 @@ acpi_ut_exception(char *module_name,
va_start(args, format);
acpi_os_vprintf(format, args);
acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+ va_end(args);
}
EXPORT_SYMBOL(acpi_ut_exception);
@@ -1063,7 +1064,6 @@ acpi_ut_warning(char *module_name, u32 line_number, char *format, ...)
acpi_os_vprintf(format, args);
acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
va_end(args);
- va_end(args);
}
void ACPI_INTERNAL_VAR_XFACE
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 5e5dda3a3027..d089c4519d45 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -1713,7 +1713,8 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video,
status = acpi_video_bus_get_one_device(dev, video);
if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Cant attach device"));
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+ "Cant attach device"));
continue;
}
}
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 9bf2986a2788..ae8494944c45 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -651,9 +651,17 @@ config PATA_WINBOND_VLB
Support for the Winbond W83759A controller on Vesa Local Bus
systems.
+config HAVE_PATA_PLATFORM
+ bool
+ help
+ This is an internal configuration node for any machine that
+ uses pata-platform driver to enable the relevant driver in the
+ configuration structure without having to submit endless patches
+ to update the PATA_PLATFORM entry.
+
config PATA_PLATFORM
tristate "Generic platform device PATA support"
- depends on EMBEDDED || ARCH_RPC || PPC
+ depends on EMBEDDED || ARCH_RPC || PPC || HAVE_PATA_PLATFORM
help
This option enables support for generic directly connected ATA
devices commonly found on embedded systems.
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 97f83fb2ee2e..5e6468a7ca4b 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -89,6 +89,8 @@ enum {
board_ahci_sb600 = 3,
board_ahci_mv = 4,
board_ahci_sb700 = 5,
+ board_ahci_mcp65 = 6,
+ board_ahci_nopmp = 7,
/* global controller registers */
HOST_CAP = 0x00, /* host capabilities */
@@ -190,6 +192,7 @@ enum {
AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */
AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */
AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */
+ AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */
/* ap->flags bits */
@@ -253,6 +256,8 @@ static void ahci_pmp_attach(struct ata_port *ap);
static void ahci_pmp_detach(struct ata_port *ap);
static int ahci_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
+static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline);
static int ahci_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
@@ -329,6 +334,12 @@ static struct ata_port_operations ahci_p5wdh_ops = {
.hardreset = ahci_p5wdh_hardreset,
};
+static struct ata_port_operations ahci_sb600_ops = {
+ .inherits = &ahci_ops,
+ .softreset = ahci_sb600_softreset,
+ .pmp_softreset = ahci_sb600_softreset,
+};
+
#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
static const struct ata_port_info ahci_port_info[] = {
@@ -359,11 +370,11 @@ static const struct ata_port_info ahci_port_info[] = {
{
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
- AHCI_HFLAG_SECT255 | AHCI_HFLAG_NO_PMP),
+ AHCI_HFLAG_SECT255),
.flags = AHCI_FLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
- .port_ops = &ahci_ops,
+ .port_ops = &ahci_sb600_ops,
},
/* board_ahci_mv */
{
@@ -377,8 +388,23 @@ static const struct ata_port_info ahci_port_info[] = {
},
/* board_ahci_sb700 */
{
- AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
- AHCI_HFLAG_NO_PMP),
+ AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL),
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_sb600_ops,
+ },
+ /* board_ahci_mcp65 */
+ {
+ AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ),
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_ops,
+ },
+ /* board_ahci_nopmp */
+ {
+ AHCI_HFLAGS (AHCI_HFLAG_NO_PMP),
.flags = AHCI_FLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
@@ -438,14 +464,14 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
/* NVIDIA */
- { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci }, /* MCP65 */
- { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 }, /* MCP65 */
{ PCI_VDEVICE(NVIDIA, 0x0550), board_ahci }, /* MCP67 */
{ PCI_VDEVICE(NVIDIA, 0x0551), board_ahci }, /* MCP67 */
{ PCI_VDEVICE(NVIDIA, 0x0552), board_ahci }, /* MCP67 */
@@ -502,15 +528,15 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(NVIDIA, 0x0bcd), board_ahci }, /* MCP7B */
{ PCI_VDEVICE(NVIDIA, 0x0bce), board_ahci }, /* MCP7B */
{ PCI_VDEVICE(NVIDIA, 0x0bcf), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bd0), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bd1), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bd2), board_ahci }, /* MCP7B */
- { PCI_VDEVICE(NVIDIA, 0x0bd3), board_ahci }, /* MCP7B */
+ { PCI_VDEVICE(NVIDIA, 0x0bc4), board_ahci }, /* MCP7B */
+ { PCI_VDEVICE(NVIDIA, 0x0bc5), board_ahci }, /* MCP7B */
+ { PCI_VDEVICE(NVIDIA, 0x0bc6), board_ahci }, /* MCP7B */
+ { PCI_VDEVICE(NVIDIA, 0x0bc7), board_ahci }, /* MCP7B */
/* SiS */
- { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
- { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
- { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
+ { PCI_VDEVICE(SI, 0x1184), board_ahci_nopmp }, /* SiS 966 */
+ { PCI_VDEVICE(SI, 0x1185), board_ahci_nopmp }, /* SiS 968 */
+ { PCI_VDEVICE(SI, 0x0186), board_ahci_nopmp }, /* SiS 968 */
/* Marvell */
{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */
@@ -624,12 +650,26 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
cap &= ~HOST_CAP_NCQ;
}
+ if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "controller can do NCQ, turning on CAP_NCQ\n");
+ cap |= HOST_CAP_NCQ;
+ }
+
if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
dev_printk(KERN_INFO, &pdev->dev,
"controller can't do PMP, turning off CAP_PMP\n");
cap &= ~HOST_CAP_PMP;
}
+ if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361 &&
+ port_map != 1) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "JMB361 has only one port, port_map 0x%x -> 0x%x\n",
+ port_map, 1);
+ port_map = 1;
+ }
+
/*
* Temporary Marvell 6145 hack: PATA port presence
* is asserted through the standard AHCI port
@@ -1262,19 +1302,11 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
return 0;
}
-static int ahci_check_ready(struct ata_link *link)
-{
- void __iomem *port_mmio = ahci_port_base(link->ap);
- u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
-
- return ata_check_ready(status);
-}
-
-static int ahci_softreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline)
+static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
+ int pmp, unsigned long deadline,
+ int (*check_ready)(struct ata_link *link))
{
struct ata_port *ap = link->ap;
- int pmp = sata_srst_pmp(link);
const char *reason = NULL;
unsigned long now, msecs;
struct ata_taskfile tf;
@@ -1312,7 +1344,7 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
/* wait for link to become ready */
- rc = ata_wait_after_reset(link, deadline, ahci_check_ready);
+ rc = ata_wait_after_reset(link, deadline, check_ready);
/* link occupied, -ENODEV too is an error */
if (rc) {
reason = "device not ready";
@@ -1328,6 +1360,72 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
return rc;
}
+static int ahci_check_ready(struct ata_link *link)
+{
+ void __iomem *port_mmio = ahci_port_base(link->ap);
+ u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
+
+ return ata_check_ready(status);
+}
+
+static int ahci_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ int pmp = sata_srst_pmp(link);
+
+ DPRINTK("ENTER\n");
+
+ return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
+}
+
+static int ahci_sb600_check_ready(struct ata_link *link)
+{
+ void __iomem *port_mmio = ahci_port_base(link->ap);
+ u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
+ u32 irq_status = readl(port_mmio + PORT_IRQ_STAT);
+
+ /*
+ * There is no need to check TFDATA if BAD PMP is found due to HW bug,
+ * which can save timeout delay.
+ */
+ if (irq_status & PORT_IRQ_BAD_PMP)
+ return -EIO;
+
+ return ata_check_ready(status);
+}
+
+static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ int pmp = sata_srst_pmp(link);
+ int rc;
+ u32 irq_sts;
+
+ DPRINTK("ENTER\n");
+
+ rc = ahci_do_softreset(link, class, pmp, deadline,
+ ahci_sb600_check_ready);
+
+ /*
+ * Soft reset fails on some ATI chips with IPMS set when PMP
+ * is enabled but SATA HDD/ODD is connected to SATA port,
+ * do soft reset again to port 0.
+ */
+ if (rc == -EIO) {
+ irq_sts = readl(port_mmio + PORT_IRQ_STAT);
+ if (irq_sts & PORT_IRQ_BAD_PMP) {
+ ata_link_printk(link, KERN_WARNING,
+ "failed due to HW bug, retry pmp=0\n");
+ rc = ahci_do_softreset(link, class, 0, deadline,
+ ahci_check_ready);
+ }
+ }
+
+ return rc;
+}
+
static int ahci_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
@@ -1679,7 +1777,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
struct ahci_host_priv *hpriv;
unsigned int i, handled = 0;
void __iomem *mmio;
- u32 irq_stat, irq_ack = 0;
+ u32 irq_stat, irq_masked;
VPRINTK("ENTER\n");
@@ -1688,16 +1786,17 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
/* sigh. 0xffffffff is a valid return from h/w */
irq_stat = readl(mmio + HOST_IRQ_STAT);
- irq_stat &= hpriv->port_map;
if (!irq_stat)
return IRQ_NONE;
+ irq_masked = irq_stat & hpriv->port_map;
+
spin_lock(&host->lock);
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap;
- if (!(irq_stat & (1 << i)))
+ if (!(irq_masked & (1 << i)))
continue;
ap = host->ports[i];
@@ -1711,14 +1810,20 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
"interrupt on disabled port %u\n", i);
}
- irq_ack |= (1 << i);
- }
-
- if (irq_ack) {
- writel(irq_ack, mmio + HOST_IRQ_STAT);
handled = 1;
}
+ /* HOST_IRQ_STAT behaves as level triggered latch meaning that
+ * it should be cleared after all the port events are cleared;
+ * otherwise, it will raise a spurious interrupt after each
+ * valid one. Please read section 10.6.2 of ahci 1.1 for more
+ * information.
+ *
+ * Also, use the unmasked value to clear interrupt as spurious
+ * pending event on a dummy port might cause screaming IRQ.
+ */
+ writel(irq_stat, mmio + HOST_IRQ_STAT);
+
spin_unlock(&host->lock);
VPRINTK("EXIT\n");
@@ -2118,7 +2223,8 @@ static void ahci_p5wdh_workaround(struct ata_host *host)
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_port_info pi = ahci_port_info[ent->driver_data];
+ unsigned int board_id = ent->driver_data;
+ struct ata_port_info pi = ahci_port_info[board_id];
const struct ata_port_info *ppi[] = { &pi, NULL };
struct device *dev = &pdev->dev;
struct ahci_host_priv *hpriv;
@@ -2167,6 +2273,11 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return -ENOMEM;
hpriv->flags |= (unsigned long)pi.private_data;
+ /* MCP65 revision A1 and A2 can't do MSI */
+ if (board_id == board_ahci_mcp65 &&
+ (pdev->revision == 0xa1 || pdev->revision == 0xa2))
+ hpriv->flags |= AHCI_HFLAG_NO_MSI;
+
if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
pci_intx(pdev, 1);
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index a9027b8fbdd5..a90ae03f56b2 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -247,10 +247,11 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* SATA Controller 2 IDE (ICH8) */
{ 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
- /* Mobile SATA Controller IDE (ICH8M) */
- { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* Mobile SATA Controller IDE (ICH8M), Apple */
{ 0x8086, 0x2828, 0x106b, 0x00a0, 0, 0, ich8m_apple_sata },
+ { 0x8086, 0x2828, 0x106b, 0x00a1, 0, 0, ich8m_apple_sata },
+ /* Mobile SATA Controller IDE (ICH8M) */
+ { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* SATA Controller IDE (ICH9) */
{ 0x8086, 0x2920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* SATA Controller IDE (ICH9) */
@@ -526,7 +527,7 @@ static struct ata_port_info piix_port_info[] = {
[ich8m_apple_sata] =
{
- .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR,
+ .flags = PIIX_SATA_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA6,
@@ -573,6 +574,8 @@ static const struct ich_laptop ich_laptop[] = {
{ 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */
{ 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */
{ 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */
+ { 0x24CA, 0x1025, 0x003d }, /* ICH4 on ACER TM290 */
+ { 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */
{ 0x2653, 0x1043, 0x82D8 }, /* ICH6M on Asus Eee 701 */
/* end marker */
{ 0, }
@@ -1040,6 +1043,13 @@ static int piix_broken_suspend(void)
},
},
{
+ .ident = "TECRA M4",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M4"),
+ },
+ },
+ {
.ident = "TECRA M5",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 70b77e0899a8..9330b7922f62 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -29,14 +29,16 @@
enum {
ATA_ACPI_FILTER_SETXFER = 1 << 0,
ATA_ACPI_FILTER_LOCK = 1 << 1,
+ ATA_ACPI_FILTER_DIPM = 1 << 2,
ATA_ACPI_FILTER_DEFAULT = ATA_ACPI_FILTER_SETXFER |
- ATA_ACPI_FILTER_LOCK,
+ ATA_ACPI_FILTER_LOCK |
+ ATA_ACPI_FILTER_DIPM,
};
static unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT;
module_param_named(acpi_gtf_filter, ata_acpi_gtf_filter, int, 0644);
-MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock)");
+MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock, 0x4=DIPM)");
#define NO_PORT_MULT 0xffff
#define SATA_ADR(root, pmp) (((root) << 16) | (pmp))
@@ -118,19 +120,86 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
}
+static void ata_acpi_eject_device(acpi_handle handle)
+{
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 1;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
+ &arg_list, NULL)))
+ printk(KERN_ERR "Failed to evaluate _EJ0!\n");
+}
+
+/* @ap and @dev are the same as ata_acpi_handle_hotplug() */
+static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
+{
+ if (dev)
+ dev->flags |= ATA_DFLAG_DETACH;
+ else {
+ struct ata_link *tlink;
+ struct ata_device *tdev;
+
+ ata_port_for_each_link(tlink, ap)
+ ata_link_for_each_dev(tdev, tlink)
+ tdev->flags |= ATA_DFLAG_DETACH;
+ }
+
+ ata_port_schedule_eh(ap);
+}
+
+/**
+ * ata_acpi_handle_hotplug - ACPI event handler backend
+ * @ap: ATA port ACPI event occurred
+ * @dev: ATA device ACPI event occurred (can be NULL)
+ * @event: ACPI event which occurred
+ * @is_dock_event: boolean indicating whether the event was a dock one
+ *
+ * All ACPI bay / device realted events end up in this function. If
+ * the event is port-wide @dev is NULL. If the event is specific to a
+ * device, @dev points to it.
+ *
+ * Hotplug (as opposed to unplug) notification is always handled as
+ * port-wide while unplug only kills the target device on device-wide
+ * event.
+ *
+ * LOCKING:
+ * ACPI notify handler context. May sleep.
+ */
static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
- u32 event)
+ u32 event, int is_dock_event)
{
char event_string[12];
char *envp[] = { event_string, NULL };
- struct ata_eh_info *ehi;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
struct kobject *kobj = NULL;
int wait = 0;
unsigned long flags;
+ acpi_handle handle, tmphandle;
+ unsigned long sta;
+ acpi_status status;
- if (!ap)
- ap = dev->link->ap;
- ehi = &ap->link.eh_info;
+ if (dev) {
+ if (dev->sdev)
+ kobj = &dev->sdev->sdev_gendev.kobj;
+ handle = dev->acpi_handle;
+ } else {
+ kobj = &ap->dev->kobj;
+ handle = ap->acpi_handle;
+ }
+
+ status = acpi_get_handle(handle, "_EJ0", &tmphandle);
+ if (ACPI_FAILURE(status))
+ /* This device does not support hotplug */
+ return;
+
+ if (event == ACPI_NOTIFY_BUS_CHECK ||
+ event == ACPI_NOTIFY_DEVICE_CHECK)
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
spin_lock_irqsave(ap->lock, flags);
@@ -138,57 +207,79 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
ata_ehi_push_desc(ehi, "ACPI event");
- ata_ehi_hotplugged(ehi);
- ata_port_freeze(ap);
- break;
+ if (ACPI_FAILURE(status)) {
+ ata_port_printk(ap, KERN_ERR,
+ "acpi: failed to determine bay status (0x%x)\n",
+ status);
+ break;
+ }
+
+ if (sta) {
+ ata_ehi_hotplugged(ehi);
+ ata_port_freeze(ap);
+ } else {
+ /* The device has gone - unplug it */
+ ata_acpi_detach_device(ap, dev);
+ wait = 1;
+ }
+ break;
case ACPI_NOTIFY_EJECT_REQUEST:
ata_ehi_push_desc(ehi, "ACPI event");
- if (dev)
- dev->flags |= ATA_DFLAG_DETACH;
- else {
- struct ata_link *tlink;
- struct ata_device *tdev;
-
- ata_port_for_each_link(tlink, ap)
- ata_link_for_each_dev(tdev, tlink)
- tdev->flags |= ATA_DFLAG_DETACH;
- }
- ata_port_schedule_eh(ap);
+ if (!is_dock_event)
+ break;
+
+ /* undock event - immediate unplug */
+ ata_acpi_detach_device(ap, dev);
wait = 1;
break;
}
- if (dev) {
- if (dev->sdev)
- kobj = &dev->sdev->sdev_gendev.kobj;
- } else
- kobj = &ap->dev->kobj;
+ /* make sure kobj doesn't go away while ap->lock is released */
+ kobject_get(kobj);
+
+ spin_unlock_irqrestore(ap->lock, flags);
- if (kobj) {
+ if (wait) {
+ ata_port_wait_eh(ap);
+ ata_acpi_eject_device(handle);
+ }
+
+ if (kobj && !is_dock_event) {
sprintf(event_string, "BAY_EVENT=%d", event);
kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
}
- spin_unlock_irqrestore(ap->lock, flags);
+ kobject_put(kobj);
+}
- if (wait)
- ata_port_wait_eh(ap);
+static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
+{
+ struct ata_device *dev = data;
+
+ ata_acpi_handle_hotplug(dev->link->ap, dev, event, 1);
+}
+
+static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data)
+{
+ struct ata_port *ap = data;
+
+ ata_acpi_handle_hotplug(ap, NULL, event, 1);
}
static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
{
struct ata_device *dev = data;
- ata_acpi_handle_hotplug(NULL, dev, event);
+ ata_acpi_handle_hotplug(dev->link->ap, dev, event, 0);
}
static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
{
struct ata_port *ap = data;
- ata_acpi_handle_hotplug(ap, NULL, event);
+ ata_acpi_handle_hotplug(ap, NULL, event, 0);
}
/**
@@ -229,7 +320,7 @@ void ata_acpi_associate(struct ata_host *host)
ata_acpi_ap_notify, ap);
/* we might be on a docking station */
register_hotplug_dock_device(ap->acpi_handle,
- ata_acpi_ap_notify, ap);
+ ata_acpi_ap_notify_dock, ap);
}
for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
@@ -241,7 +332,7 @@ void ata_acpi_associate(struct ata_host *host)
ata_acpi_dev_notify, dev);
/* we might be on a docking station */
register_hotplug_dock_device(dev->acpi_handle,
- ata_acpi_dev_notify, dev);
+ ata_acpi_dev_notify_dock, dev);
}
}
}
@@ -604,6 +695,14 @@ static int ata_acpi_filter_tf(const struct ata_taskfile *tf,
return 1;
}
+ if (ata_acpi_gtf_filter & ATA_ACPI_FILTER_DIPM) {
+ /* inhibit enabling DIPM */
+ if (tf->command == ATA_CMD_SET_FEATURES &&
+ tf->feature == SETFEATURES_SATA_ENABLE &&
+ tf->nsect == SATA_DIPM)
+ return 1;
+ }
+
return 0;
}
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 927b692d723c..303fc0d2b978 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2126,6 +2126,13 @@ int ata_dev_configure(struct ata_device *dev)
dev->horkage |= ata_dev_blacklisted(dev);
ata_force_horkage(dev);
+ if (dev->horkage & ATA_HORKAGE_DISABLE) {
+ ata_dev_printk(dev, KERN_INFO,
+ "unsupported device, disabling\n");
+ ata_dev_disable(dev);
+ return 0;
+ }
+
/* let ACPI work its magic */
rc = ata_acpi_on_devcfg(dev);
if (rc)
@@ -3490,22 +3497,11 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params,
if ((rc = sata_link_debounce(link, params, deadline)))
return rc;
- /* Clear SError. PMP and some host PHYs require this to
- * operate and clearing should be done before checking PHY
- * online status to avoid race condition (hotplugging between
- * link resume and status check).
- */
+ /* clear SError, some PHYs require this even for SRST to work */
if (!(rc = sata_scr_read(link, SCR_ERROR, &serror)))
rc = sata_scr_write(link, SCR_ERROR, serror);
- if (rc == 0 || rc == -EINVAL) {
- unsigned long flags;
- spin_lock_irqsave(link->ap->lock, flags);
- link->eh_info.serror = 0;
- spin_unlock_irqrestore(link->ap->lock, flags);
- rc = 0;
- }
- return rc;
+ return rc != -EINVAL ? rc : 0;
}
/**
@@ -3653,9 +3649,13 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
if (check_ready)
rc = ata_wait_ready(link, deadline, check_ready);
out:
- if (rc && rc != -EAGAIN)
+ if (rc && rc != -EAGAIN) {
+ /* online is set iff link is online && reset succeeded */
+ if (online)
+ *online = false;
ata_link_printk(link, KERN_ERR,
"COMRESET failed (errno=%d)\n", rc);
+ }
DPRINTK("EXIT, rc=%d\n", rc);
return rc;
}
@@ -3700,8 +3700,14 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class,
*/
void ata_std_postreset(struct ata_link *link, unsigned int *classes)
{
+ u32 serror;
+
DPRINTK("ENTER\n");
+ /* reset complete, clear SError */
+ if (!sata_scr_read(link, SCR_ERROR, &serror))
+ sata_scr_write(link, SCR_ERROR, serror);
+
/* print link status */
sata_print_link_status(link);
@@ -3894,8 +3900,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "SAMSUNG CD-ROM SN-124", "N001", ATA_HORKAGE_NODMA },
{ "Seagate STT20000A", NULL, ATA_HORKAGE_NODMA },
/* Odd clown on sil3726/4726 PMPs */
- { "Config Disk", NULL, ATA_HORKAGE_NODMA |
- ATA_HORKAGE_SKIP_PM },
+ { "Config Disk", NULL, ATA_HORKAGE_DISABLE },
/* Weird ATAPI devices */
{ "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 },
@@ -4292,7 +4297,7 @@ void ata_sg_clean(struct ata_queued_cmd *qc)
}
/**
- * ata_check_atapi_dma - Check whether ATAPI DMA can be supported
+ * atapi_check_dma - Check whether ATAPI DMA can be supported
* @qc: Metadata associated with taskfile to check
*
* Allow low-level driver to filter ATA PACKET commands, returning
@@ -4305,7 +4310,7 @@ void ata_sg_clean(struct ata_queued_cmd *qc)
* RETURNS: 0 when ATAPI DMA can be used
* nonzero otherwise
*/
-int ata_check_atapi_dma(struct ata_queued_cmd *qc)
+int atapi_check_dma(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
@@ -5398,7 +5403,7 @@ static void ata_host_stop(struct device *gendev, void *res)
*/
static void ata_finalize_port_ops(struct ata_port_operations *ops)
{
- static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+ static DEFINE_SPINLOCK(lock);
const struct ata_port_operations *cur;
void **begin = (void **)ops;
void **end = (void **)&ops->inherits;
@@ -5616,7 +5621,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
spin_lock_irqsave(ap->lock, flags);
ehi->probe_mask |= ATA_ALL_DEVICES;
- ehi->action |= ATA_EH_RESET;
+ ehi->action |= ATA_EH_RESET | ATA_EH_LPM;
ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
ap->pflags &= ~ATA_PFLAG_INITIALIZING;
@@ -5649,7 +5654,6 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
struct ata_port *ap = host->ports[i];
ata_scsi_scan_host(ap, 1);
- ata_lpm_schedule(ap, ap->pm_policy);
}
return 0;
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 62e033146bed..7894d83ea1eb 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1308,12 +1308,7 @@ static void ata_eh_analyze_serror(struct ata_link *link)
unsigned int err_mask = 0, action = 0;
u32 hotplug_mask;
- if (serror & SERR_PERSISTENT) {
- err_mask |= AC_ERR_ATA_BUS;
- action |= ATA_EH_RESET;
- }
- if (serror &
- (SERR_DATA_RECOVERED | SERR_COMM_RECOVERED | SERR_DATA)) {
+ if (serror & (SERR_PERSISTENT | SERR_DATA)) {
err_mask |= AC_ERR_ATA_BUS;
action |= ATA_EH_RESET;
}
@@ -2047,19 +2042,11 @@ static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
unsigned int *classes, unsigned long deadline)
{
struct ata_device *dev;
- int rc;
ata_link_for_each_dev(dev, link)
classes[dev->devno] = ATA_DEV_UNKNOWN;
- rc = reset(link, classes, deadline);
-
- /* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */
- ata_link_for_each_dev(dev, link)
- if (classes[dev->devno] == ATA_DEV_UNKNOWN)
- classes[dev->devno] = ATA_DEV_NONE;
-
- return rc;
+ return reset(link, classes, deadline);
}
static int ata_eh_followup_srst_needed(struct ata_link *link,
@@ -2096,9 +2083,11 @@ int ata_eh_reset(struct ata_link *link, int classify,
ata_reset_fn_t reset;
unsigned long flags;
u32 sstatus;
- int rc;
+ int nr_known, rc;
- /* about to reset */
+ /*
+ * Prepare to reset
+ */
spin_lock_irqsave(ap->lock, flags);
ap->pflags |= ATA_PFLAG_RESETTING;
spin_unlock_irqrestore(ap->lock, flags);
@@ -2124,16 +2113,8 @@ int ata_eh_reset(struct ata_link *link, int classify,
ap->ops->set_piomode(ap, dev);
}
- if (!softreset && !hardreset) {
- if (verbose)
- ata_link_printk(link, KERN_INFO, "no reset method "
- "available, skipping reset\n");
- if (!(lflags & ATA_LFLAG_ASSUME_CLASS))
- lflags |= ATA_LFLAG_ASSUME_ATA;
- goto done;
- }
-
/* prefer hardreset */
+ reset = NULL;
ehc->i.action &= ~ATA_EH_RESET;
if (hardreset) {
reset = hardreset;
@@ -2141,11 +2122,6 @@ int ata_eh_reset(struct ata_link *link, int classify,
} else if (softreset) {
reset = softreset;
ehc->i.action = ATA_EH_SOFTRESET;
- } else {
- ata_link_printk(link, KERN_ERR, "BUG: no reset method, "
- "please report to linux-ide@vger.kernel.org\n");
- dump_stack();
- return -EINVAL;
}
if (prereset) {
@@ -2165,55 +2141,71 @@ int ata_eh_reset(struct ata_link *link, int classify,
"prereset failed (errno=%d)\n", rc);
goto out;
}
- }
- /* prereset() might have cleared ATA_EH_RESET */
- if (!(ehc->i.action & ATA_EH_RESET)) {
- /* prereset told us not to reset, bang classes and return */
- ata_link_for_each_dev(dev, link)
- classes[dev->devno] = ATA_DEV_NONE;
- rc = 0;
- goto out;
+ /* prereset() might have cleared ATA_EH_RESET. If so,
+ * bang classes and return.
+ */
+ if (reset && !(ehc->i.action & ATA_EH_RESET)) {
+ ata_link_for_each_dev(dev, link)
+ classes[dev->devno] = ATA_DEV_NONE;
+ rc = 0;
+ goto out;
+ }
}
retry:
+ /*
+ * Perform reset
+ */
+ if (ata_is_host_link(link))
+ ata_eh_freeze_port(ap);
+
deadline = jiffies + ata_eh_reset_timeouts[try++];
- /* shut up during boot probing */
- if (verbose)
- ata_link_printk(link, KERN_INFO, "%s resetting link\n",
- reset == softreset ? "soft" : "hard");
+ if (reset) {
+ if (verbose)
+ ata_link_printk(link, KERN_INFO, "%s resetting link\n",
+ reset == softreset ? "soft" : "hard");
- /* mark that this EH session started with reset */
- if (reset == hardreset)
- ehc->i.flags |= ATA_EHI_DID_HARDRESET;
- else
- ehc->i.flags |= ATA_EHI_DID_SOFTRESET;
+ /* mark that this EH session started with reset */
+ if (reset == hardreset)
+ ehc->i.flags |= ATA_EHI_DID_HARDRESET;
+ else
+ ehc->i.flags |= ATA_EHI_DID_SOFTRESET;
- rc = ata_do_reset(link, reset, classes, deadline);
+ rc = ata_do_reset(link, reset, classes, deadline);
- if (reset == hardreset &&
- ata_eh_followup_srst_needed(link, rc, classify, classes)) {
- /* okay, let's do follow-up softreset */
- reset = softreset;
+ if (reset == hardreset &&
+ ata_eh_followup_srst_needed(link, rc, classify, classes)) {
+ /* okay, let's do follow-up softreset */
+ reset = softreset;
- if (!reset) {
- ata_link_printk(link, KERN_ERR,
- "follow-up softreset required "
- "but no softreset avaliable\n");
- rc = -EINVAL;
- goto fail;
+ if (!reset) {
+ ata_link_printk(link, KERN_ERR,
+ "follow-up softreset required "
+ "but no softreset avaliable\n");
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ ata_eh_about_to_do(link, NULL, ATA_EH_RESET);
+ rc = ata_do_reset(link, reset, classes, deadline);
}
- ata_eh_about_to_do(link, NULL, ATA_EH_RESET);
- rc = ata_do_reset(link, reset, classes, deadline);
+ /* -EAGAIN can happen if we skipped followup SRST */
+ if (rc && rc != -EAGAIN)
+ goto fail;
+ } else {
+ if (verbose)
+ ata_link_printk(link, KERN_INFO, "no reset method "
+ "available, skipping reset\n");
+ if (!(lflags & ATA_LFLAG_ASSUME_CLASS))
+ lflags |= ATA_LFLAG_ASSUME_ATA;
}
- /* -EAGAIN can happen if we skipped followup SRST */
- if (rc && rc != -EAGAIN)
- goto fail;
-
- done:
+ /*
+ * Post-reset processing
+ */
ata_link_for_each_dev(dev, link) {
/* After the reset, the device state is PIO 0 and the
* controller state is undefined. Reset also wakes up
@@ -2236,9 +2228,53 @@ int ata_eh_reset(struct ata_link *link, int classify,
if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0)
link->sata_spd = (sstatus >> 4) & 0xf;
+ /* thaw the port */
+ if (ata_is_host_link(link))
+ ata_eh_thaw_port(ap);
+
+ /* postreset() should clear hardware SError. Although SError
+ * is cleared during link resume, clearing SError here is
+ * necessary as some PHYs raise hotplug events after SRST.
+ * This introduces race condition where hotplug occurs between
+ * reset and here. This race is mediated by cross checking
+ * link onlineness and classification result later.
+ */
if (postreset)
postreset(link, classes);
+ /* clear cached SError */
+ spin_lock_irqsave(link->ap->lock, flags);
+ link->eh_info.serror = 0;
+ spin_unlock_irqrestore(link->ap->lock, flags);
+
+ /* Make sure onlineness and classification result correspond.
+ * Hotplug could have happened during reset and some
+ * controllers fail to wait while a drive is spinning up after
+ * being hotplugged causing misdetection. By cross checking
+ * link onlineness and classification result, those conditions
+ * can be reliably detected and retried.
+ */
+ nr_known = 0;
+ ata_link_for_each_dev(dev, link) {
+ /* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */
+ if (classes[dev->devno] == ATA_DEV_UNKNOWN)
+ classes[dev->devno] = ATA_DEV_NONE;
+ else
+ nr_known++;
+ }
+
+ if (classify && !nr_known && ata_link_online(link)) {
+ if (try < max_tries) {
+ ata_link_printk(link, KERN_WARNING, "link online but "
+ "device misclassified, retrying\n");
+ rc = -EAGAIN;
+ goto fail;
+ }
+ ata_link_printk(link, KERN_WARNING,
+ "link online but device misclassified, "
+ "device detection might fail\n");
+ }
+
/* reset successful, schedule revalidation */
ata_eh_done(link, NULL, ATA_EH_RESET);
ehc->i.action |= ATA_EH_REVALIDATE;
@@ -2587,7 +2623,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
struct ata_link *link;
struct ata_device *dev;
int nr_failed_devs, nr_disabled_devs;
- int reset, rc;
+ int rc;
unsigned long flags;
DPRINTK("ENTER\n");
@@ -2630,7 +2666,6 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
rc = 0;
nr_failed_devs = 0;
nr_disabled_devs = 0;
- reset = 0;
/* if UNLOADING, finish immediately */
if (ap->pflags & ATA_PFLAG_UNLOADING)
@@ -2644,40 +2679,24 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
if (ata_eh_skip_recovery(link))
ehc->i.action = 0;
- /* do we need to reset? */
- if (ehc->i.action & ATA_EH_RESET)
- reset = 1;
-
ata_link_for_each_dev(dev, link)
ehc->classes[dev->devno] = ATA_DEV_UNKNOWN;
}
/* reset */
- if (reset) {
- /* if PMP is attached, this function only deals with
- * downstream links, port should stay thawed.
- */
- if (!sata_pmp_attached(ap))
- ata_eh_freeze_port(ap);
-
- ata_port_for_each_link(link, ap) {
- struct ata_eh_context *ehc = &link->eh_context;
+ ata_port_for_each_link(link, ap) {
+ struct ata_eh_context *ehc = &link->eh_context;
- if (!(ehc->i.action & ATA_EH_RESET))
- continue;
+ if (!(ehc->i.action & ATA_EH_RESET))
+ continue;
- rc = ata_eh_reset(link, ata_link_nr_vacant(link),
- prereset, softreset, hardreset,
- postreset);
- if (rc) {
- ata_link_printk(link, KERN_ERR,
- "reset failed, giving up\n");
- goto out;
- }
+ rc = ata_eh_reset(link, ata_link_nr_vacant(link),
+ prereset, softreset, hardreset, postreset);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "reset failed, giving up\n");
+ goto out;
}
-
- if (!sata_pmp_attached(ap))
- ata_eh_thaw_port(ap);
}
/* the rest */
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
index ff1822a7da38..7daf4c0f6216 100644
--- a/drivers/ata/libata-pmp.c
+++ b/drivers/ata/libata-pmp.c
@@ -48,7 +48,7 @@ static unsigned int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val)
tf.device = link->pmp;
err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
- SATA_PMP_SCR_TIMEOUT);
+ SATA_PMP_RW_TIMEOUT);
if (err_mask)
return err_mask;
@@ -88,7 +88,7 @@ static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val)
tf.lbah = (val >> 24) & 0xff;
return ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
- SATA_PMP_SCR_TIMEOUT);
+ SATA_PMP_RW_TIMEOUT);
}
/**
@@ -257,19 +257,6 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info)
goto fail;
}
- /* turn off notification till fan-out ports are reset and configured */
- if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) {
- gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY;
-
- err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN,
- gscr[SATA_PMP_GSCR_FEAT_EN]);
- if (err_mask) {
- rc = -EIO;
- reason = "failed to write GSCR_FEAT_EN";
- goto fail;
- }
- }
-
if (print_info) {
ata_dev_printk(dev, KERN_INFO, "Port Multiplier %s, "
"0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n",
@@ -335,9 +322,12 @@ static void sata_pmp_quirks(struct ata_port *ap)
if (vendor == 0x1095 && devid == 0x3726) {
/* sil3726 quirks */
ata_port_for_each_link(link, ap) {
- /* class code report is unreliable */
+ /* Class code report is unreliable and SRST
+ * times out under certain configurations.
+ */
if (link->pmp < 5)
- link->flags |= ATA_LFLAG_ASSUME_ATA;
+ link->flags |= ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_ATA;
/* port 5 is for SEMB device and it doesn't like SRST */
if (link->pmp == 5)
@@ -700,8 +690,6 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
if (ehc->i.action & ATA_EH_RESET) {
struct ata_link *tlink;
- ata_eh_freeze_port(ap);
-
/* reset */
rc = ata_eh_reset(link, 0, prereset, softreset, hardreset,
postreset);
@@ -711,8 +699,6 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
goto fail;
}
- ata_eh_thaw_port(ap);
-
/* PMP is reset, SErrors cannot be trusted, scan all */
ata_port_for_each_link(tlink, ap) {
struct ata_eh_context *ehc = &tlink->eh_context;
@@ -864,6 +850,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
struct ata_link *pmp_link = &ap->link;
struct ata_device *pmp_dev = pmp_link->device;
struct ata_eh_context *pmp_ehc = &pmp_link->eh_context;
+ u32 *gscr = pmp_dev->gscr;
struct ata_link *link;
struct ata_device *dev;
unsigned int err_mask;
@@ -901,6 +888,22 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
if (rc)
goto pmp_fail;
+ /* PHY event notification can disturb reset and other recovery
+ * operations. Turn it off.
+ */
+ if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) {
+ gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY;
+
+ err_mask = sata_pmp_write(pmp_link, SATA_PMP_GSCR_FEAT_EN,
+ gscr[SATA_PMP_GSCR_FEAT_EN]);
+ if (err_mask) {
+ ata_link_printk(pmp_link, KERN_WARNING,
+ "failed to disable NOTIFY (err_mask=0x%x)\n",
+ err_mask);
+ goto pmp_fail;
+ }
+ }
+
/* handle disabled links */
rc = sata_pmp_eh_handle_disabled_links(ap);
if (rc)
@@ -923,10 +926,10 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
/* enable notification */
if (pmp_dev->flags & ATA_DFLAG_AN) {
- pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
+ gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
- err_mask = sata_pmp_write(pmp_dev->link, SATA_PMP_GSCR_FEAT_EN,
- pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN]);
+ err_mask = sata_pmp_write(pmp_link, SATA_PMP_GSCR_FEAT_EN,
+ gscr[SATA_PMP_GSCR_FEAT_EN]);
if (err_mask) {
ata_dev_printk(pmp_dev, KERN_ERR, "failed to write "
"PMP_FEAT_EN (Emask=0x%x)\n", err_mask);
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 3ce43920e459..57a43649a461 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1082,12 +1082,6 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
if (((cdb[4] >> 4) & 0xf) != 0)
goto invalid_fld; /* power conditions not supported */
- if (qc->dev->horkage & ATA_HORKAGE_SKIP_PM) {
- /* the device lacks PM support, finish without doing anything */
- scmd->result = SAM_STAT_GOOD;
- return 1;
- }
-
if (cdb[4] & 0x1) {
tf->nsect = 1; /* 1 sector, lba=0 */
@@ -1643,6 +1637,7 @@ defer:
/**
* ata_scsi_rbuf_get - Map response buffer.
+ * @cmd: SCSI command containing buffer to be mapped.
* @flags: unsigned long variable to store irq enable status
* @copy_in: copy in from user buffer
*
@@ -1960,7 +1955,7 @@ static unsigned int ata_msense_ctl_mode(u8 *buf)
/**
* ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page
- * @bufp: output buffer
+ * @buf: output buffer
*
* Generate a generic MODE SENSE r/w error recovery page.
*
@@ -2348,8 +2343,8 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
{
struct scsi_cmnd *scmd = qc->scsicmd;
struct ata_device *dev = qc->dev;
- int using_pio = (dev->flags & ATA_DFLAG_PIO);
int nodata = (scmd->sc_data_direction == DMA_NONE);
+ int using_pio = !nodata && (dev->flags & ATA_DFLAG_PIO);
unsigned int nbytes;
memset(qc->cdb, 0, dev->cdb_len);
@@ -2367,7 +2362,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
ata_qc_set_pc_nbytes(qc);
/* check whether ATAPI DMA is safe */
- if (!using_pio && ata_check_atapi_dma(qc))
+ if (!nodata && !using_pio && atapi_check_dma(qc))
using_pio = 1;
/* Some controller variants snoop this value for Packet
@@ -2407,13 +2402,11 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
qc->tf.lbam = (nbytes & 0xFF);
qc->tf.lbah = (nbytes >> 8);
- if (using_pio || nodata) {
- /* no data, or PIO data xfer */
- if (nodata)
- qc->tf.protocol = ATAPI_PROT_NODATA;
- else
- qc->tf.protocol = ATAPI_PROT_PIO;
- } else {
+ if (nodata)
+ qc->tf.protocol = ATAPI_PROT_NODATA;
+ else if (using_pio)
+ qc->tf.protocol = ATAPI_PROT_PIO;
+ else {
/* DMA data xfer */
qc->tf.protocol = ATAPI_PROT_DMA;
qc->tf.feature |= ATAPI_PKT_DMA;
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 3c2d2289f85e..c0908c225483 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -247,7 +247,7 @@ u8 ata_sff_check_status(struct ata_port *ap)
* LOCKING:
* Inherited from caller.
*/
-u8 ata_sff_altstatus(struct ata_port *ap)
+static u8 ata_sff_altstatus(struct ata_port *ap)
{
if (ap->ops->sff_check_altstatus)
return ap->ops->sff_check_altstatus(ap);
@@ -256,6 +256,93 @@ u8 ata_sff_altstatus(struct ata_port *ap)
}
/**
+ * ata_sff_irq_status - Check if the device is busy
+ * @ap: port where the device is
+ *
+ * Determine if the port is currently busy. Uses altstatus
+ * if available in order to avoid clearing shared IRQ status
+ * when finding an IRQ source. Non ctl capable devices don't
+ * share interrupt lines fortunately for us.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static u8 ata_sff_irq_status(struct ata_port *ap)
+{
+ u8 status;
+
+ if (ap->ops->sff_check_altstatus || ap->ioaddr.altstatus_addr) {
+ status = ata_sff_altstatus(ap);
+ /* Not us: We are busy */
+ if (status & ATA_BUSY)
+ return status;
+ }
+ /* Clear INTRQ latch */
+ status = ap->ops->sff_check_status(ap);
+ return status;
+}
+
+/**
+ * ata_sff_sync - Flush writes
+ * @ap: Port to wait for.
+ *
+ * CAUTION:
+ * If we have an mmio device with no ctl and no altstatus
+ * method this will fail. No such devices are known to exist.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+static void ata_sff_sync(struct ata_port *ap)
+{
+ if (ap->ops->sff_check_altstatus)
+ ap->ops->sff_check_altstatus(ap);
+ else if (ap->ioaddr.altstatus_addr)
+ ioread8(ap->ioaddr.altstatus_addr);
+}
+
+/**
+ * ata_sff_pause - Flush writes and wait 400nS
+ * @ap: Port to pause for.
+ *
+ * CAUTION:
+ * If we have an mmio device with no ctl and no altstatus
+ * method this will fail. No such devices are known to exist.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+void ata_sff_pause(struct ata_port *ap)
+{
+ ata_sff_sync(ap);
+ ndelay(400);
+}
+
+/**
+ * ata_sff_dma_pause - Pause before commencing DMA
+ * @ap: Port to pause for.
+ *
+ * Perform I/O fencing and ensure sufficient cycle delays occur
+ * for the HDMA1:0 transition
+ */
+
+void ata_sff_dma_pause(struct ata_port *ap)
+{
+ if (ap->ops->sff_check_altstatus || ap->ioaddr.altstatus_addr) {
+ /* An altstatus read will cause the needed delay without
+ messing up the IRQ status */
+ ata_sff_altstatus(ap);
+ return;
+ }
+ /* There are no DMA controllers without ctl. BUG here to ensure
+ we never violate the HDMA1:0 transition timing and risk
+ corruption. */
+ BUG();
+}
+
+/**
* ata_sff_busy_sleep - sleep until BSY clears, or timeout
* @ap: port containing status register to be polled
* @tmout_pat: impatience timeout
@@ -742,7 +829,7 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc)
} else
ata_pio_sector(qc);
- ata_sff_altstatus(qc->ap); /* flush */
+ ata_sff_sync(qc->ap); /* flush */
}
/**
@@ -763,8 +850,9 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
WARN_ON(qc->dev->cdb_len < 12);
ap->ops->sff_data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1);
- ata_sff_altstatus(ap); /* flush */
-
+ ata_sff_sync(ap);
+ /* FIXME: If the CDB is for DMA do we need to do the transition delay
+ or is bmdma_start guaranteed to do it ? */
switch (qc->tf.protocol) {
case ATAPI_PROT_PIO:
ap->hsm_task_state = HSM_ST;
@@ -905,7 +993,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
if (unlikely(__atapi_pio_bytes(qc, bytes)))
goto err_out;
- ata_sff_altstatus(ap); /* flush */
+ ata_sff_sync(ap); /* flush */
return;
@@ -1006,6 +1094,7 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
u8 status, int in_wq)
{
+ struct ata_eh_info *ehi = &ap->link.eh_info;
unsigned long flags = 0;
int poll_next;
@@ -1037,9 +1126,12 @@ fsm_start:
if (likely(status & (ATA_ERR | ATA_DF)))
/* device stops HSM for abort/error */
qc->err_mask |= AC_ERR_DEV;
- else
+ else {
/* HSM violation. Let EH handle this */
+ ata_ehi_push_desc(ehi,
+ "ST_FIRST: !(DRQ|ERR|DF)");
qc->err_mask |= AC_ERR_HSM;
+ }
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
@@ -1058,9 +1150,9 @@ fsm_start:
* the CDB.
*/
if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) {
- ata_port_printk(ap, KERN_WARNING,
- "DRQ=1 with device error, "
- "dev_stat 0x%X\n", status);
+ ata_ehi_push_desc(ehi, "ST_FIRST: "
+ "DRQ=1 with device error, "
+ "dev_stat 0x%X", status);
qc->err_mask |= AC_ERR_HSM;
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
@@ -1117,9 +1209,9 @@ fsm_start:
* let the EH abort the command or reset the device.
*/
if (unlikely(status & (ATA_ERR | ATA_DF))) {
- ata_port_printk(ap, KERN_WARNING, "DRQ=1 with "
- "device error, dev_stat 0x%X\n",
- status);
+ ata_ehi_push_desc(ehi, "ST-ATAPI: "
+ "DRQ=1 with device error, "
+ "dev_stat 0x%X", status);
qc->err_mask |= AC_ERR_HSM;
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
@@ -1138,13 +1230,17 @@ fsm_start:
if (likely(status & (ATA_ERR | ATA_DF)))
/* device stops HSM for abort/error */
qc->err_mask |= AC_ERR_DEV;
- else
+ else {
/* HSM violation. Let EH handle this.
* Phantom devices also trigger this
* condition. Mark hint.
*/
+ ata_ehi_push_desc(ehi, "ST-ATA: "
+ "DRQ=1 with device error, "
+ "dev_stat 0x%X", status);
qc->err_mask |= AC_ERR_HSM |
AC_ERR_NODEV_HINT;
+ }
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
@@ -1169,8 +1265,12 @@ fsm_start:
status = ata_wait_idle(ap);
}
- if (status & (ATA_BUSY | ATA_DRQ))
+ if (status & (ATA_BUSY | ATA_DRQ)) {
+ ata_ehi_push_desc(ehi, "ST-ATA: "
+ "BUSY|DRQ persists on ERR|DF, "
+ "dev_stat 0x%X", status);
qc->err_mask |= AC_ERR_HSM;
+ }
/* ata_pio_sectors() might change the
* state to HSM_ST_LAST. so, the state
@@ -1489,14 +1589,10 @@ inline unsigned int ata_sff_host_intr(struct ata_port *ap,
goto idle_irq;
}
- /* check altstatus */
- status = ata_sff_altstatus(ap);
- if (status & ATA_BUSY)
- goto idle_irq;
- /* check main status, clearing INTRQ */
- status = ap->ops->sff_check_status(ap);
- if (unlikely(status & ATA_BUSY))
+ /* check main status, clearing INTRQ if needed */
+ status = ata_sff_irq_status(ap);
+ if (status & ATA_BUSY)
goto idle_irq;
/* ack bmdma irq events */
@@ -2030,7 +2126,7 @@ void ata_sff_error_handler(struct ata_port *ap)
ap->ops->bmdma_stop(qc);
}
- ata_sff_altstatus(ap);
+ ata_sff_sync(ap); /* FIXME: We don't need this */
ap->ops->sff_check_status(ap);
ap->ops->sff_irq_clear(ap);
@@ -2203,7 +2299,7 @@ void ata_bmdma_stop(struct ata_queued_cmd *qc)
mmio + ATA_DMA_CMD);
/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
- ata_sff_altstatus(ap); /* dummy read */
+ ata_sff_dma_pause(ap);
}
/**
@@ -2722,7 +2818,8 @@ EXPORT_SYMBOL_GPL(ata_sff_qc_prep);
EXPORT_SYMBOL_GPL(ata_sff_dumb_qc_prep);
EXPORT_SYMBOL_GPL(ata_sff_dev_select);
EXPORT_SYMBOL_GPL(ata_sff_check_status);
-EXPORT_SYMBOL_GPL(ata_sff_altstatus);
+EXPORT_SYMBOL_GPL(ata_sff_dma_pause);
+EXPORT_SYMBOL_GPL(ata_sff_pause);
EXPORT_SYMBOL_GPL(ata_sff_busy_sleep);
EXPORT_SYMBOL_GPL(ata_sff_wait_ready);
EXPORT_SYMBOL_GPL(ata_sff_tf_load);
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 4514283937ea..1cf803adbc95 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -106,7 +106,7 @@ extern void ata_sg_clean(struct ata_queued_cmd *qc);
extern void ata_qc_free(struct ata_queued_cmd *qc);
extern void ata_qc_issue(struct ata_queued_cmd *qc);
extern void __ata_qc_complete(struct ata_queued_cmd *qc);
-extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
+extern int atapi_check_dma(struct ata_queued_cmd *qc);
extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
extern void ata_dev_init(struct ata_device *dev);
extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp);
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index fcabe46f262b..0f3e659db99a 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -177,11 +177,11 @@ static void ali_program_modes(struct ata_port *ap, struct ata_device *adev, stru
u8 udma;
if (t != NULL) {
- t->setup = FIT(t->setup, 1, 8) & 7;
- t->act8b = FIT(t->act8b, 1, 8) & 7;
- t->rec8b = FIT(t->rec8b, 1, 16) & 15;
- t->active = FIT(t->active, 1, 8) & 7;
- t->recover = FIT(t->recover, 1, 16) & 15;
+ t->setup = clamp_val(t->setup, 1, 8) & 7;
+ t->act8b = clamp_val(t->act8b, 1, 8) & 7;
+ t->rec8b = clamp_val(t->rec8b, 1, 16) & 15;
+ t->active = clamp_val(t->active, 1, 8) & 7;
+ t->recover = clamp_val(t->recover, 1, 16) & 15;
pci_write_config_byte(pdev, cas, t->setup);
pci_write_config_byte(pdev, cbt, (t->act8b << 4) | t->rec8b);
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 26665c396485..57dd00f463d3 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -84,32 +84,32 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse
/* Configure the address set up timing */
pci_read_config_byte(pdev, offset + 0x0C, &t);
- t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(at.setup, 1, 4) - 1) << ((3 - dn) << 1));
+ t = (t & ~(3 << ((3 - dn) << 1))) | ((clamp_val(at.setup, 1, 4) - 1) << ((3 - dn) << 1));
pci_write_config_byte(pdev, offset + 0x0C , t);
/* Configure the 8bit I/O timing */
pci_write_config_byte(pdev, offset + 0x0E + (1 - (dn >> 1)),
- ((FIT(at.act8b, 1, 16) - 1) << 4) | (FIT(at.rec8b, 1, 16) - 1));
+ ((clamp_val(at.act8b, 1, 16) - 1) << 4) | (clamp_val(at.rec8b, 1, 16) - 1));
/* Drive timing */
pci_write_config_byte(pdev, offset + 0x08 + (3 - dn),
- ((FIT(at.active, 1, 16) - 1) << 4) | (FIT(at.recover, 1, 16) - 1));
+ ((clamp_val(at.active, 1, 16) - 1) << 4) | (clamp_val(at.recover, 1, 16) - 1));
switch (clock) {
case 1:
- t = at.udma ? (0xc0 | (FIT(at.udma, 2, 5) - 2)) : 0x03;
+ t = at.udma ? (0xc0 | (clamp_val(at.udma, 2, 5) - 2)) : 0x03;
break;
case 2:
- t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 2, 10)]) : 0x03;
+ t = at.udma ? (0xc0 | amd_cyc2udma[clamp_val(at.udma, 2, 10)]) : 0x03;
break;
case 3:
- t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 1, 10)]) : 0x03;
+ t = at.udma ? (0xc0 | amd_cyc2udma[clamp_val(at.udma, 1, 10)]) : 0x03;
break;
case 4:
- t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 1, 15)]) : 0x03;
+ t = at.udma ? (0xc0 | amd_cyc2udma[clamp_val(at.udma, 1, 15)]) : 0x03;
break;
default:
diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c
index 5e104385d6a3..82fb6e273169 100644
--- a/drivers/ata/pata_at32.c
+++ b/drivers/ata/pata_at32.c
@@ -291,8 +291,6 @@ static int __init pata_at32_probe(struct platform_device *pdev)
if (!info)
return -ENOMEM;
- memset(info, 0, sizeof(struct at32_ide_info));
-
info->irq = irq;
info->cs = board->cs;
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
index 9ab89732cf94..55516103626a 100644
--- a/drivers/ata/pata_bf54x.c
+++ b/drivers/ata/pata_bf54x.c
@@ -911,7 +911,10 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
/* Reset all transfer count */
ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST);
- /* Set transfer length to buffer len */
+ /* Set ATAPI state machine contorl in terminate sequence */
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | END_ON_TERM);
+
+ /* Set transfer length to buffer len */
for_each_sg(qc->sg, sg, qc->n_elem, si) {
ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1));
}
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index a9c3218e22fd..2ff62608ae37 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -62,14 +62,14 @@ static void cy82c693_set_piomode(struct ata_port *ap, struct ata_device *adev)
return;
}
- time_16 = FIT(t.recover, 0, 15) | (FIT(t.active, 0, 15) << 4);
- time_8 = FIT(t.act8b, 0, 15) | (FIT(t.rec8b, 0, 15) << 4);
+ time_16 = clamp_val(t.recover, 0, 15) | (clamp_val(t.active, 0, 15) << 4);
+ time_8 = clamp_val(t.act8b, 0, 15) | (clamp_val(t.rec8b, 0, 15) << 4);
if (adev->devno == 0) {
pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr);
addr &= ~0x0F; /* Mask bits */
- addr |= FIT(t.setup, 0, 15);
+ addr |= clamp_val(t.setup, 0, 15);
pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr);
pci_write_config_byte(pdev, CY82_IDE_MASTER_IOR, time_16);
@@ -79,7 +79,7 @@ static void cy82c693_set_piomode(struct ata_port *ap, struct ata_device *adev)
pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr);
addr &= ~0xF0; /* Mask bits */
- addr |= (FIT(t.setup, 0, 15) << 4);
+ addr |= (clamp_val(t.setup, 0, 15) << 4);
pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr);
pci_write_config_byte(pdev, CY82_IDE_SLAVE_IOR, time_16);
diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c
index 17138436423d..cf9e9848f8b5 100644
--- a/drivers/ata/pata_icside.c
+++ b/drivers/ata/pata_icside.c
@@ -270,7 +270,7 @@ static void pata_icside_bmdma_stop(struct ata_queued_cmd *qc)
disable_dma(state->dma);
/* see ata_bmdma_stop */
- ata_sff_altstatus(ap);
+ ata_sff_dma_pause(ap);
}
static u8 pata_icside_bmdma_status(struct ata_port *ap)
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index 7af4b29cc422..fe7cc8ed4ea4 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -343,8 +343,8 @@ static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev)
/* Get the timing data in cycles. For now play safe at 50Mhz */
ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
- active = FIT(t.active, 2, 15);
- recover = FIT(t.recover, 4, 15);
+ active = clamp_val(t.active, 2, 15);
+ recover = clamp_val(t.recover, 4, 15);
inb(0x3E6);
inb(0x3E6);
@@ -377,8 +377,8 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev)
/* Get the timing data in cycles. For now play safe at 50Mhz */
ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
- active = FIT(t.active, 2, 15);
- recover = FIT(t.recover, 2, 16);
+ active = clamp_val(t.active, 2, 15);
+ recover = clamp_val(t.recover, 2, 16);
recover &= 0x15;
inb(0x3E6);
@@ -462,9 +462,9 @@ static void opti82c611a_set_piomode(struct ata_port *ap,
ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);
}
- active = FIT(t.active, 2, 17) - 2;
- recover = FIT(t.recover, 1, 16) - 1;
- setup = FIT(t.setup, 1, 4) - 1;
+ active = clamp_val(t.active, 2, 17) - 2;
+ recover = clamp_val(t.recover, 1, 16) - 1;
+ setup = clamp_val(t.setup, 1, 4) - 1;
/* Select the right timing bank for write timing */
rc = ioread8(ap->ioaddr.lbal_addr);
@@ -541,9 +541,9 @@ static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev)
ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);
}
- active = FIT(t.active, 2, 17) - 2;
- recover = FIT(t.recover, 1, 16) - 1;
- setup = FIT(t.setup, 1, 4) - 1;
+ active = clamp_val(t.active, 2, 17) - 2;
+ recover = clamp_val(t.recover, 1, 16) - 1;
+ setup = clamp_val(t.setup, 1, 4) - 1;
/* Select the right timing bank for write timing */
rc = ioread8(ap->ioaddr.lbal_addr);
@@ -624,11 +624,11 @@ static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev)
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
if (ld_qdi->fast) {
- active = 8 - FIT(t.active, 1, 8);
- recovery = 18 - FIT(t.recover, 3, 18);
+ active = 8 - clamp_val(t.active, 1, 8);
+ recovery = 18 - clamp_val(t.recover, 3, 18);
} else {
- active = 9 - FIT(t.active, 2, 9);
- recovery = 15 - FIT(t.recover, 0, 15);
+ active = 9 - clamp_val(t.active, 2, 9);
+ recovery = 15 - clamp_val(t.recover, 0, 15);
}
timing = (recovery << 4) | active | 0x08;
@@ -658,11 +658,11 @@ static void qdi6580dp_set_piomode(struct ata_port *ap, struct ata_device *adev)
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
if (ld_qdi->fast) {
- active = 8 - FIT(t.active, 1, 8);
- recovery = 18 - FIT(t.recover, 3, 18);
+ active = 8 - clamp_val(t.active, 1, 8);
+ recovery = 18 - clamp_val(t.recover, 3, 18);
} else {
- active = 9 - FIT(t.active, 2, 9);
- recovery = 15 - FIT(t.recover, 0, 15);
+ active = 9 - clamp_val(t.active, 2, 9);
+ recovery = 15 - clamp_val(t.recover, 0, 15);
}
timing = (recovery << 4) | active | 0x08;
@@ -695,11 +695,11 @@ static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev)
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
if (ld_qdi->fast) {
- active = 8 - FIT(t.active, 1, 8);
- recovery = 18 - FIT(t.recover, 3, 18);
+ active = 8 - clamp_val(t.active, 1, 8);
+ recovery = 18 - clamp_val(t.recover, 3, 18);
} else {
- active = 9 - FIT(t.active, 2, 9);
- recovery = 15 - FIT(t.recover, 0, 15);
+ active = 9 - clamp_val(t.active, 2, 9);
+ recovery = 15 - clamp_val(t.recover, 0, 15);
}
timing = (recovery << 4) | active | 0x08;
ld_qdi->clock[adev->devno] = timing;
@@ -830,8 +830,8 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
else
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
- active = (FIT(t.active, 3, 17) - 1) & 0x0F;
- recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F;
+ active = (clamp_val(t.active, 3, 17) - 1) & 0x0F;
+ recovery = (clamp_val(t.recover, 1, 15) + 1) & 0x0F;
timing = (active << 4) | recovery;
winbond_writecfg(ld_winbond->timing, timing, reg);
@@ -842,7 +842,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
reg |= 0x08; /* FIFO off */
if (!ata_pio_need_iordy(adev))
reg |= 0x02; /* IORDY off */
- reg |= (FIT(t.setup, 0, 3) << 6);
+ reg |= (clamp_val(t.setup, 0, 3) << 6);
winbond_writecfg(ld_winbond->timing, timing + 1, reg);
}
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index 76d2455bc453..be756b7ef07e 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -91,9 +91,9 @@ static void ns87410_set_piomode(struct ata_port *ap, struct ata_device *adev)
return;
}
- at.active = FIT(at.active, 2, 16) - 2;
- at.setup = FIT(at.setup, 1, 4) - 1;
- at.recover = FIT(at.recover, 1, 12) - 1;
+ at.active = clamp_val(at.active, 2, 16) - 2;
+ at.setup = clamp_val(at.setup, 1, 4) - 1;
+ at.recover = clamp_val(at.recover, 1, 12) - 1;
idetcr = (at.setup << 6) | (recoverbits[at.recover] << 3) | activebits[at.active];
diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c
index ae92b0049bd5..e0aa7eaaee0a 100644
--- a/drivers/ata/pata_ns87415.c
+++ b/drivers/ata/pata_ns87415.c
@@ -66,8 +66,8 @@ static void ns87415_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mo
ata_timing_compute(adev, adev->pio_mode, &t, T, 0);
- clocking = 17 - FIT(t.active, 2, 17);
- clocking |= (16 - FIT(t.recover, 1, 16)) << 4;
+ clocking = 17 - clamp_val(t.active, 2, 17);
+ clocking |= (16 - clamp_val(t.recover, 1, 16)) << 4;
/* Use the same timing for read and write bytes */
clocking |= (clocking << 8);
pci_write_config_word(dev, timing, clocking);
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 3d39f9dfec5a..41b4361bbf6e 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -414,6 +414,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
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("M-Systems", "CF300", 0x7ed2ad87, 0x7e9e78ee),
PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c),
PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79),
PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
@@ -424,6 +425,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF45", 0x709b1bf1, 0xf68b6f32),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
index bf45cf017753..97e5b090d7c2 100644
--- a/drivers/ata/pata_qdi.c
+++ b/drivers/ata/pata_qdi.c
@@ -60,11 +60,11 @@ static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev)
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
if (qdi->fast) {
- active = 8 - FIT(t.active, 1, 8);
- recovery = 18 - FIT(t.recover, 3, 18);
+ active = 8 - clamp_val(t.active, 1, 8);
+ recovery = 18 - clamp_val(t.recover, 3, 18);
} else {
- active = 9 - FIT(t.active, 2, 9);
- recovery = 15 - FIT(t.recover, 0, 15);
+ active = 9 - clamp_val(t.active, 2, 9);
+ recovery = 15 - clamp_val(t.recover, 0, 15);
}
timing = (recovery << 4) | active | 0x08;
@@ -84,11 +84,11 @@ static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev)
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
if (qdi->fast) {
- active = 8 - FIT(t.active, 1, 8);
- recovery = 18 - FIT(t.recover, 3, 18);
+ active = 8 - clamp_val(t.active, 1, 8);
+ recovery = 18 - clamp_val(t.recover, 3, 18);
} else {
- active = 9 - FIT(t.active, 2, 9);
- recovery = 15 - FIT(t.recover, 0, 15);
+ active = 9 - clamp_val(t.active, 2, 9);
+ recovery = 15 - clamp_val(t.recover, 0, 15);
}
timing = (recovery << 4) | active | 0x08;
diff --git a/drivers/ata/pata_rb532_cf.c b/drivers/ata/pata_rb532_cf.c
index a108d259f19d..f8b3ffc8ae9e 100644
--- a/drivers/ata/pata_rb532_cf.c
+++ b/drivers/ata/pata_rb532_cf.c
@@ -57,7 +57,9 @@ static inline void rb532_pata_finish_io(struct ata_port *ap)
struct ata_host *ah = ap->host;
struct rb532_cf_info *info = ah->private_data;
- ata_sff_altstatus(ap);
+ /* FIXME: Keep previous delay. If this is merely a fence then
+ ata_sff_sync might be sufficient. */
+ ata_sff_dma_pause(ap);
ndelay(RB500_CF_IO_DELAY);
set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH);
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index e965b251ca24..bbf5aa345e68 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -726,7 +726,7 @@ static void scc_bmdma_stop (struct ata_queued_cmd *qc)
in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
- ata_sff_altstatus(ap); /* dummy read */
+ ata_sff_dma_pause(ap); /* dummy read */
}
/**
@@ -747,7 +747,8 @@ static u8 scc_bmdma_status (struct ata_port *ap)
return host_stat;
/* errata A252,A308 workaround: Step4 */
- if ((ata_sff_altstatus(ap) & ATA_ERR) && (int_status & INTSTS_INTRQ))
+ if ((scc_check_altstatus(ap) & ATA_ERR)
+ && (int_status & INTSTS_INTRQ))
return (host_stat | ATA_DMA_INTR);
/* errata A308 workaround Step5 */
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index e82c66e8d31b..26345d7b531c 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -56,6 +56,7 @@ static const struct sis_laptop sis_laptop[] = {
{ 0x5513, 0x1043, 0x1107 }, /* ASUS A6K */
{ 0x5513, 0x1734, 0x105F }, /* FSC Amilo A1630 */
{ 0x5513, 0x1071, 0x8640 }, /* EasyNote K5305 */
+ { 0x5513, 0x1039, 0x5513 }, /* Targa Visionary 1000 */
/* end marker */
{ 0, }
};
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index 70d94fb28a5f..69877bd81815 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -216,7 +216,7 @@ static int sl82c105_qc_defer(struct ata_queued_cmd *qc)
struct ata_port *alt = host->ports[1 ^ qc->ap->port_no];
int rc;
- /* First apply the usual rules */
+ /* First apply the usual rules */
rc = ata_std_qc_defer(qc);
if (rc != 0)
return rc;
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index 2fea6cbe7755..708ed144ede9 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -259,15 +259,15 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo
pci_read_config_byte(pdev, 0x4C, &setup);
setup &= ~(3 << shift);
- setup |= FIT(t.setup, 1, 4) << shift; /* 1,4 or 1,4 - 1 FIXME */
+ setup |= clamp_val(t.setup, 1, 4) << shift; /* 1,4 or 1,4 - 1 FIXME */
pci_write_config_byte(pdev, 0x4C, setup);
}
/* Load the PIO mode bits */
pci_write_config_byte(pdev, 0x4F - ap->port_no,
- ((FIT(t.act8b, 1, 16) - 1) << 4) | (FIT(t.rec8b, 1, 16) - 1));
+ ((clamp_val(t.act8b, 1, 16) - 1) << 4) | (clamp_val(t.rec8b, 1, 16) - 1));
pci_write_config_byte(pdev, 0x48 + offset,
- ((FIT(t.active, 1, 16) - 1) << 4) | (FIT(t.recover, 1, 16) - 1));
+ ((clamp_val(t.active, 1, 16) - 1) << 4) | (clamp_val(t.recover, 1, 16) - 1));
/* Load the UDMA bits according to type */
switch(udma_type) {
@@ -275,16 +275,16 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo
/* BUG() ? */
/* fall through */
case 33:
- ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 5) - 2)) : 0x03;
+ ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 5) - 2)) : 0x03;
break;
case 66:
- ut = t.udma ? (0xe8 | (FIT(t.udma, 2, 9) - 2)) : 0x0f;
+ ut = t.udma ? (0xe8 | (clamp_val(t.udma, 2, 9) - 2)) : 0x0f;
break;
case 100:
- ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07;
+ ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07;
break;
case 133:
- ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07;
+ ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07;
break;
}
diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c
index 6e52a3573fbf..474528f8fe3d 100644
--- a/drivers/ata/pata_winbond.c
+++ b/drivers/ata/pata_winbond.c
@@ -75,8 +75,8 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
else
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
- active = (FIT(t.active, 3, 17) - 1) & 0x0F;
- recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F;
+ active = (clamp_val(t.active, 3, 17) - 1) & 0x0F;
+ recovery = (clamp_val(t.recover, 1, 15) + 1) & 0x0F;
timing = (active << 4) | recovery;
winbond_writecfg(winbond->config, timing, reg);
@@ -87,7 +87,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
reg |= 0x08; /* FIFO off */
if (!ata_pio_need_iordy(adev))
reg |= 0x02; /* IORDY off */
- reg |= (FIT(t.setup, 0, 3) << 6);
+ reg |= (clamp_val(t.setup, 0, 3) << 6);
winbond_writecfg(winbond->config, timing + 1, reg);
}
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 853559e32315..3924e7209a44 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -34,7 +34,7 @@ enum {
SATA_FSL_HOST_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_NCQ),
+ ATA_FLAG_PMP | ATA_FLAG_NCQ),
SATA_FSL_MAX_CMDS = SATA_FSL_QUEUE_DEPTH,
SATA_FSL_CMD_HDR_SIZE = 16, /* 4 DWORDS */
@@ -395,7 +395,7 @@ static void sata_fsl_qc_prep(struct ata_queued_cmd *qc)
cd = (struct command_desc *)pp->cmdentry + tag;
cd_paddr = pp->cmdentry_paddr + tag * SATA_FSL_CMD_DESC_SIZE;
- ata_tf_to_fis(&qc->tf, 0, 1, (u8 *) &cd->cfis);
+ ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, (u8 *) &cd->cfis);
VPRINTK("Dumping cfis : 0x%x, 0x%x, 0x%x\n",
cd->cfis[0], cd->cfis[1], cd->cfis[2]);
@@ -438,6 +438,8 @@ static unsigned int sata_fsl_qc_issue(struct ata_queued_cmd *qc)
ioread32(CA + hcr_base),
ioread32(CE + hcr_base), ioread32(CC + hcr_base));
+ iowrite32(qc->dev->link->pmp, CQPMP + hcr_base);
+
/* Simply queue command to the controller/device */
iowrite32(1 << tag, CQ + hcr_base);
@@ -558,11 +560,36 @@ static void sata_fsl_thaw(struct ata_port *ap)
ioread32(hcr_base + HCONTROL), ioread32(hcr_base + HSTATUS));
}
+static void sata_fsl_pmp_attach(struct ata_port *ap)
+{
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ u32 temp;
+
+ temp = ioread32(hcr_base + HCONTROL);
+ iowrite32((temp | HCONTROL_PMP_ATTACHED), hcr_base + HCONTROL);
+}
+
+static void sata_fsl_pmp_detach(struct ata_port *ap)
+{
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ u32 temp;
+
+ temp = ioread32(hcr_base + HCONTROL);
+ temp &= ~HCONTROL_PMP_ATTACHED;
+ iowrite32(temp, hcr_base + HCONTROL);
+
+ /* enable interrupts on the controller/port */
+ temp = ioread32(hcr_base + HCONTROL);
+ iowrite32((temp | DEFAULT_PORT_IRQ_ENABLE_MASK), hcr_base + HCONTROL);
+
+}
+
static int sata_fsl_port_start(struct ata_port *ap)
{
struct device *dev = ap->host->dev;
struct sata_fsl_port_priv *pp;
- int retval;
void *mem;
dma_addr_t mem_dma;
struct sata_fsl_host_priv *host_priv = ap->host->private_data;
@@ -688,12 +715,13 @@ static int sata_fsl_prereset(struct ata_link *link, unsigned long deadline)
}
static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline)
+ unsigned long deadline)
{
struct ata_port *ap = link->ap;
struct sata_fsl_port_priv *pp = ap->private_data;
struct sata_fsl_host_priv *host_priv = ap->host->private_data;
void __iomem *hcr_base = host_priv->hcr_base;
+ int pmp = sata_srst_pmp(link);
u32 temp;
struct ata_taskfile tf;
u8 *cfis;
@@ -703,6 +731,9 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
DPRINTK("in xx_softreset\n");
+ if (pmp != SATA_PMP_CTRL_PORT)
+ goto issue_srst;
+
try_offline_again:
/*
* Force host controller to go off-line, aborting current operations
@@ -746,6 +777,7 @@ try_offline_again:
temp = ioread32(hcr_base + HCONTROL);
temp |= (HCONTROL_ONLINE_PHY_RST | HCONTROL_SNOOP_ENABLE);
+ temp |= HCONTROL_PMP_ATTACHED;
iowrite32(temp, hcr_base + HCONTROL);
temp = ata_wait_register(hcr_base + HSTATUS, ONLINE, 0, 1, 500);
@@ -771,7 +803,8 @@ try_offline_again:
ata_port_printk(ap, KERN_WARNING,
"No Device OR PHYRDY change,Hstatus = 0x%x\n",
ioread32(hcr_base + HSTATUS));
- goto err;
+ *class = ATA_DEV_NONE;
+ goto out;
}
/*
@@ -783,7 +816,8 @@ try_offline_again:
if ((temp & 0xFF) != 0x18) {
ata_port_printk(ap, KERN_WARNING, "No Signature Update\n");
- goto err;
+ *class = ATA_DEV_NONE;
+ goto out;
} else {
ata_port_printk(ap, KERN_INFO,
"Signature Update detected @ %d msecs\n",
@@ -798,6 +832,7 @@ try_offline_again:
* reached here, we can send a command to the target device
*/
+issue_srst:
DPRINTK("Sending SRST/device reset\n");
ata_tf_init(link->device, &tf);
@@ -808,7 +843,7 @@ try_offline_again:
SRST_CMD | CMD_DESC_SNOOP_ENABLE, 0, 0, 5);
tf.ctl |= ATA_SRST; /* setup SRST bit in taskfile control reg */
- ata_tf_to_fis(&tf, 0, 0, cfis);
+ ata_tf_to_fis(&tf, pmp, 0, cfis);
DPRINTK("Dumping cfis : 0x%x, 0x%x, 0x%x, 0x%x\n",
cfis[0], cfis[1], cfis[2], cfis[3]);
@@ -854,8 +889,10 @@ try_offline_again:
sata_fsl_setup_cmd_hdr_entry(pp, 0, CMD_DESC_SNOOP_ENABLE, 0, 0, 5);
tf.ctl &= ~ATA_SRST; /* 2nd H2D Ctl. register FIS */
- ata_tf_to_fis(&tf, 0, 0, cfis);
+ ata_tf_to_fis(&tf, pmp, 0, cfis);
+ if (pmp != SATA_PMP_CTRL_PORT)
+ iowrite32(pmp, CQPMP + hcr_base);
iowrite32(1, CQ + hcr_base);
msleep(150); /* ?? */
@@ -886,12 +923,21 @@ try_offline_again:
VPRINTK("cereg = 0x%x\n", ioread32(hcr_base + CE));
}
+out:
return 0;
err:
return -EIO;
}
+static void sata_fsl_error_handler(struct ata_port *ap)
+{
+
+ DPRINTK("in xx_error_handler\n");
+ sata_pmp_error_handler(ap);
+
+}
+
static void sata_fsl_post_internal_cmd(struct ata_queued_cmd *qc)
{
if (qc->flags & ATA_QCFLAG_FAILED)
@@ -905,18 +951,21 @@ static void sata_fsl_post_internal_cmd(struct ata_queued_cmd *qc)
static void sata_fsl_error_intr(struct ata_port *ap)
{
- struct ata_link *link = &ap->link;
- struct ata_eh_info *ehi = &link->eh_info;
struct sata_fsl_host_priv *host_priv = ap->host->private_data;
void __iomem *hcr_base = host_priv->hcr_base;
- u32 hstatus, dereg, cereg = 0, SError = 0;
+ u32 hstatus, dereg=0, cereg = 0, SError = 0;
unsigned int err_mask = 0, action = 0;
- struct ata_queued_cmd *qc;
- int freeze = 0;
+ int freeze = 0, abort=0;
+ struct ata_link *link = NULL;
+ struct ata_queued_cmd *qc = NULL;
+ struct ata_eh_info *ehi;
hstatus = ioread32(hcr_base + HSTATUS);
cereg = ioread32(hcr_base + CE);
+ /* first, analyze and record host port events */
+ link = &ap->link;
+ ehi = &link->eh_info;
ata_ehi_clear_desc(ehi);
/*
@@ -926,42 +975,28 @@ static void sata_fsl_error_intr(struct ata_port *ap)
sata_fsl_scr_read(ap, SCR_ERROR, &SError);
if (unlikely(SError & 0xFFFF0000)) {
sata_fsl_scr_write(ap, SCR_ERROR, SError);
- err_mask |= AC_ERR_ATA_BUS;
}
DPRINTK("error_intr,hStat=0x%x,CE=0x%x,DE =0x%x,SErr=0x%x\n",
hstatus, cereg, ioread32(hcr_base + DE), SError);
- /* handle single device errors */
- if (cereg) {
- /*
- * clear the command error, also clears queue to the device
- * in error, and we can (re)issue commands to this device.
- * When a device is in error all commands queued into the
- * host controller and at the device are considered aborted
- * and the queue for that device is stopped. Now, after
- * clearing the device error, we can issue commands to the
- * device to interrogate it to find the source of the error.
- */
- dereg = ioread32(hcr_base + DE);
- iowrite32(dereg, hcr_base + DE);
- iowrite32(cereg, hcr_base + CE);
+ /* handle fatal errors */
+ if (hstatus & FATAL_ERROR_DECODE) {
+ ehi->err_mask |= AC_ERR_ATA_BUS;
+ ehi->action |= ATA_EH_SOFTRESET;
- DPRINTK("single device error, CE=0x%x, DE=0x%x\n",
- ioread32(hcr_base + CE), ioread32(hcr_base + DE));
/*
- * We should consider this as non fatal error, and TF must
- * be updated as done below.
+ * Ignore serror in case of fatal errors as we always want
+ * to do a soft-reset of the FSL SATA controller. Analyzing
+ * serror may cause libata to schedule a hard-reset action,
+ * and hard-reset currently does not do controller
+ * offline/online, causing command timeouts and leads to an
+ * un-recoverable state, hence make libATA ignore
+ * autopsy in case of fatal errors.
*/
- err_mask |= AC_ERR_DEV;
- }
+ ehi->flags |= ATA_EHI_NO_AUTOPSY;
- /* handle fatal errors */
- if (hstatus & FATAL_ERROR_DECODE) {
- err_mask |= AC_ERR_ATA_BUS;
- action |= ATA_EH_RESET;
- /* how will fatal error interrupts be completed ?? */
freeze = 1;
}
@@ -971,30 +1006,83 @@ static void sata_fsl_error_intr(struct ata_port *ap)
/* Setup a soft-reset EH action */
ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, "%s", "PHY RDY changed");
freeze = 1;
}
- /* record error info */
- qc = ata_qc_from_tag(ap, link->active_tag);
+ /* handle single device errors */
+ if (cereg) {
+ /*
+ * clear the command error, also clears queue to the device
+ * in error, and we can (re)issue commands to this device.
+ * When a device is in error all commands queued into the
+ * host controller and at the device are considered aborted
+ * and the queue for that device is stopped. Now, after
+ * clearing the device error, we can issue commands to the
+ * device to interrogate it to find the source of the error.
+ */
+ abort = 1;
+
+ DPRINTK("single device error, CE=0x%x, DE=0x%x\n",
+ ioread32(hcr_base + CE), ioread32(hcr_base + DE));
- if (qc)
+ /* find out the offending link and qc */
+ if (ap->nr_pmp_links) {
+ dereg = ioread32(hcr_base + DE);
+ iowrite32(dereg, hcr_base + DE);
+ iowrite32(cereg, hcr_base + CE);
+
+ if (dereg < ap->nr_pmp_links) {
+ link = &ap->pmp_link[dereg];
+ ehi = &link->eh_info;
+ qc = ata_qc_from_tag(ap, link->active_tag);
+ /*
+ * We should consider this as non fatal error,
+ * and TF must be updated as done below.
+ */
+
+ err_mask |= AC_ERR_DEV;
+
+ } else {
+ err_mask |= AC_ERR_HSM;
+ action |= ATA_EH_HARDRESET;
+ freeze = 1;
+ }
+ } else {
+ dereg = ioread32(hcr_base + DE);
+ iowrite32(dereg, hcr_base + DE);
+ iowrite32(cereg, hcr_base + CE);
+
+ qc = ata_qc_from_tag(ap, link->active_tag);
+ /*
+ * We should consider this as non fatal error,
+ * and TF must be updated as done below.
+ */
+ err_mask |= AC_ERR_DEV;
+ }
+ }
+
+ /* record error info */
+ if (qc) {
qc->err_mask |= err_mask;
- else
+ } else
ehi->err_mask |= err_mask;
ehi->action |= action;
- ehi->serror |= SError;
/* freeze or abort */
if (freeze)
ata_port_freeze(ap);
- else
- ata_port_abort(ap);
+ else if (abort) {
+ if (qc)
+ ata_link_abort(qc->dev->link);
+ else
+ ata_port_abort(ap);
+ }
}
static void sata_fsl_host_intr(struct ata_port *ap)
{
- struct ata_link *link = &ap->link;
struct sata_fsl_host_priv *host_priv = ap->host->private_data;
void __iomem *hcr_base = host_priv->hcr_base;
u32 hstatus, qc_active = 0;
@@ -1017,10 +1105,19 @@ static void sata_fsl_host_intr(struct ata_port *ap)
return;
}
- if (link->sactive) { /* only true for NCQ commands */
+ /* Read command completed register */
+ qc_active = ioread32(hcr_base + CC);
+
+ VPRINTK("Status of all queues :\n");
+ VPRINTK("qc_active/CC = 0x%x, CA = 0x%x, CE=0x%x,CQ=0x%x,apqa=0x%x\n",
+ qc_active,
+ ioread32(hcr_base + CA),
+ ioread32(hcr_base + CE),
+ ioread32(hcr_base + CQ),
+ ap->qc_active);
+
+ if (qc_active & ap->qc_active) {
int i;
- /* Read command completed register */
- qc_active = ioread32(hcr_base + CC);
/* clear CC bit, this will also complete the interrupt */
iowrite32(qc_active, hcr_base + CC);
@@ -1032,8 +1129,9 @@ static void sata_fsl_host_intr(struct ata_port *ap)
for (i = 0; i < SATA_FSL_QUEUE_DEPTH; i++) {
if (qc_active & (1 << i)) {
qc = ata_qc_from_tag(ap, i);
- if (qc)
+ if (qc) {
ata_qc_complete(qc);
+ }
DPRINTK
("completing ncq cmd,tag=%d,CC=0x%x,CA=0x%x\n",
i, ioread32(hcr_base + CC),
@@ -1042,19 +1140,21 @@ static void sata_fsl_host_intr(struct ata_port *ap)
}
return;
- } else if (ap->qc_active) {
+ } else if ((ap->qc_active & (1 << ATA_TAG_INTERNAL))) {
iowrite32(1, hcr_base + CC);
- qc = ata_qc_from_tag(ap, link->active_tag);
+ qc = ata_qc_from_tag(ap, ATA_TAG_INTERNAL);
- DPRINTK("completing non-ncq cmd, tag=%d,CC=0x%x\n",
- link->active_tag, ioread32(hcr_base + CC));
+ DPRINTK("completing non-ncq cmd, CC=0x%x\n",
+ ioread32(hcr_base + CC));
- if (qc)
+ if (qc) {
ata_qc_complete(qc);
+ }
} else {
/* Spurious Interrupt!! */
DPRINTK("spurious interrupt!!, CC = 0x%x\n",
ioread32(hcr_base + CC));
+ iowrite32(qc_active, hcr_base + CC);
return;
}
}
@@ -1130,9 +1230,6 @@ static int sata_fsl_init_controller(struct ata_host *host)
iowrite32(0x00000FFFF, hcr_base + CE);
iowrite32(0x00000FFFF, hcr_base + DE);
- /* initially assuming no Port multiplier, set CQPMP to 0 */
- iowrite32(0x0, hcr_base + CQPMP);
-
/*
* host controller will be brought on-line, during xx_port_start()
* callback, that should also initiate the OOB, COMINIT sequence
@@ -1154,8 +1251,8 @@ static struct scsi_host_template sata_fsl_sht = {
.dma_boundary = ATA_DMA_BOUNDARY,
};
-static const struct ata_port_operations sata_fsl_ops = {
- .inherits = &sata_port_ops,
+static struct ata_port_operations sata_fsl_ops = {
+ .inherits = &sata_pmp_port_ops,
.qc_prep = sata_fsl_qc_prep,
.qc_issue = sata_fsl_qc_issue,
@@ -1168,10 +1265,15 @@ static const struct ata_port_operations sata_fsl_ops = {
.thaw = sata_fsl_thaw,
.prereset = sata_fsl_prereset,
.softreset = sata_fsl_softreset,
+ .pmp_softreset = sata_fsl_softreset,
+ .error_handler = sata_fsl_error_handler,
.post_internal_cmd = sata_fsl_post_internal_cmd,
.port_start = sata_fsl_port_start,
.port_stop = sata_fsl_port_stop,
+
+ .pmp_attach = sata_fsl_pmp_attach,
+ .pmp_detach = sata_fsl_pmp_detach,
};
static const struct ata_port_info sata_fsl_port_info[] = {
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index bb73b2222627..ad169ffbc4cb 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -72,7 +72,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_mv"
-#define DRV_VERSION "1.20"
+#define DRV_VERSION "1.24"
enum {
/* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -122,14 +122,17 @@ enum {
/* Host Flags */
MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */
MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */
- /* SoC integrated controllers, no PCI interface */
- MV_FLAG_SOC = (1 << 28),
MV_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
ATA_FLAG_PIO_POLLING,
+
MV_6XXX_FLAGS = MV_FLAG_IRQ_COALESCE,
+ MV_GENIIE_FLAGS = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+ ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
+ ATA_FLAG_NCQ | ATA_FLAG_AN,
+
CRQB_FLAG_READ = (1 << 0),
CRQB_TAG_SHIFT = 1,
CRQB_IOID_SHIFT = 6, /* CRQB Gen-II/IIE IO Id shift */
@@ -197,13 +200,6 @@ enum {
HC_MAIN_RSVD = (0x7f << 25), /* bits 31-25 */
HC_MAIN_RSVD_5 = (0x1fff << 19), /* bits 31-19 */
HC_MAIN_RSVD_SOC = (0x3fffffb << 6), /* bits 31-9, 7-6 */
- HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_DONE |
- PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
- PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
- HC_MAIN_RSVD),
- HC_MAIN_MASKED_IRQS_5 = (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE |
- HC_MAIN_RSVD_5),
- HC_MAIN_MASKED_IRQS_SOC = (PORTS_0_3_COAL_DONE | HC_MAIN_RSVD_SOC),
/* SATAHC registers */
HC_CFG_OFS = 0,
@@ -221,12 +217,18 @@ enum {
SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */
SATA_ACTIVE_OFS = 0x350,
SATA_FIS_IRQ_CAUSE_OFS = 0x364,
+ SATA_FIS_IRQ_AN = (1 << 9), /* async notification */
LTMODE_OFS = 0x30c,
LTMODE_BIT8 = (1 << 8), /* unknown, but necessary */
PHY_MODE3 = 0x310,
PHY_MODE4 = 0x314,
+ PHY_MODE4_CFG_MASK = 0x00000003, /* phy internal config field */
+ PHY_MODE4_CFG_VALUE = 0x00000001, /* phy internal config field */
+ PHY_MODE4_RSVD_ZEROS = 0x5de3fffa, /* Gen2e always write zeros */
+ PHY_MODE4_RSVD_ONES = 0x00000005, /* Gen2e always write ones */
+
PHY_MODE2 = 0x330,
SATA_IFCTL_OFS = 0x344,
SATA_TESTCTL_OFS = 0x348,
@@ -357,12 +359,12 @@ enum {
MV_HP_ERRATA_50XXB2 = (1 << 2),
MV_HP_ERRATA_60X1B2 = (1 << 3),
MV_HP_ERRATA_60X1C0 = (1 << 4),
- MV_HP_ERRATA_XX42A0 = (1 << 5),
MV_HP_GEN_I = (1 << 6), /* Generation I: 50xx */
MV_HP_GEN_II = (1 << 7), /* Generation II: 60xx */
MV_HP_GEN_IIE = (1 << 8), /* Generation IIE: 6042/7042 */
MV_HP_PCIE = (1 << 9), /* PCIe bus/regs: 7042 */
MV_HP_CUT_THROUGH = (1 << 10), /* can use EDMA cut-through */
+ MV_HP_FLAG_SOC = (1 << 11), /* SystemOnChip, no PCI */
/* Port private flags (pp_flags) */
MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */
@@ -375,7 +377,7 @@ enum {
#define IS_GEN_II(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_II)
#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
#define IS_PCIE(hpriv) ((hpriv)->hp_flags & MV_HP_PCIE)
-#define HAS_PCI(host) (!((host)->ports[0]->flags & MV_FLAG_SOC))
+#define IS_SOC(hpriv) ((hpriv)->hp_flags & MV_HP_FLAG_SOC)
#define WINDOW_CTRL(i) (0x20030 + ((i) << 4))
#define WINDOW_BASE(i) (0x20034 + ((i) << 4))
@@ -459,6 +461,7 @@ struct mv_port_signal {
struct mv_host_priv {
u32 hp_flags;
+ u32 main_irq_mask;
struct mv_port_signal signal[8];
const struct mv_hw_ops *ops;
int n_ports;
@@ -640,25 +643,19 @@ static const struct ata_port_info mv_port_info[] = {
.port_ops = &mv6_ops,
},
{ /* chip_6042 */
- .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
- ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
- ATA_FLAG_NCQ,
+ .flags = MV_GENIIE_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &mv_iie_ops,
},
{ /* chip_7042 */
- .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
- ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
- ATA_FLAG_NCQ,
+ .flags = MV_GENIIE_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &mv_iie_ops,
},
{ /* chip_soc */
- .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
- ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
- ATA_FLAG_NCQ | MV_FLAG_SOC,
+ .flags = MV_GENIIE_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &mv_iie_ops,
@@ -818,12 +815,7 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio,
writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | index,
port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
-
- if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
- writelfl((pp->crqb_dma & 0xffffffff) | index,
- port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
- else
- writelfl(index, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
+ writelfl(index, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
/*
* initialize response queue
@@ -833,17 +825,38 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio,
WARN_ON(pp->crpb_dma & 0xff);
writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
-
- if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
- writelfl((pp->crpb_dma & 0xffffffff) | index,
- port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
- else
- writelfl(index, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
-
+ writelfl(index, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) | index,
port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
}
+static void mv_set_main_irq_mask(struct ata_host *host,
+ u32 disable_bits, u32 enable_bits)
+{
+ struct mv_host_priv *hpriv = host->private_data;
+ u32 old_mask, new_mask;
+
+ old_mask = hpriv->main_irq_mask;
+ new_mask = (old_mask & ~disable_bits) | enable_bits;
+ if (new_mask != old_mask) {
+ hpriv->main_irq_mask = new_mask;
+ writelfl(new_mask, hpriv->main_irq_mask_addr);
+ }
+}
+
+static void mv_enable_port_irqs(struct ata_port *ap,
+ unsigned int port_bits)
+{
+ unsigned int shift, hardport, port = ap->port_no;
+ u32 disable_bits, enable_bits;
+
+ MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport);
+
+ disable_bits = (DONE_IRQ | ERR_IRQ) << shift;
+ enable_bits = port_bits << shift;
+ mv_set_main_irq_mask(ap->host, disable_bits, enable_bits);
+}
+
/**
* mv_start_dma - Enable eDMA engine
* @base: port base address
@@ -886,9 +899,11 @@ static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,
mv_edma_cfg(ap, want_ncq);
/* clear FIS IRQ Cause */
- writelfl(0, port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
+ if (IS_GEN_IIE(hpriv))
+ writelfl(0, port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
mv_set_edma_ptrs(port_mmio, hpriv, pp);
+ mv_enable_port_irqs(ap, DONE_IRQ|ERR_IRQ);
writelfl(EDMA_EN, port_mmio + EDMA_CMD_OFS);
pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
@@ -1231,7 +1246,7 @@ static void mv_edma_cfg(struct ata_port *ap, int want_ncq)
cfg |= (1 << 23); /* do not mask PM field in rx'd FIS */
cfg |= (1 << 22); /* enab 4-entry host queue cache */
- if (HAS_PCI(ap->host))
+ if (!IS_SOC(hpriv))
cfg |= (1 << 18); /* enab early completion */
if (hpriv->hp_flags & MV_HP_CUT_THROUGH)
cfg |= (1 << 17); /* enab cut-thru (dis stor&forwrd) */
@@ -1307,6 +1322,9 @@ static int mv_port_start(struct ata_port *ap)
goto out_port_free_dma_mem;
memset(pp->crpb, 0, MV_CRPB_Q_SZ);
+ /* 6041/6081 Rev. "C0" (and newer) are okay with async notify */
+ if (hpriv->hp_flags & MV_HP_ERRATA_60X1C0)
+ ap->flags |= ATA_FLAG_AN;
/*
* For GEN_I, there's no NCQ, so we only allocate a single sg_tbl.
* For later hardware, we need one unique sg_tbl per NCQ tag.
@@ -1341,6 +1359,7 @@ out_port_free_dma_mem:
static void mv_port_stop(struct ata_port *ap)
{
mv_stop_edma(ap);
+ mv_enable_port_irqs(ap, 0);
mv_port_free_dma_mem(ap);
}
@@ -1576,12 +1595,31 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
if ((qc->tf.protocol != ATA_PROT_DMA) &&
(qc->tf.protocol != ATA_PROT_NCQ)) {
+ static int limit_warnings = 10;
+ /*
+ * Errata SATA#16, SATA#24: warn if multiple DRQs expected.
+ *
+ * Someday, we might implement special polling workarounds
+ * for these, but it all seems rather unnecessary since we
+ * normally use only DMA for commands which transfer more
+ * than a single block of data.
+ *
+ * Much of the time, this could just work regardless.
+ * So for now, just log the incident, and allow the attempt.
+ */
+ if (limit_warnings > 0 && (qc->nbytes / qc->sect_size) > 1) {
+ --limit_warnings;
+ ata_link_printk(qc->dev->link, KERN_WARNING, DRV_NAME
+ ": attempting PIO w/multiple DRQ: "
+ "this may fail due to h/w errata\n");
+ }
/*
* We're about to send a non-EDMA capable command to the
* port. Turn off EDMA so there won't be problems accessing
* shadow block, etc registers.
*/
mv_stop_edma(ap);
+ mv_enable_port_irqs(ap, ERR_IRQ);
mv_pmp_select(ap, qc->dev->link->pmp);
return ata_sff_qc_issue(qc);
}
@@ -1670,6 +1708,18 @@ static void mv_pmp_eh_prep(struct ata_port *ap, unsigned int pmp_map)
}
}
+static int mv_req_q_empty(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+ u32 in_ptr, out_ptr;
+
+ in_ptr = (readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS)
+ >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+ out_ptr = (readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
+ >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+ return (in_ptr == out_ptr); /* 1 == queue_is_empty */
+}
+
static int mv_handle_fbs_ncq_dev_err(struct ata_port *ap)
{
struct mv_port_priv *pp = ap->private_data;
@@ -1703,7 +1753,7 @@ static int mv_handle_fbs_ncq_dev_err(struct ata_port *ap)
ap->qc_active, failed_links,
ap->nr_active_links);
- if (ap->nr_active_links <= failed_links) {
+ if (ap->nr_active_links <= failed_links && mv_req_q_empty(ap)) {
mv_process_crpb_entries(ap, pp);
mv_stop_edma(ap);
mv_eh_freeze(ap);
@@ -1812,6 +1862,7 @@ static void mv_err_intr(struct ata_port *ap)
{
void __iomem *port_mmio = mv_ap_base(ap);
u32 edma_err_cause, eh_freeze_mask, serr = 0;
+ u32 fis_cause = 0;
struct mv_port_priv *pp = ap->private_data;
struct mv_host_priv *hpriv = ap->host->private_data;
unsigned int action = 0, err_mask = 0;
@@ -1821,16 +1872,19 @@ static void mv_err_intr(struct ata_port *ap)
/*
* Read and clear the SError and err_cause bits.
+ * For GenIIe, if EDMA_ERR_TRANS_IRQ_7 is set, we also must read/clear
+ * the FIS_IRQ_CAUSE register before clearing edma_err_cause.
*/
sata_scr_read(&ap->link, SCR_ERROR, &serr);
sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+ if (IS_GEN_IIE(hpriv) && (edma_err_cause & EDMA_ERR_TRANS_IRQ_7)) {
+ fis_cause = readl(port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
+ writelfl(~fis_cause, port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
+ }
writelfl(~edma_err_cause, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
- ata_port_printk(ap, KERN_INFO, "%s: err_cause=%08x pp_flags=0x%x\n",
- __func__, edma_err_cause, pp->pp_flags);
-
if (edma_err_cause & EDMA_ERR_DEV) {
/*
* Device errors during FIS-based switching operation
@@ -1844,6 +1898,18 @@ static void mv_err_intr(struct ata_port *ap)
ata_ehi_clear_desc(ehi);
ata_ehi_push_desc(ehi, "edma_err_cause=%08x pp_flags=%08x",
edma_err_cause, pp->pp_flags);
+
+ if (IS_GEN_IIE(hpriv) && (edma_err_cause & EDMA_ERR_TRANS_IRQ_7)) {
+ ata_ehi_push_desc(ehi, "fis_cause=%08x", fis_cause);
+ if (fis_cause & SATA_FIS_IRQ_AN) {
+ u32 ec = edma_err_cause &
+ ~(EDMA_ERR_TRANS_IRQ_7 | EDMA_ERR_IRQ_TRANSIENT);
+ sata_async_notification(ap);
+ if (!ec)
+ return; /* Just an AN; no need for the nukes */
+ ata_ehi_push_desc(ehi, "SDB notify");
+ }
+ }
/*
* All generations share these EDMA error cause bits:
*/
@@ -2162,20 +2228,20 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
struct ata_host *host = dev_instance;
struct mv_host_priv *hpriv = host->private_data;
unsigned int handled = 0;
- u32 main_irq_cause, main_irq_mask;
+ u32 main_irq_cause, pending_irqs;
spin_lock(&host->lock);
main_irq_cause = readl(hpriv->main_irq_cause_addr);
- main_irq_mask = readl(hpriv->main_irq_mask_addr);
+ pending_irqs = main_irq_cause & hpriv->main_irq_mask;
/*
* Deal with cases where we either have nothing pending, or have read
* a bogus register value which can indicate HW removal or PCI fault.
*/
- if ((main_irq_cause & main_irq_mask) && (main_irq_cause != 0xffffffffU)) {
- if (unlikely((main_irq_cause & PCI_ERR) && HAS_PCI(host)))
+ if (pending_irqs && main_irq_cause != 0xffffffffU) {
+ if (unlikely((pending_irqs & PCI_ERR) && !IS_SOC(hpriv)))
handled = mv_pci_error(host, hpriv->base);
else
- handled = mv_host_intr(host, main_irq_cause);
+ handled = mv_host_intr(host, pending_irqs);
}
spin_unlock(&host->lock);
return IRQ_RETVAL(handled);
@@ -2373,7 +2439,6 @@ static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio)
ZERO(MV_PCI_DISC_TIMER);
ZERO(MV_PCI_MSI_TRIGGER);
writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT_OFS);
- ZERO(PCI_HC_MAIN_IRQ_MASK_OFS);
ZERO(MV_PCI_SERR_MASK);
ZERO(hpriv->irq_cause_ofs);
ZERO(hpriv->irq_mask_ofs);
@@ -2495,7 +2560,7 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
int fix_phy_mode4 =
hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
- u32 m2, tmp;
+ u32 m2, m3;
if (fix_phy_mode2) {
m2 = readl(port_mmio + PHY_MODE2);
@@ -2512,28 +2577,36 @@ static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
udelay(200);
}
- /* who knows what this magic does */
- tmp = readl(port_mmio + PHY_MODE3);
- tmp &= ~0x7F800000;
- tmp |= 0x2A800000;
- writel(tmp, port_mmio + PHY_MODE3);
-
- if (fix_phy_mode4) {
- u32 m4;
-
- m4 = readl(port_mmio + PHY_MODE4);
-
- if (hp_flags & MV_HP_ERRATA_60X1B2)
- tmp = readl(port_mmio + PHY_MODE3);
+ /*
+ * Gen-II/IIe PHY_MODE3 errata RM#2:
+ * Achieves better receiver noise performance than the h/w default:
+ */
+ m3 = readl(port_mmio + PHY_MODE3);
+ m3 = (m3 & 0x1f) | (0x5555601 << 5);
- /* workaround for errata FEr SATA#10 (part 1) */
- m4 = (m4 & ~(1 << 1)) | (1 << 0);
+ /* Guideline 88F5182 (GL# SATA-S11) */
+ if (IS_SOC(hpriv))
+ m3 &= ~0x1c;
+ if (fix_phy_mode4) {
+ u32 m4 = readl(port_mmio + PHY_MODE4);
+ /*
+ * Enforce reserved-bit restrictions on GenIIe devices only.
+ * For earlier chipsets, force only the internal config field
+ * (workaround for errata FEr SATA#10 part 1).
+ */
+ if (IS_GEN_IIE(hpriv))
+ m4 = (m4 & ~PHY_MODE4_RSVD_ZEROS) | PHY_MODE4_RSVD_ONES;
+ else
+ m4 = (m4 & ~PHY_MODE4_CFG_MASK) | PHY_MODE4_CFG_VALUE;
writel(m4, port_mmio + PHY_MODE4);
-
- if (hp_flags & MV_HP_ERRATA_60X1B2)
- writel(tmp, port_mmio + PHY_MODE3);
}
+ /*
+ * Workaround for 60x1-B2 errata SATA#13:
+ * Any write to PHY_MODE4 (above) may corrupt PHY_MODE3,
+ * so we must always rewrite PHY_MODE3 after PHY_MODE4.
+ */
+ writel(m3, port_mmio + PHY_MODE3);
/* Revert values of pre-emphasis and signal amps to the saved ones */
m2 = readl(port_mmio + PHY_MODE2);
@@ -2728,6 +2801,7 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class,
rc = sata_link_hardreset(link, timing, deadline + extra,
&online, NULL);
+ rc = online ? -EAGAIN : rc;
if (rc)
return rc;
sata_scr_read(link, SCR_STATUS, &sstatus);
@@ -2744,32 +2818,18 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class,
static void mv_eh_freeze(struct ata_port *ap)
{
- struct mv_host_priv *hpriv = ap->host->private_data;
- unsigned int shift, hardport, port = ap->port_no;
- u32 main_irq_mask;
-
- /* FIXME: handle coalescing completion events properly */
-
mv_stop_edma(ap);
- MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport);
-
- /* disable assertion of portN err, done events */
- main_irq_mask = readl(hpriv->main_irq_mask_addr);
- main_irq_mask &= ~((DONE_IRQ | ERR_IRQ) << shift);
- writelfl(main_irq_mask, hpriv->main_irq_mask_addr);
+ mv_enable_port_irqs(ap, 0);
}
static void mv_eh_thaw(struct ata_port *ap)
{
struct mv_host_priv *hpriv = ap->host->private_data;
- unsigned int shift, hardport, port = ap->port_no;
+ unsigned int port = ap->port_no;
+ unsigned int hardport = mv_hardport_from_port(port);
void __iomem *hc_mmio = mv_hc_base_from_port(hpriv->base, port);
void __iomem *port_mmio = mv_ap_base(ap);
- u32 main_irq_mask, hc_irq_cause;
-
- /* FIXME: handle coalescing completion events properly */
-
- MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport);
+ u32 hc_irq_cause;
/* clear EDMA errors on this port */
writel(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
@@ -2779,10 +2839,7 @@ static void mv_eh_thaw(struct ata_port *ap)
hc_irq_cause &= ~((DEV_IRQ | DMA_IRQ) << hardport);
writelfl(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
- /* enable assertion of portN err, done events */
- main_irq_mask = readl(hpriv->main_irq_mask_addr);
- main_irq_mask |= ((DONE_IRQ | ERR_IRQ) << shift);
- writelfl(main_irq_mask, hpriv->main_irq_mask_addr);
+ mv_enable_port_irqs(ap, ERR_IRQ);
}
/**
@@ -2840,7 +2897,7 @@ static unsigned int mv_in_pcix_mode(struct ata_host *host)
void __iomem *mmio = hpriv->base;
u32 reg;
- if (!HAS_PCI(host) || !IS_PCIE(hpriv))
+ if (IS_SOC(hpriv) || !IS_PCIE(hpriv))
return 0; /* not PCI-X capable */
reg = readl(mmio + MV_PCI_MODE_OFS);
if ((reg & MV_PCI_MODE_MASK) == 0)
@@ -2967,10 +3024,7 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
hp_flags |= MV_HP_CUT_THROUGH;
switch (pdev->revision) {
- case 0x0:
- hp_flags |= MV_HP_ERRATA_XX42A0;
- break;
- case 0x1:
+ case 0x2: /* Rev.B0: the first/only public release */
hp_flags |= MV_HP_ERRATA_60X1C0;
break;
default:
@@ -2982,7 +3036,7 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
break;
case chip_soc:
hpriv->ops = &mv_soc_ops;
- hp_flags |= MV_HP_ERRATA_60X1C0;
+ hp_flags |= MV_HP_FLAG_SOC | MV_HP_ERRATA_60X1C0;
break;
default:
@@ -3026,16 +3080,16 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
if (rc)
goto done;
- if (HAS_PCI(host)) {
- hpriv->main_irq_cause_addr = mmio + PCI_HC_MAIN_IRQ_CAUSE_OFS;
- hpriv->main_irq_mask_addr = mmio + PCI_HC_MAIN_IRQ_MASK_OFS;
- } else {
+ if (IS_SOC(hpriv)) {
hpriv->main_irq_cause_addr = mmio + SOC_HC_MAIN_IRQ_CAUSE_OFS;
hpriv->main_irq_mask_addr = mmio + SOC_HC_MAIN_IRQ_MASK_OFS;
+ } else {
+ hpriv->main_irq_cause_addr = mmio + PCI_HC_MAIN_IRQ_CAUSE_OFS;
+ hpriv->main_irq_mask_addr = mmio + PCI_HC_MAIN_IRQ_MASK_OFS;
}
/* global interrupt mask: 0 == mask everything */
- writel(0, hpriv->main_irq_mask_addr);
+ mv_set_main_irq_mask(host, ~0, 0);
n_hc = mv_get_hc_count(host->ports[0]->flags);
@@ -3057,7 +3111,7 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
mv_port_init(&ap->ioaddr, port_mmio);
#ifdef CONFIG_PCI
- if (HAS_PCI(host)) {
+ if (!IS_SOC(hpriv)) {
unsigned int offset = port_mmio - mmio;
ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
@@ -3077,31 +3131,18 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
}
- if (HAS_PCI(host)) {
+ if (!IS_SOC(hpriv)) {
/* Clear any currently outstanding host interrupt conditions */
writelfl(0, mmio + hpriv->irq_cause_ofs);
/* and unmask interrupt generation for host regs */
writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
- if (IS_GEN_I(hpriv))
- writelfl(~HC_MAIN_MASKED_IRQS_5,
- hpriv->main_irq_mask_addr);
- else
- writelfl(~HC_MAIN_MASKED_IRQS,
- hpriv->main_irq_mask_addr);
-
- VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
- "PCI int cause/mask=0x%08x/0x%08x\n",
- readl(hpriv->main_irq_cause_addr),
- readl(hpriv->main_irq_mask_addr),
- readl(mmio + hpriv->irq_cause_ofs),
- readl(mmio + hpriv->irq_mask_ofs));
- } else {
- writelfl(~HC_MAIN_MASKED_IRQS_SOC,
- hpriv->main_irq_mask_addr);
- VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x\n",
- readl(hpriv->main_irq_cause_addr),
- readl(hpriv->main_irq_mask_addr));
+
+ /*
+ * enable only global host interrupts for now.
+ * The per-port interrupts get done later as ports are set up.
+ */
+ mv_set_main_irq_mask(host, 0, PCI_ERR);
}
done:
return rc;
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index 5a10dc5048ad..030665ba76b7 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -53,7 +53,15 @@ enum {
PDC_MMIO_BAR = 3,
PDC_MAX_PRD = LIBATA_MAX_PRD - 1, /* -1 for ASIC PRD bug workaround */
- /* register offsets */
+ /* host register offsets (from host->iomap[PDC_MMIO_BAR]) */
+ PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
+ PDC_FLASH_CTL = 0x44, /* Flash control register */
+ PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */
+ PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */
+ PDC_TBG_MODE = 0x41C, /* TBG mode (not SATAII) */
+ PDC_SLEW_CTL = 0x470, /* slew rate control reg (not SATAII) */
+
+ /* per-port ATA register offsets (from ap->ioaddr.cmd_addr) */
PDC_FEATURE = 0x04, /* Feature/Error reg (per port) */
PDC_SECTOR_COUNT = 0x08, /* Sector count reg (per port) */
PDC_SECTOR_NUMBER = 0x0C, /* Sector number reg (per port) */
@@ -63,14 +71,11 @@ enum {
PDC_COMMAND = 0x1C, /* Command/status reg (per port) */
PDC_ALTSTATUS = 0x38, /* Alternate-status/device-control reg (per port) */
PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
- PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
- PDC_FLASH_CTL = 0x44, /* Flash control register */
PDC_GLOBAL_CTL = 0x48, /* Global control/status (per port) */
PDC_CTLSTAT = 0x60, /* IDE control and status (per port) */
- PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */
- PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */
- PDC_TBG_MODE = 0x41C, /* TBG mode (not SATAII) */
- PDC_SLEW_CTL = 0x470, /* slew rate control reg (not SATAII) */
+
+ /* per-port SATA register offsets (from ap->ioaddr.scr_addr) */
+ PDC_PHYMODE4 = 0x14,
/* PDC_GLOBAL_CTL bit definitions */
PDC_PH_ERR = (1 << 8), /* PCI error while loading packet */
@@ -134,7 +139,7 @@ struct pdc_port_priv {
static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
-static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static int pdc_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int pdc_common_port_start(struct ata_port *ap);
static int pdc_sata_port_start(struct ata_port *ap);
static void pdc_qc_prep(struct ata_queued_cmd *qc);
@@ -332,12 +337,12 @@ static int pdc_sata_port_start(struct ata_port *ap)
/* fix up PHYMODE4 align timing */
if (ap->flags & PDC_FLAG_GEN_II) {
- void __iomem *mmio = ap->ioaddr.scr_addr;
+ void __iomem *sata_mmio = ap->ioaddr.scr_addr;
unsigned int tmp;
- tmp = readl(mmio + 0x014);
+ tmp = readl(sata_mmio + PDC_PHYMODE4);
tmp = (tmp & ~3) | 1; /* set bits 1:0 = 0:1 */
- writel(tmp, mmio + 0x014);
+ writel(tmp, sata_mmio + PDC_PHYMODE4);
}
return 0;
@@ -345,32 +350,32 @@ static int pdc_sata_port_start(struct ata_port *ap)
static void pdc_reset_port(struct ata_port *ap)
{
- void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT;
+ void __iomem *ata_ctlstat_mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT;
unsigned int i;
u32 tmp;
for (i = 11; i > 0; i--) {
- tmp = readl(mmio);
+ tmp = readl(ata_ctlstat_mmio);
if (tmp & PDC_RESET)
break;
udelay(100);
tmp |= PDC_RESET;
- writel(tmp, mmio);
+ writel(tmp, ata_ctlstat_mmio);
}
tmp &= ~PDC_RESET;
- writel(tmp, mmio);
- readl(mmio); /* flush */
+ writel(tmp, ata_ctlstat_mmio);
+ readl(ata_ctlstat_mmio); /* flush */
}
static int pdc_pata_cable_detect(struct ata_port *ap)
{
u8 tmp;
- void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03;
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
- tmp = readb(mmio);
+ tmp = readb(ata_mmio + PDC_CTLSTAT + 3);
if (tmp & 0x01)
return ATA_CBL_PATA40;
return ATA_CBL_PATA80;
@@ -557,31 +562,25 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc)
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
pdc_fill_sg(qc);
- /* fall through */
-
+ /*FALLTHROUGH*/
case ATA_PROT_NODATA:
i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma,
qc->dev->devno, pp->pkt);
-
if (qc->tf.flags & ATA_TFLAG_LBA48)
i = pdc_prep_lba48(&qc->tf, pp->pkt, i);
else
i = pdc_prep_lba28(&qc->tf, pp->pkt, i);
-
pdc_pkt_footer(&qc->tf, pp->pkt, i);
break;
-
case ATAPI_PROT_PIO:
pdc_fill_sg(qc);
break;
-
case ATAPI_PROT_DMA:
pdc_fill_sg(qc);
/*FALLTHROUGH*/
case ATAPI_PROT_NODATA:
pdc_atapi_pkt(qc);
break;
-
default:
break;
}
@@ -611,7 +610,7 @@ static unsigned int pdc_sata_ata_port_to_ata_no(const struct ata_port *ap)
unsigned int nr_ports = pdc_sata_nr_ports(ap);
unsigned int i;
- for(i = 0; i < nr_ports && host->ports[i] != ap; ++i)
+ for (i = 0; i < nr_ports && host->ports[i] != ap; ++i)
;
BUG_ON(i >= nr_ports);
return pdc_port_no_to_ata_no(i, pdc_is_sataii_tx4(ap->flags));
@@ -624,14 +623,14 @@ static unsigned int pdc_sata_hotplug_offset(const struct ata_port *ap)
static void pdc_freeze(struct ata_port *ap)
{
- void __iomem *mmio = ap->ioaddr.cmd_addr;
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
u32 tmp;
- tmp = readl(mmio + PDC_CTLSTAT);
+ tmp = readl(ata_mmio + PDC_CTLSTAT);
tmp |= PDC_IRQ_DISABLE;
tmp &= ~PDC_DMA_ENABLE;
- writel(tmp, mmio + PDC_CTLSTAT);
- readl(mmio + PDC_CTLSTAT); /* flush */
+ writel(tmp, ata_mmio + PDC_CTLSTAT);
+ readl(ata_mmio + PDC_CTLSTAT); /* flush */
}
static void pdc_sata_freeze(struct ata_port *ap)
@@ -659,17 +658,17 @@ static void pdc_sata_freeze(struct ata_port *ap)
static void pdc_thaw(struct ata_port *ap)
{
- void __iomem *mmio = ap->ioaddr.cmd_addr;
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
u32 tmp;
/* clear IRQ */
- readl(mmio + PDC_INT_SEQMASK);
+ readl(ata_mmio + PDC_COMMAND);
/* turn IRQ back on */
- tmp = readl(mmio + PDC_CTLSTAT);
+ tmp = readl(ata_mmio + PDC_CTLSTAT);
tmp &= ~PDC_IRQ_DISABLE;
- writel(tmp, mmio + PDC_CTLSTAT);
- readl(mmio + PDC_CTLSTAT); /* flush */
+ writel(tmp, ata_mmio + PDC_CTLSTAT);
+ readl(ata_mmio + PDC_CTLSTAT); /* flush */
}
static void pdc_sata_thaw(struct ata_port *ap)
@@ -743,11 +742,11 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
ata_port_abort(ap);
}
-static inline unsigned int pdc_host_intr(struct ata_port *ap,
- struct ata_queued_cmd *qc)
+static unsigned int pdc_host_intr(struct ata_port *ap,
+ struct ata_queued_cmd *qc)
{
unsigned int handled = 0;
- void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
u32 port_status, err_mask;
err_mask = PDC_ERR_MASK;
@@ -755,7 +754,7 @@ static inline unsigned int pdc_host_intr(struct ata_port *ap,
err_mask &= ~PDC1_ERR_MASK;
else
err_mask &= ~PDC2_ERR_MASK;
- port_status = readl(port_mmio + PDC_GLOBAL_CTL);
+ port_status = readl(ata_mmio + PDC_GLOBAL_CTL);
if (unlikely(port_status & err_mask)) {
pdc_error_intr(ap, qc, port_status, err_mask);
return 1;
@@ -770,7 +769,6 @@ static inline unsigned int pdc_host_intr(struct ata_port *ap,
ata_qc_complete(qc);
handled = 1;
break;
-
default:
ap->stats.idle_irq++;
break;
@@ -781,10 +779,9 @@ static inline unsigned int pdc_host_intr(struct ata_port *ap,
static void pdc_irq_clear(struct ata_port *ap)
{
- struct ata_host *host = ap->host;
- void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
- readl(mmio + PDC_INT_SEQMASK);
+ readl(ata_mmio + PDC_COMMAND);
}
static irqreturn_t pdc_interrupt(int irq, void *dev_instance)
@@ -794,7 +791,7 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance)
u32 mask = 0;
unsigned int i, tmp;
unsigned int handled = 0;
- void __iomem *mmio_base;
+ void __iomem *host_mmio;
unsigned int hotplug_offset, ata_no;
u32 hotplug_status;
int is_sataii_tx4;
@@ -806,7 +803,7 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance)
return IRQ_NONE;
}
- mmio_base = host->iomap[PDC_MMIO_BAR];
+ host_mmio = host->iomap[PDC_MMIO_BAR];
spin_lock(&host->lock);
@@ -815,26 +812,26 @@ static irqreturn_t pdc_interrupt(int irq, void *dev_instance)
hotplug_offset = PDC2_SATA_PLUG_CSR;
else
hotplug_offset = PDC_SATA_PLUG_CSR;
- hotplug_status = readl(mmio_base + hotplug_offset);
+ hotplug_status = readl(host_mmio + hotplug_offset);
if (hotplug_status & 0xff)
- writel(hotplug_status | 0xff, mmio_base + hotplug_offset);
+ writel(hotplug_status | 0xff, host_mmio + hotplug_offset);
hotplug_status &= 0xff; /* clear uninteresting bits */
/* reading should also clear interrupts */
- mask = readl(mmio_base + PDC_INT_SEQMASK);
+ mask = readl(host_mmio + PDC_INT_SEQMASK);
if (mask == 0xffffffff && hotplug_status == 0) {
VPRINTK("QUICK EXIT 2\n");
goto done_irq;
}
- mask &= 0xffff; /* only 16 tags possible */
+ mask &= 0xffff; /* only 16 SEQIDs possible */
if (mask == 0 && hotplug_status == 0) {
VPRINTK("QUICK EXIT 3\n");
goto done_irq;
}
- writel(mask, mmio_base + PDC_INT_SEQMASK);
+ writel(mask, host_mmio + PDC_INT_SEQMASK);
is_sataii_tx4 = pdc_is_sataii_tx4(host->ports[0]->flags);
@@ -875,23 +872,24 @@ done_irq:
return IRQ_RETVAL(handled);
}
-static inline void pdc_packet_start(struct ata_queued_cmd *qc)
+static void pdc_packet_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct pdc_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR];
+ void __iomem *host_mmio = ap->host->iomap[PDC_MMIO_BAR];
+ void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
unsigned int port_no = ap->port_no;
u8 seq = (u8) (port_no + 1);
VPRINTK("ENTER, ap %p\n", ap);
- writel(0x00000001, mmio + (seq * 4));
- readl(mmio + (seq * 4)); /* flush */
+ writel(0x00000001, host_mmio + (seq * 4));
+ readl(host_mmio + (seq * 4)); /* flush */
pp->pkt[2] = seq;
wmb(); /* flush PRD, pkt writes */
- writel(pp->pkt_dma, ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
+ writel(pp->pkt_dma, ata_mmio + PDC_PKT_SUBMIT);
+ readl(ata_mmio + PDC_PKT_SUBMIT); /* flush */
}
static unsigned int pdc_qc_issue(struct ata_queued_cmd *qc)
@@ -909,11 +907,9 @@ static unsigned int pdc_qc_issue(struct ata_queued_cmd *qc)
case ATA_PROT_DMA:
pdc_packet_start(qc);
return 0;
-
default:
break;
}
-
return ata_sff_qc_issue(qc);
}
@@ -987,7 +983,7 @@ static void pdc_ata_setup_port(struct ata_port *ap,
static void pdc_host_init(struct ata_host *host)
{
- void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+ void __iomem *host_mmio = host->iomap[PDC_MMIO_BAR];
int is_gen2 = host->ports[0]->flags & PDC_FLAG_GEN_II;
int hotplug_offset;
u32 tmp;
@@ -1004,38 +1000,38 @@ static void pdc_host_init(struct ata_host *host)
*/
/* enable BMR_BURST, maybe change FIFO_SHD to 8 dwords */
- tmp = readl(mmio + PDC_FLASH_CTL);
+ tmp = readl(host_mmio + PDC_FLASH_CTL);
tmp |= 0x02000; /* bit 13 (enable bmr burst) */
if (!is_gen2)
tmp |= 0x10000; /* bit 16 (fifo threshold at 8 dw) */
- writel(tmp, mmio + PDC_FLASH_CTL);
+ writel(tmp, host_mmio + PDC_FLASH_CTL);
/* clear plug/unplug flags for all ports */
- tmp = readl(mmio + hotplug_offset);
- writel(tmp | 0xff, mmio + hotplug_offset);
+ tmp = readl(host_mmio + hotplug_offset);
+ writel(tmp | 0xff, host_mmio + hotplug_offset);
/* unmask plug/unplug ints */
- tmp = readl(mmio + hotplug_offset);
- writel(tmp & ~0xff0000, mmio + hotplug_offset);
+ tmp = readl(host_mmio + hotplug_offset);
+ writel(tmp & ~0xff0000, host_mmio + hotplug_offset);
/* don't initialise TBG or SLEW on 2nd generation chips */
if (is_gen2)
return;
/* reduce TBG clock to 133 Mhz. */
- tmp = readl(mmio + PDC_TBG_MODE);
+ tmp = readl(host_mmio + PDC_TBG_MODE);
tmp &= ~0x30000; /* clear bit 17, 16*/
tmp |= 0x10000; /* set bit 17:16 = 0:1 */
- writel(tmp, mmio + PDC_TBG_MODE);
+ writel(tmp, host_mmio + PDC_TBG_MODE);
- readl(mmio + PDC_TBG_MODE); /* flush */
+ readl(host_mmio + PDC_TBG_MODE); /* flush */
msleep(10);
/* adjust slew rate control register. */
- tmp = readl(mmio + PDC_SLEW_CTL);
+ tmp = readl(host_mmio + PDC_SLEW_CTL);
tmp &= 0xFFFFF03F; /* clear bit 11 ~ 6 */
tmp |= 0x00000900; /* set bit 11-9 = 100b , bit 8-6 = 100 */
- writel(tmp, mmio + PDC_SLEW_CTL);
+ writel(tmp, host_mmio + PDC_SLEW_CTL);
}
static int pdc_ata_init_one(struct pci_dev *pdev,
@@ -1045,7 +1041,7 @@ static int pdc_ata_init_one(struct pci_dev *pdev,
const struct ata_port_info *pi = &pdc_port_info[ent->driver_data];
const struct ata_port_info *ppi[PDC_MAX_PORTS];
struct ata_host *host;
- void __iomem *base;
+ void __iomem *host_mmio;
int n_ports, i, rc;
int is_sataii_tx4;
@@ -1062,7 +1058,7 @@ static int pdc_ata_init_one(struct pci_dev *pdev,
pcim_pin_device(pdev);
if (rc)
return rc;
- base = pcim_iomap_table(pdev)[PDC_MMIO_BAR];
+ host_mmio = pcim_iomap_table(pdev)[PDC_MMIO_BAR];
/* determine port configuration and setup host */
n_ports = 2;
@@ -1072,7 +1068,7 @@ static int pdc_ata_init_one(struct pci_dev *pdev,
ppi[i] = pi;
if (pi->flags & PDC_FLAG_SATA_PATA) {
- u8 tmp = readb(base + PDC_FLASH_CTL+1);
+ u8 tmp = readb(host_mmio + PDC_FLASH_CTL + 1);
if (!(tmp & 0x80))
ppi[n_ports++] = pi + 1;
}
@@ -1088,13 +1084,13 @@ static int pdc_ata_init_one(struct pci_dev *pdev,
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
unsigned int ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4);
- unsigned int port_offset = 0x200 + ata_no * 0x80;
+ unsigned int ata_offset = 0x200 + ata_no * 0x80;
unsigned int scr_offset = 0x400 + ata_no * 0x100;
- pdc_ata_setup_port(ap, base + port_offset, base + scr_offset);
+ pdc_ata_setup_port(ap, host_mmio + ata_offset, host_mmio + scr_offset);
ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
- ata_port_pbar_desc(ap, PDC_MMIO_BAR, port_offset, "port");
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, ata_offset, "ata");
}
/* initialize adapter */
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 27a110110077..84ffcc26a74b 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -370,6 +370,7 @@ static const struct pci_device_id sil24_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x3124), BID_SIL3124 },
{ PCI_VDEVICE(CMD, 0x3132), BID_SIL3132 },
{ PCI_VDEVICE(CMD, 0x0242), BID_SIL3132 },
+ { PCI_VDEVICE(CMD, 0x0244), BID_SIL3132 },
{ PCI_VDEVICE(CMD, 0x3131), BID_SIL3131 },
{ PCI_VDEVICE(CMD, 0x3531), BID_SIL3131 },
@@ -899,14 +900,25 @@ static bool sil24_qc_fill_rtf(struct ata_queued_cmd *qc)
static void sil24_pmp_attach(struct ata_port *ap)
{
+ u32 *gscr = ap->link.device->gscr;
+
sil24_config_pmp(ap, 1);
sil24_init_port(ap);
+
+ if (sata_pmp_gscr_vendor(gscr) == 0x11ab &&
+ sata_pmp_gscr_devid(gscr) == 0x4140) {
+ ata_port_printk(ap, KERN_INFO,
+ "disabling NCQ support due to sil24-mv4140 quirk\n");
+ ap->flags &= ~ATA_FLAG_NCQ;
+ }
}
static void sil24_pmp_detach(struct ata_port *ap)
{
sil24_init_port(ap);
sil24_config_pmp(ap, 0);
+
+ ap->flags |= ATA_FLAG_NCQ;
}
static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class,
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index f277cea904ce..db529b849948 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -83,6 +83,7 @@ static struct ata_port_operations uli_ops = {
.inherits = &ata_bmdma_port_ops,
.scr_read = uli_scr_read,
.scr_write = uli_scr_write,
+ .hardreset = ATA_OP_NULL,
};
static const struct ata_port_info uli_port_info = {
diff --git a/drivers/atm/eni.h b/drivers/atm/eni.h
index d04fefb0841f..e4c9525e60b3 100644
--- a/drivers/atm/eni.h
+++ b/drivers/atm/eni.h
@@ -18,7 +18,6 @@
#include "midway.h"
-#define KERNEL_OFFSET 0xC0000000 /* kernel 0x0 is at phys 0xC0000000 */
#define DEV_LABEL "eni"
#define UBR_BUFFER (128*1024) /* UBR buffer size */
diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h
index 183841cc8fdf..8dd4aa76c3bd 100644
--- a/drivers/atm/fore200e.h
+++ b/drivers/atm/fore200e.h
@@ -1,4 +1,3 @@
-/* $Id: fore200e.h,v 1.4 2000/04/14 10:10:34 davem Exp $ */
#ifndef _FORE200E_H
#define _FORE200E_H
diff --git a/drivers/atm/fore200e_mkfirm.c b/drivers/atm/fore200e_mkfirm.c
index 2ebe1a1e6f8b..520e14b488ff 100644
--- a/drivers/atm/fore200e_mkfirm.c
+++ b/drivers/atm/fore200e_mkfirm.c
@@ -1,6 +1,4 @@
/*
- $Id: fore200e_mkfirm.c,v 1.1 2000/02/21 16:04:32 davem Exp $
-
mkfirm.c: generates a C readable file from a binary firmware image
Christophe Lizzi (lizzi@{csti.fr, cnam.fr}), June 1999.
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index ffc4a5a41946..ea495b21f916 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -1542,7 +1542,8 @@ he_start(struct atm_dev *dev)
/* initialize framer */
#ifdef CONFIG_ATM_HE_USE_SUNI
- suni_init(he_dev->atm_dev);
+ if (he_isMM(he_dev))
+ suni_init(he_dev->atm_dev);
if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->start)
he_dev->atm_dev->phy->start(he_dev->atm_dev);
#endif /* CONFIG_ATM_HE_USE_SUNI */
@@ -1554,6 +1555,7 @@ he_start(struct atm_dev *dev)
val = he_phy_get(he_dev->atm_dev, SUNI_TPOP_APM);
val = (val & ~SUNI_TPOP_APM_S) | (SUNI_TPOP_S_SDH << SUNI_TPOP_APM_S_SHIFT);
he_phy_put(he_dev->atm_dev, val, SUNI_TPOP_APM);
+ he_phy_put(he_dev->atm_dev, SUNI_TACP_IUCHP_CLP, SUNI_TACP_IUCHP);
}
/* 5.1.12 enable transmit and receive */
@@ -2844,10 +2846,15 @@ he_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void __user *arg)
if (copy_from_user(&reg, arg,
sizeof(struct he_ioctl_reg)))
return -EFAULT;
-
+
spin_lock_irqsave(&he_dev->global_lock, flags);
switch (reg.type) {
case HE_REGTYPE_PCI:
+ if (reg.addr < 0 || reg.addr >= HE_REGMAP_SIZE) {
+ err = -EINVAL;
+ break;
+ }
+
reg.val = he_readl(he_dev, reg.addr);
break;
case HE_REGTYPE_RCM:
diff --git a/drivers/atm/he.h b/drivers/atm/he.h
index 1dc277547a73..b87d6ccabac1 100644
--- a/drivers/atm/he.h
+++ b/drivers/atm/he.h
@@ -1,5 +1,3 @@
-/* $Id: he.h,v 1.4 2003/05/06 22:48:00 chas Exp $ */
-
/*
he.h
@@ -269,13 +267,7 @@ struct he_dev {
char prod_id[30];
char mac_addr[6];
- int media; /*
- * 0x26 = HE155 MM
- * 0x27 = HE622 MM
- * 0x46 = HE155 SM
- * 0x47 = HE622 SM
- */
-
+ int media;
unsigned int vcibits, vpibits;
unsigned int cells_per_row;
@@ -394,6 +386,7 @@ struct he_vcc
#define HE_DEV(dev) ((struct he_dev *) (dev)->dev_data)
#define he_is622(dev) ((dev)->media & 0x1)
+#define he_isMM(dev) ((dev)->media & 0x20)
#define HE_REGMAP_SIZE 0x100000
@@ -878,8 +871,8 @@ struct he_vcc
#define M_SN 0x3a /* integer */
#define MEDIA 0x3e /* integer */
#define HE155MM 0x26
-#define HE155SM 0x27
-#define HE622MM 0x46
+#define HE622MM 0x27
+#define HE155SM 0x46
#define HE622SM 0x47
#define MAC_ADDR 0x42 /* char[] */
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index 28d77b5195de..3a504e94a4d9 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -1,8 +1,4 @@
/*******************************************************************
- * ident "$Id: idt77252.c,v 1.2 2001/11/11 08:13:54 ecd Exp $"
- *
- * $Author: ecd $
- * $Date: 2001/11/11 08:13:54 $
*
* Copyright (c) 2000 ATecoM GmbH
*
@@ -29,9 +25,6 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*******************************************************************/
-static char const rcsid[] =
-"$Id: idt77252.c,v 1.2 2001/11/11 08:13:54 ecd Exp $";
-
#include <linux/module.h>
#include <linux/pci.h>
diff --git a/drivers/atm/idt77252.h b/drivers/atm/idt77252.h
index 6f2b4a5875fb..e83eaf120da0 100644
--- a/drivers/atm/idt77252.h
+++ b/drivers/atm/idt77252.h
@@ -1,8 +1,4 @@
/*******************************************************************
- * ident "$Id: idt77252.h,v 1.2 2001/11/11 08:13:54 ecd Exp $"
- *
- * $Author: ecd $
- * $Date: 2001/11/11 08:13:54 $
*
* Copyright (c) 2000 ATecoM GmbH
*
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 5c28ca7380ff..139fce6968a6 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -2562,17 +2562,11 @@ static int __devinit ia_start(struct atm_dev *dev)
error = suni_init(dev);
if (error)
goto err_free_rx;
- /*
- * Enable interrupt on loss of signal
- * SUNI_RSOP_CIE - 0x10
- * SUNI_RSOP_CIE_LOSE - 0x04
- */
- ia_phy_put(dev, ia_phy_get(dev, 0x10) | 0x04, 0x10);
-#ifndef MODULE
- error = dev->phy->start(dev);
- if (error)
- goto err_free_rx;
-#endif
+ if (dev->phy->start) {
+ error = dev->phy->start(dev);
+ if (error)
+ goto err_free_rx;
+ }
/* Get iadev->carrier_detect status */
IaFrontEndIntr(iadev);
}
@@ -3198,6 +3192,8 @@ static int __devinit ia_init_one(struct pci_dev *pdev,
IF_INIT(printk("dev_id = 0x%x iadev->LineRate = %d \n", (u32)dev,
iadev->LineRate);)
+ pci_set_drvdata(pdev, dev);
+
ia_dev[iadev_count] = iadev;
_ia_dev[iadev_count] = dev;
iadev_count++;
@@ -3219,8 +3215,6 @@ static int __devinit ia_init_one(struct pci_dev *pdev,
iadev->next_board = ia_boards;
ia_boards = dev;
- pci_set_drvdata(pdev, dev);
-
return 0;
err_out_deregister_dev:
@@ -3238,9 +3232,14 @@ static void __devexit ia_remove_one(struct pci_dev *pdev)
struct atm_dev *dev = pci_get_drvdata(pdev);
IADEV *iadev = INPH_IA_DEV(dev);
- ia_phy_put(dev, ia_phy_get(dev,0x10) & ~(0x4), 0x10);
+ /* Disable phy interrupts */
+ ia_phy_put(dev, ia_phy_get(dev, SUNI_RSOP_CIE) & ~(SUNI_RSOP_CIE_LOSE),
+ SUNI_RSOP_CIE);
udelay(1);
+ if (dev->phy && dev->phy->stop)
+ dev->phy->stop(dev);
+
/* De-register device */
free_irq(iadev->irq, dev);
iadev_count--;
diff --git a/drivers/atm/iphase.h b/drivers/atm/iphase.h
index 133eefcc0475..b2cd20f549cb 100644
--- a/drivers/atm/iphase.h
+++ b/drivers/atm/iphase.h
@@ -1025,7 +1025,8 @@ typedef struct iadev_t {
spinlock_t rx_lock, misc_lock;
struct atm_vcc **rx_open; /* list of all open VCs */
u16 num_rx_desc, rx_buf_sz, rxing;
- u32 rx_pkt_ram, rx_tmp_cnt, rx_tmp_jif;
+ u32 rx_pkt_ram, rx_tmp_cnt;
+ unsigned long rx_tmp_jif;
void __iomem *RX_DESC_BASE_ADDR;
u32 drop_rxpkt, drop_rxcell, rx_cell_cnt, rx_pkt_cnt;
struct atm_dev *next_board; /* other iphase devices */
diff --git a/drivers/atm/nicstarmac.copyright b/drivers/atm/nicstarmac.copyright
index 2e15b39fac4f..180531a83c62 100644
--- a/drivers/atm/nicstarmac.copyright
+++ b/drivers/atm/nicstarmac.copyright
@@ -13,7 +13,7 @@
*
* Modified to work with the IDT7721 nicstar -- AAL5 (tested) only.
*
- * R. D. Rechenmacher <ron@fnal.gov>, Aug. 6, 1997 $Revision: 1.1 $ $Date: 1999/08/20 11:00:11 $
+ * R. D. Rechenmacher <ron@fnal.gov>, Aug. 6, 1997
*
* Linux driver for the IDT77201 NICStAR PCI ATM controller.
* PHY component is expected to be 155 Mbps S/UNI-Lite or IDT 77155;
diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig
index 043353bd0600..14b9d5f4c203 100644
--- a/drivers/auxdisplay/Kconfig
+++ b/drivers/auxdisplay/Kconfig
@@ -64,7 +64,7 @@ config KS0108_DELAY
Amount of time the ks0108 should wait between each control write
to the parallel port.
- If your driver seems to miss random writings, increment this.
+ If your LCD seems to miss random writings, increment this.
If you don't know what I'm talking about, ignore it.
diff --git a/drivers/auxdisplay/cfag12864b.c b/drivers/auxdisplay/cfag12864b.c
index 80bb06105387..683509f013ab 100644
--- a/drivers/auxdisplay/cfag12864b.c
+++ b/drivers/auxdisplay/cfag12864b.c
@@ -5,7 +5,7 @@
* License: GPLv2
* Depends: ks0108
*
- * Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com>
+ * Author: Copyright (C) Miguel Ojeda Sandonis
* Date: 2006-10-31
*
* This program is free software; you can redistribute it and/or modify
@@ -398,5 +398,5 @@ module_init(cfag12864b_init);
module_exit(cfag12864b_exit);
MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Miguel Ojeda Sandonis <maxextreme@gmail.com>");
+MODULE_AUTHOR("Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>");
MODULE_DESCRIPTION("cfag12864b LCD driver");
diff --git a/drivers/auxdisplay/cfag12864bfb.c b/drivers/auxdisplay/cfag12864bfb.c
index 307c190699e0..fe3a865be4e5 100644
--- a/drivers/auxdisplay/cfag12864bfb.c
+++ b/drivers/auxdisplay/cfag12864bfb.c
@@ -5,7 +5,7 @@
* License: GPLv2
* Depends: cfag12864b
*
- * Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com>
+ * Author: Copyright (C) Miguel Ojeda Sandonis
* Date: 2006-10-31
*
* This program is free software; you can redistribute it and/or modify
@@ -186,5 +186,5 @@ module_init(cfag12864bfb_init);
module_exit(cfag12864bfb_exit);
MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Miguel Ojeda Sandonis <maxextreme@gmail.com>");
+MODULE_AUTHOR("Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>");
MODULE_DESCRIPTION("cfag12864b LCD framebuffer driver");
diff --git a/drivers/auxdisplay/ks0108.c b/drivers/auxdisplay/ks0108.c
index e6c3646ef18c..5b93852392b8 100644
--- a/drivers/auxdisplay/ks0108.c
+++ b/drivers/auxdisplay/ks0108.c
@@ -5,7 +5,7 @@
* License: GPLv2
* Depends: parport
*
- * Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com>
+ * Author: Copyright (C) Miguel Ojeda Sandonis
* Date: 2006-10-31
*
* This program is free software; you can redistribute it and/or modify
@@ -173,6 +173,6 @@ module_init(ks0108_init);
module_exit(ks0108_exit);
MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Miguel Ojeda Sandonis <maxextreme@gmail.com>");
+MODULE_AUTHOR("Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>");
MODULE_DESCRIPTION("ks0108 LCD Controller driver");
diff --git a/drivers/base/core.c b/drivers/base/core.c
index be288b5e4180..ee0a51a3a41d 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -760,6 +760,22 @@ static void device_remove_class_symlinks(struct device *dev)
}
/**
+ * dev_set_name - set a device name
+ * @dev: device
+ * @fmt: format string for the device's name
+ */
+int dev_set_name(struct device *dev, const char *fmt, ...)
+{
+ va_list vargs;
+
+ va_start(vargs, fmt);
+ vsnprintf(dev->bus_id, sizeof(dev->bus_id), fmt, vargs);
+ va_end(vargs);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dev_set_name);
+
+/**
* device_add - add device to device hierarchy.
* @dev: device.
*
@@ -1084,11 +1100,13 @@ static void device_create_release(struct device *dev)
}
/**
- * device_create - creates a device and registers it with sysfs
+ * device_create_vargs - creates a device and registers it with sysfs
* @class: pointer to the struct class that this device should be registered to
* @parent: pointer to the parent struct device of this new device, if any
* @devt: the dev_t for the char device to be added
+ * @drvdata: the data to be added to the device for callbacks
* @fmt: string for the device's name
+ * @args: va_list for the device's name
*
* This function can be used by char device classes. A struct device
* will be created in sysfs, registered to the specified class.
@@ -1104,10 +1122,10 @@ static void device_create_release(struct device *dev)
* Note: the struct class passed to this function must have previously
* been created with a call to class_create().
*/
-struct device *device_create(struct class *class, struct device *parent,
- dev_t devt, const char *fmt, ...)
+struct device *device_create_vargs(struct class *class, struct device *parent,
+ dev_t devt, void *drvdata, const char *fmt,
+ va_list args)
{
- va_list args;
struct device *dev = NULL;
int retval = -ENODEV;
@@ -1124,10 +1142,9 @@ struct device *device_create(struct class *class, struct device *parent,
dev->class = class;
dev->parent = parent;
dev->release = device_create_release;
+ dev_set_drvdata(dev, drvdata);
- va_start(args, fmt);
vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);
- va_end(args);
retval = device_register(dev);
if (retval)
goto error;
@@ -1138,6 +1155,78 @@ error:
kfree(dev);
return ERR_PTR(retval);
}
+EXPORT_SYMBOL_GPL(device_create_vargs);
+
+/**
+ * device_create_drvdata - creates a device and registers it with sysfs
+ * @class: pointer to the struct class that this device should be registered to
+ * @parent: pointer to the parent struct device of this new device, if any
+ * @devt: the dev_t for the char device to be added
+ * @drvdata: the data to be added to the device for callbacks
+ * @fmt: string for the device's name
+ *
+ * This function can be used by char device classes. A struct device
+ * will be created in sysfs, registered to the specified class.
+ *
+ * A "dev" file will be created, showing the dev_t for the device, if
+ * the dev_t is not 0,0.
+ * If a pointer to a parent struct device is passed in, the newly created
+ * struct device will be a child of that device in sysfs.
+ * The pointer to the struct device will be returned from the call.
+ * Any further sysfs files that might be required can be created using this
+ * pointer.
+ *
+ * Note: the struct class passed to this function must have previously
+ * been created with a call to class_create().
+ */
+struct device *device_create_drvdata(struct class *class,
+ struct device *parent,
+ dev_t devt,
+ void *drvdata,
+ const char *fmt, ...)
+{
+ va_list vargs;
+ struct device *dev;
+
+ va_start(vargs, fmt);
+ dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
+ va_end(vargs);
+ return dev;
+}
+EXPORT_SYMBOL_GPL(device_create_drvdata);
+
+/**
+ * device_create - creates a device and registers it with sysfs
+ * @class: pointer to the struct class that this device should be registered to
+ * @parent: pointer to the parent struct device of this new device, if any
+ * @devt: the dev_t for the char device to be added
+ * @fmt: string for the device's name
+ *
+ * This function can be used by char device classes. A struct device
+ * will be created in sysfs, registered to the specified class.
+ *
+ * A "dev" file will be created, showing the dev_t for the device, if
+ * the dev_t is not 0,0.
+ * If a pointer to a parent struct device is passed in, the newly created
+ * struct device will be a child of that device in sysfs.
+ * The pointer to the struct device will be returned from the call.
+ * Any further sysfs files that might be required can be created using this
+ * pointer.
+ *
+ * Note: the struct class passed to this function must have previously
+ * been created with a call to class_create().
+ */
+struct device *device_create(struct class *class, struct device *parent,
+ dev_t devt, const char *fmt, ...)
+{
+ va_list vargs;
+ struct device *dev;
+
+ va_start(vargs, fmt);
+ dev = device_create_vargs(class, parent, devt, NULL, fmt, vargs);
+ va_end(vargs);
+ return dev;
+}
EXPORT_SYMBOL_GPL(device_create);
static int __match_devt(struct device *dev, void *data)
@@ -1218,13 +1307,11 @@ int device_rename(struct device *dev, char *new_name)
}
#else
if (dev->class) {
- sysfs_remove_link(&dev->class->subsys.kobj, old_device_name);
error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
dev->bus_id);
- if (error) {
- dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n",
- __func__, error);
- }
+ if (error)
+ goto out;
+ sysfs_remove_link(&dev->class->subsys.kobj, old_device_name);
}
#endif
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 39f3d1b3a213..0f867a083338 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -84,8 +84,8 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
nid, K(i.totalram),
nid, K(i.freeram),
nid, K(i.totalram - i.freeram),
- nid, node_page_state(nid, NR_ACTIVE),
- nid, node_page_state(nid, NR_INACTIVE),
+ nid, K(node_page_state(nid, NR_ACTIVE)),
+ nid, K(node_page_state(nid, NR_INACTIVE)),
#ifdef CONFIG_HIGHMEM
nid, K(i.totalhigh),
nid, K(i.freehigh),
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index a196ef7f147f..24b97b0bef99 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -397,6 +397,7 @@ module_param(max_part, int, 0);
MODULE_PARM_DESC(max_part, "Maximum number of partitions per RAM disk");
MODULE_LICENSE("GPL");
MODULE_ALIAS_BLOCKDEV_MAJOR(RAMDISK_MAJOR);
+MODULE_ALIAS("rd");
#ifndef MODULE
/* Legacy boot options - nonmodular */
@@ -447,6 +448,7 @@ static struct brd_device *brd_alloc(int i)
disk->fops = &brd_fops;
disk->private_data = brd;
disk->queue = brd->brd_queue;
+ disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
sprintf(disk->disk_name, "ram%d", i);
set_capacity(disk, rd_size * 2);
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index e336b05fe4a7..d81632cd7d06 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -53,15 +53,16 @@
#include <linux/scatterlist.h>
#define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "HP CISS Driver (v 3.6.14)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(3,6,14)
+#define DRIVER_NAME "HP CISS Driver (v 3.6.20)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(3, 6, 20)
/* Embedded module documentation macros - see modules.h */
MODULE_AUTHOR("Hewlett-Packard Company");
-MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 3.6.14");
+MODULE_DESCRIPTION("Driver for HP Smart Array Controllers");
MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
- " SA6i P600 P800 P400 P400i E200 E200i E500");
-MODULE_VERSION("3.6.14");
+ " SA6i P600 P800 P400 P400i E200 E200i E500 P700m"
+ " Smart Array G2 Series SAS/SATA Controllers");
+MODULE_VERSION("3.6.20");
MODULE_LICENSE("GPL");
#include "cciss_cmd.h"
@@ -90,6 +91,11 @@ static const struct pci_device_id cciss_pci_device_id[] = {
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3215},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3237},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x323D},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3241},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3243},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3245},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3247},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3249},
{PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
{0,}
@@ -100,30 +106,34 @@ MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
/* board_id = Subsystem Device ID & Vendor ID
* product = Marketing Name for the board
* access = Address of the struct of function pointers
- * nr_cmds = Number of commands supported by controller
*/
static struct board_type products[] = {
- {0x40700E11, "Smart Array 5300", &SA5_access, 512},
- {0x40800E11, "Smart Array 5i", &SA5B_access, 512},
- {0x40820E11, "Smart Array 532", &SA5B_access, 512},
- {0x40830E11, "Smart Array 5312", &SA5B_access, 512},
- {0x409A0E11, "Smart Array 641", &SA5_access, 512},
- {0x409B0E11, "Smart Array 642", &SA5_access, 512},
- {0x409C0E11, "Smart Array 6400", &SA5_access, 512},
- {0x409D0E11, "Smart Array 6400 EM", &SA5_access, 512},
- {0x40910E11, "Smart Array 6i", &SA5_access, 512},
- {0x3225103C, "Smart Array P600", &SA5_access, 512},
- {0x3223103C, "Smart Array P800", &SA5_access, 512},
- {0x3234103C, "Smart Array P400", &SA5_access, 512},
- {0x3235103C, "Smart Array P400i", &SA5_access, 512},
- {0x3211103C, "Smart Array E200i", &SA5_access, 120},
- {0x3212103C, "Smart Array E200", &SA5_access, 120},
- {0x3213103C, "Smart Array E200i", &SA5_access, 120},
- {0x3214103C, "Smart Array E200i", &SA5_access, 120},
- {0x3215103C, "Smart Array E200i", &SA5_access, 120},
- {0x3237103C, "Smart Array E500", &SA5_access, 512},
- {0x323D103C, "Smart Array P700m", &SA5_access, 512},
- {0xFFFF103C, "Unknown Smart Array", &SA5_access, 120},
+ {0x40700E11, "Smart Array 5300", &SA5_access},
+ {0x40800E11, "Smart Array 5i", &SA5B_access},
+ {0x40820E11, "Smart Array 532", &SA5B_access},
+ {0x40830E11, "Smart Array 5312", &SA5B_access},
+ {0x409A0E11, "Smart Array 641", &SA5_access},
+ {0x409B0E11, "Smart Array 642", &SA5_access},
+ {0x409C0E11, "Smart Array 6400", &SA5_access},
+ {0x409D0E11, "Smart Array 6400 EM", &SA5_access},
+ {0x40910E11, "Smart Array 6i", &SA5_access},
+ {0x3225103C, "Smart Array P600", &SA5_access},
+ {0x3223103C, "Smart Array P800", &SA5_access},
+ {0x3234103C, "Smart Array P400", &SA5_access},
+ {0x3235103C, "Smart Array P400i", &SA5_access},
+ {0x3211103C, "Smart Array E200i", &SA5_access},
+ {0x3212103C, "Smart Array E200", &SA5_access},
+ {0x3213103C, "Smart Array E200i", &SA5_access},
+ {0x3214103C, "Smart Array E200i", &SA5_access},
+ {0x3215103C, "Smart Array E200i", &SA5_access},
+ {0x3237103C, "Smart Array E500", &SA5_access},
+ {0x323D103C, "Smart Array P700m", &SA5_access},
+ {0x3241103C, "Smart Array P212", &SA5_access},
+ {0x3243103C, "Smart Array P410", &SA5_access},
+ {0x3245103C, "Smart Array P410i", &SA5_access},
+ {0x3247103C, "Smart Array P411", &SA5_access},
+ {0x3249103C, "Smart Array P812", &SA5_access},
+ {0xFFFF103C, "Unknown Smart Array", &SA5_access},
};
/* How long to wait (in milliseconds) for board to go into simple mode */
@@ -3075,11 +3085,20 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
print_cfg_table(c->cfgtable);
#endif /* CCISS_DEBUG */
+ /* Some controllers support Zero Memory Raid (ZMR).
+ * When configured in ZMR mode the number of supported
+ * commands drops to 64. So instead of just setting an
+ * arbitrary value we make the driver a little smarter.
+ * We read the config table to tell us how many commands
+ * are supported on the controller then subtract 4 to
+ * leave a little room for ioctl calls.
+ */
+ c->max_commands = readl(&(c->cfgtable->CmdsOutMax));
for (i = 0; i < ARRAY_SIZE(products); i++) {
if (board_id == products[i].board_id) {
c->product_name = products[i].product_name;
c->access = *(products[i].access);
- c->nr_cmds = products[i].nr_cmds;
+ c->nr_cmds = c->max_commands - 4;
break;
}
}
@@ -3099,7 +3118,7 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
if (subsystem_vendor_id == PCI_VENDOR_ID_HP) {
c->product_name = products[i-1].product_name;
c->access = *(products[i-1].access);
- c->nr_cmds = products[i-1].nr_cmds;
+ c->nr_cmds = c->max_commands - 4;
printk(KERN_WARNING "cciss: This is an unknown "
"Smart Array controller.\n"
"cciss: Please update to the latest driver "
@@ -3535,6 +3554,10 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
for (j = 0; j <= hba[i]->highest_lun; j++)
add_disk(hba[i]->gendisk[j]);
+ /* we must register the controller even if no disks exist */
+ if (hba[i]->highest_lun == -1)
+ add_disk(hba[i]->gendisk[0]);
+
return 1;
clean4:
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
index ebfe038d859e..f1c8feb5510b 100644
--- a/drivers/block/viodasd.c
+++ b/drivers/block/viodasd.c
@@ -3,7 +3,7 @@
* Authors: Dave Boutcher <boutcher@us.ibm.com>
* Ryan Arnold <ryanarn@us.ibm.com>
* Colin Devilbiss <devilbis@us.ibm.com>
- * Stephen Rothwell <sfr@au1.ibm.com>
+ * Stephen Rothwell
*
* (C) Copyright 2000-2004 IBM Corporation
*
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 84e064ffee52..dd7ea203f940 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -260,6 +260,10 @@ static int virtblk_probe(struct virtio_device *vdev)
if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
+ /* If disk is read-only in the host, the guest should obey */
+ if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
+ set_disk_ro(vblk->disk, 1);
+
/* Host must always specify the capacity. */
vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
&cap, sizeof(cap));
@@ -311,6 +315,7 @@ static void virtblk_remove(struct virtio_device *vdev)
/* Stop all the virtqueues. */
vdev->config->reset(vdev);
+ del_gendisk(vblk->disk);
blk_cleanup_queue(vblk->disk->queue);
put_disk(vblk->disk);
mempool_destroy(vblk->pool);
@@ -325,7 +330,7 @@ static struct virtio_device_id id_table[] = {
static unsigned int features[] = {
VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
- VIRTIO_BLK_F_GEOMETRY,
+ VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO,
};
static struct virtio_driver virtio_blk = {
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index 5245a4a0ba74..9d0dfe6e0d63 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -6,7 +6,7 @@
* Authors: Dave Boutcher <boutcher@us.ibm.com>
* Ryan Arnold <ryanarn@us.ibm.com>
* Colin Devilbiss <devilbis@us.ibm.com>
- * Stephen Rothwell <sfr@au1.ibm.com>
+ * Stephen Rothwell
*
* (C) Copyright 2000-2004 IBM Corporation
*
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 595a925c62a9..2d854bb9373e 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -118,8 +118,8 @@ config COMPUTONE
order to become a dial-in server. If you have a card like that, say
Y here and read <file:Documentation/computone.txt>.
- To compile this driver as modules, choose M here: the
- modules will be called ip2 and ip2main.
+ To compile this driver as module, choose M here: the
+ module will be called ip2.
config ROCKETPORT
tristate "Comtrol RocketPort support"
@@ -749,7 +749,7 @@ config NVRAM
if RTC_LIB=n
config RTC
- tristate "Enhanced Real Time Clock Support"
+ tristate "Enhanced Real Time Clock Support (legacy PC RTC driver)"
depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV \
&& !ARM && !SUPERH && !S390 && !AVR32
---help---
@@ -1036,9 +1036,9 @@ config HPET
non-periodic and/or periodic.
config HPET_RTC_IRQ
- bool "HPET Control RTC IRQ" if !HPET_EMULATE_RTC
- default n
- depends on HPET
+ bool
+ default HPET_EMULATE_RTC
+ depends on RTC && HPET
help
If you say Y here, you will disable RTC_IRQ in drivers/char/rtc.c. It
is assumed the platform called hpet_alloc with the RTC IRQ values for
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 99e6a406efb4..81e14bea54bd 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -99,8 +99,8 @@ struct agp_bridge_driver {
const void *aperture_sizes;
int num_aperture_sizes;
enum aper_size_type size_type;
- int cant_use_aperture;
- int needs_scratch_page;
+ bool cant_use_aperture;
+ bool needs_scratch_page;
const struct gatt_mask *masks;
int (*fetch_size)(void);
int (*configure)(void);
@@ -278,7 +278,7 @@ void agp_generic_destroy_page(void *addr, int flags);
void agp_free_key(int key);
int agp_num_entries(void);
u32 agp_collect_device_status(struct agp_bridge_data *bridge, u32 mode, u32 command);
-void agp_device_command(u32 command, int agp_v3);
+void agp_device_command(u32 command, bool agp_v3);
int agp_3_5_enable(struct agp_bridge_data *bridge);
void global_cache_flush(void);
void get_agp_version(struct agp_bridge_data *bridge);
diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c
index e77c17838c8a..5da89f6c6c25 100644
--- a/drivers/char/agp/alpha-agp.c
+++ b/drivers/char/agp/alpha-agp.c
@@ -80,7 +80,7 @@ static void alpha_core_agp_enable(struct agp_bridge_data *bridge, u32 mode)
agp->mode.bits.enable = 1;
agp->ops->configure(agp);
- agp_device_command(agp->mode.lw, 0);
+ agp_device_command(agp->mode.lw, false);
}
static int alpha_core_agp_insert_memory(struct agp_memory *mem, off_t pg_start,
@@ -126,7 +126,7 @@ struct agp_bridge_driver alpha_core_agp_driver = {
.aperture_sizes = alpha_core_agp_sizes,
.num_aperture_sizes = 1,
.size_type = FIXED_APER_SIZE,
- .cant_use_aperture = 1,
+ .cant_use_aperture = true,
.masks = NULL,
.fetch_size = alpha_core_agp_fetch_size,
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index 96bdb9296b07..39a0718bc616 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -314,9 +314,9 @@ static int amd_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
j++;
}
- if (mem->is_flushed == FALSE) {
+ if (!mem->is_flushed) {
global_cache_flush();
- mem->is_flushed = TRUE;
+ mem->is_flushed = true;
}
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index d8200ac8f8cb..13665db363d6 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -90,9 +90,9 @@ static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
j++;
}
- if (mem->is_flushed == FALSE) {
+ if (!mem->is_flushed) {
global_cache_flush();
- mem->is_flushed = TRUE;
+ mem->is_flushed = true;
}
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
index 55c97f623242..3a4566c0d84f 100644
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -287,10 +287,10 @@ static int ati_insert_memory(struct agp_memory * mem,
j++;
}
- if (mem->is_flushed == FALSE) {
+ if (!mem->is_flushed) {
/*CACHE_FLUSH(); */
global_cache_flush();
- mem->is_flushed = TRUE;
+ mem->is_flushed = true;
}
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
@@ -458,6 +458,10 @@ static struct agp_device_ids ati_agp_device_ids[] __devinitdata =
.chipset_name = "IGP9100/M",
},
{
+ .device_id = PCI_DEVICE_ID_ATI_RS350_133,
+ .chipset_name = "IGP9000/M",
+ },
+ {
.device_id = PCI_DEVICE_ID_ATI_RS350_200,
.chipset_name = "IGP9100/M",
},
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index b1bdd015165c..1ec87104e68c 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -188,10 +188,10 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
err_out:
if (bridge->driver->needs_scratch_page) {
- bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
- AGP_PAGE_DESTROY_UNMAP);
- bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
- AGP_PAGE_DESTROY_FREE);
+ void *va = gart_to_virt(bridge->scratch_page_real);
+
+ bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
+ bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
}
if (got_gatt)
bridge->driver->free_gatt_table(bridge);
@@ -215,10 +215,10 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge)
if (bridge->driver->agp_destroy_page &&
bridge->driver->needs_scratch_page) {
- bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
- AGP_PAGE_DESTROY_UNMAP);
- bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
- AGP_PAGE_DESTROY_FREE);
+ void *va = gart_to_virt(bridge->scratch_page_real);
+
+ bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
+ bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
}
}
diff --git a/drivers/char/agp/compat_ioctl.c b/drivers/char/agp/compat_ioctl.c
index 39275794fe63..58c57cb2518c 100644
--- a/drivers/char/agp/compat_ioctl.c
+++ b/drivers/char/agp/compat_ioctl.c
@@ -214,7 +214,7 @@ long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ret_val = -EINVAL;
goto ioctl_out;
}
- if ((agp_fe.backend_acquired != TRUE) &&
+ if ((agp_fe.backend_acquired != true) &&
(cmd != AGPIOC_ACQUIRE32)) {
ret_val = -EBUSY;
goto ioctl_out;
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c
index cac0009cebc1..8ca6f262ef85 100644
--- a/drivers/char/agp/efficeon-agp.c
+++ b/drivers/char/agp/efficeon-agp.c
@@ -249,9 +249,9 @@ static int efficeon_insert_memory(struct agp_memory * mem, off_t pg_start, int t
if (type != 0 || mem->type != 0)
return -EINVAL;
- if (mem->is_flushed == FALSE) {
+ if (!mem->is_flushed) {
global_cache_flush();
- mem->is_flushed = TRUE;
+ mem->is_flushed = true;
}
last_page = NULL;
@@ -329,7 +329,7 @@ static const struct agp_bridge_driver efficeon_driver = {
.free_gatt_table = efficeon_free_gatt_table,
.insert_memory = efficeon_insert_memory,
.remove_memory = efficeon_remove_memory,
- .cant_use_aperture = 0, // 1 might be faster?
+ .cant_use_aperture = false, // true might be faster?
// Generic
.alloc_by_type = agp_generic_alloc_by_type,
diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c
index 963eff28fa00..a96f3197e60f 100644
--- a/drivers/char/agp/frontend.c
+++ b/drivers/char/agp/frontend.c
@@ -396,7 +396,7 @@ static int agp_remove_controller(struct agp_controller *controller)
if (agp_fe.current_controller == controller) {
agp_fe.current_controller = NULL;
- agp_fe.backend_acquired = FALSE;
+ agp_fe.backend_acquired = false;
agp_backend_release(agp_bridge);
}
kfree(controller);
@@ -444,7 +444,7 @@ static void agp_controller_release_current(struct agp_controller *controller,
}
agp_fe.current_controller = NULL;
- agp_fe.used_by_controller = FALSE;
+ agp_fe.used_by_controller = false;
agp_backend_release(agp_bridge);
}
@@ -574,7 +574,7 @@ static int agp_mmap(struct file *file, struct vm_area_struct *vma)
mutex_lock(&(agp_fe.agp_mutex));
- if (agp_fe.backend_acquired != TRUE)
+ if (agp_fe.backend_acquired != true)
goto out_eperm;
if (!(test_bit(AGP_FF_IS_VALID, &priv->access_flags)))
@@ -772,7 +772,7 @@ int agpioc_acquire_wrap(struct agp_file_private *priv)
atomic_inc(&agp_bridge->agp_in_use);
- agp_fe.backend_acquired = TRUE;
+ agp_fe.backend_acquired = true;
controller = agp_find_controller_by_pid(priv->my_pid);
@@ -782,7 +782,7 @@ int agpioc_acquire_wrap(struct agp_file_private *priv)
controller = agp_create_controller(priv->my_pid);
if (controller == NULL) {
- agp_fe.backend_acquired = FALSE;
+ agp_fe.backend_acquired = false;
agp_backend_release(agp_bridge);
return -ENOMEM;
}
@@ -985,7 +985,7 @@ static long agp_ioctl(struct file *file,
ret_val = -EINVAL;
goto ioctl_out;
}
- if ((agp_fe.backend_acquired != TRUE) &&
+ if ((agp_fe.backend_acquired != true) &&
(cmd != AGPIOC_ACQUIRE)) {
ret_val = -EBUSY;
goto ioctl_out;
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 7fc0c99a3a58..564daaa6c7d0 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -96,13 +96,13 @@ EXPORT_SYMBOL(agp_flush_chipset);
void agp_alloc_page_array(size_t size, struct agp_memory *mem)
{
mem->memory = NULL;
- mem->vmalloc_flag = 0;
+ mem->vmalloc_flag = false;
if (size <= 2*PAGE_SIZE)
mem->memory = kmalloc(size, GFP_KERNEL | __GFP_NORETRY);
if (mem->memory == NULL) {
mem->memory = vmalloc(size);
- mem->vmalloc_flag = 1;
+ mem->vmalloc_flag = true;
}
}
EXPORT_SYMBOL(agp_alloc_page_array);
@@ -188,7 +188,7 @@ void agp_free_memory(struct agp_memory *curr)
if (curr == NULL)
return;
- if (curr->is_bound == TRUE)
+ if (curr->is_bound)
agp_unbind_memory(curr);
if (curr->type >= AGP_USER_TYPES) {
@@ -202,10 +202,13 @@ void agp_free_memory(struct agp_memory *curr)
}
if (curr->page_count != 0) {
for (i = 0; i < curr->page_count; i++) {
- curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_UNMAP);
+ curr->memory[i] = (unsigned long)gart_to_virt(curr->memory[i]);
+ curr->bridge->driver->agp_destroy_page((void *)curr->memory[i],
+ AGP_PAGE_DESTROY_UNMAP);
}
for (i = 0; i < curr->page_count; i++) {
- curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_FREE);
+ curr->bridge->driver->agp_destroy_page((void *)curr->memory[i],
+ AGP_PAGE_DESTROY_FREE);
}
}
agp_free_key(curr->key);
@@ -411,20 +414,20 @@ int agp_bind_memory(struct agp_memory *curr, off_t pg_start)
if (curr == NULL)
return -EINVAL;
- if (curr->is_bound == TRUE) {
+ if (curr->is_bound) {
printk(KERN_INFO PFX "memory %p is already bound!\n", curr);
return -EINVAL;
}
- if (curr->is_flushed == FALSE) {
+ if (!curr->is_flushed) {
curr->bridge->driver->cache_flush();
- curr->is_flushed = TRUE;
+ curr->is_flushed = true;
}
ret_val = curr->bridge->driver->insert_memory(curr, pg_start, curr->type);
if (ret_val != 0)
return ret_val;
- curr->is_bound = TRUE;
+ curr->is_bound = true;
curr->pg_start = pg_start;
return 0;
}
@@ -446,7 +449,7 @@ int agp_unbind_memory(struct agp_memory *curr)
if (curr == NULL)
return -EINVAL;
- if (curr->is_bound != TRUE) {
+ if (!curr->is_bound) {
printk(KERN_INFO PFX "memory %p was not bound!\n", curr);
return -EINVAL;
}
@@ -456,7 +459,7 @@ int agp_unbind_memory(struct agp_memory *curr)
if (ret_val != 0)
return ret_val;
- curr->is_bound = FALSE;
+ curr->is_bound = false;
curr->pg_start = 0;
return 0;
}
@@ -754,7 +757,7 @@ u32 agp_collect_device_status(struct agp_bridge_data *bridge, u32 requested_mode
EXPORT_SYMBOL(agp_collect_device_status);
-void agp_device_command(u32 bridge_agpstat, int agp_v3)
+void agp_device_command(u32 bridge_agpstat, bool agp_v3)
{
struct pci_dev *device = NULL;
int mode;
@@ -818,7 +821,7 @@ void agp_generic_enable(struct agp_bridge_data *bridge, u32 requested_mode)
/* If we have 3.5, we can do the isoch stuff. */
if (bridge->minor_version >= 5)
agp_3_5_enable(bridge);
- agp_device_command(bridge_agpstat, TRUE);
+ agp_device_command(bridge_agpstat, true);
return;
} else {
/* Disable calibration cycle in RX91<1> when not in AGP3.0 mode of operation.*/
@@ -835,7 +838,7 @@ void agp_generic_enable(struct agp_bridge_data *bridge, u32 requested_mode)
}
/* AGP v<3 */
- agp_device_command(bridge_agpstat, FALSE);
+ agp_device_command(bridge_agpstat, false);
}
EXPORT_SYMBOL(agp_generic_enable);
@@ -1083,9 +1086,9 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
j++;
}
- if (mem->is_flushed == FALSE) {
+ if (!mem->is_flushed) {
bridge->driver->cache_flush();
- mem->is_flushed = TRUE;
+ mem->is_flushed = true;
}
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
index cbb0444467ba..80d7317f85c9 100644
--- a/drivers/char/agp/hp-agp.c
+++ b/drivers/char/agp/hp-agp.c
@@ -353,9 +353,9 @@ hp_zx1_insert_memory (struct agp_memory *mem, off_t pg_start, int type)
j++;
}
- if (mem->is_flushed == FALSE) {
+ if (!mem->is_flushed) {
global_cache_flush();
- mem->is_flushed = TRUE;
+ mem->is_flushed = true;
}
for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
@@ -437,7 +437,7 @@ const struct agp_bridge_driver hp_zx1_driver = {
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
- .cant_use_aperture = 1,
+ .cant_use_aperture = true,
};
static int __init
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index 76f581c85a7d..e587eebebc67 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -580,7 +580,7 @@ const struct agp_bridge_driver intel_i460_driver = {
.alloc_by_type = agp_generic_alloc_by_type,
.free_by_type = agp_generic_free_by_type,
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
- .cant_use_aperture = 1,
+ .cant_use_aperture = true,
};
static int __devinit agp_intel_i460_probe(struct pci_dev *pdev,
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index eeea50a1d22a..df702642ab8f 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -34,6 +34,12 @@
#define PCI_DEVICE_ID_INTEL_Q33_IG 0x29D2
#define PCI_DEVICE_ID_INTEL_IGD_HB 0x2A40
#define PCI_DEVICE_ID_INTEL_IGD_IG 0x2A42
+#define PCI_DEVICE_ID_INTEL_IGD_E_HB 0x2E00
+#define PCI_DEVICE_ID_INTEL_IGD_E_IG 0x2E02
+#define PCI_DEVICE_ID_INTEL_Q45_HB 0x2E10
+#define PCI_DEVICE_ID_INTEL_Q45_IG 0x2E12
+#define PCI_DEVICE_ID_INTEL_G45_HB 0x2E20
+#define PCI_DEVICE_ID_INTEL_G45_IG 0x2E22
/* cover 915 and 945 variants */
#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
@@ -55,6 +61,10 @@
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q33_HB)
+#define IS_G4X (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGD_E_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G45_HB)
+
extern int agp_memory_reserved;
@@ -80,8 +90,13 @@ extern int agp_memory_reserved;
#define I915_PTEADDR 0x1C
#define I915_GMCH_GMS_STOLEN_48M (0x6 << 4)
#define I915_GMCH_GMS_STOLEN_64M (0x7 << 4)
-#define G33_GMCH_GMS_STOLEN_128M (0x8 << 4)
-#define G33_GMCH_GMS_STOLEN_256M (0x9 << 4)
+#define G33_GMCH_GMS_STOLEN_128M (0x8 << 4)
+#define G33_GMCH_GMS_STOLEN_256M (0x9 << 4)
+#define INTEL_GMCH_GMS_STOLEN_96M (0xa << 4)
+#define INTEL_GMCH_GMS_STOLEN_160M (0xb << 4)
+#define INTEL_GMCH_GMS_STOLEN_224M (0xc << 4)
+#define INTEL_GMCH_GMS_STOLEN_352M (0xd << 4)
+
#define I915_IFPADDR 0x60
/* Intel 965G registers */
@@ -325,7 +340,7 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
out:
ret = 0;
out_err:
- mem->is_flushed = 1;
+ mem->is_flushed = true;
return ret;
}
@@ -418,9 +433,11 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
if (curr->page_count == 4)
i8xx_destroy_pages(gart_to_virt(curr->memory[0]));
else {
- agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]),
+ void *va = gart_to_virt(curr->memory[0]);
+
+ agp_bridge->driver->agp_destroy_page(va,
AGP_PAGE_DESTROY_UNMAP);
- agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]),
+ agp_bridge->driver->agp_destroy_page(va,
AGP_PAGE_DESTROY_FREE);
}
agp_free_page_array(curr);
@@ -504,6 +521,10 @@ static void intel_i830_init_gtt_entries(void)
size = 512;
}
size += 4;
+ } else if (IS_G4X) {
+ /* On 4 series hardware, GTT stolen is separate from graphics
+ * stolen, ignore it in stolen gtt entries counting */
+ size = 0;
} else {
/* On previous hardware, the GTT size was just what was
* required to map the aperture.
@@ -552,30 +573,54 @@ static void intel_i830_init_gtt_entries(void)
break;
case I915_GMCH_GMS_STOLEN_48M:
/* Check it's really I915G */
- if (IS_I915 || IS_I965 || IS_G33)
+ if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
gtt_entries = MB(48) - KB(size);
else
gtt_entries = 0;
break;
case I915_GMCH_GMS_STOLEN_64M:
/* Check it's really I915G */
- if (IS_I915 || IS_I965 || IS_G33)
+ if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
gtt_entries = MB(64) - KB(size);
else
gtt_entries = 0;
break;
case G33_GMCH_GMS_STOLEN_128M:
- if (IS_G33)
+ if (IS_G33 || IS_I965 || IS_G4X)
gtt_entries = MB(128) - KB(size);
else
gtt_entries = 0;
break;
case G33_GMCH_GMS_STOLEN_256M:
- if (IS_G33)
+ if (IS_G33 || IS_I965 || IS_G4X)
gtt_entries = MB(256) - KB(size);
else
gtt_entries = 0;
break;
+ case INTEL_GMCH_GMS_STOLEN_96M:
+ if (IS_I965 || IS_G4X)
+ gtt_entries = MB(96) - KB(size);
+ else
+ gtt_entries = 0;
+ break;
+ case INTEL_GMCH_GMS_STOLEN_160M:
+ if (IS_I965 || IS_G4X)
+ gtt_entries = MB(160) - KB(size);
+ else
+ gtt_entries = 0;
+ break;
+ case INTEL_GMCH_GMS_STOLEN_224M:
+ if (IS_I965 || IS_G4X)
+ gtt_entries = MB(224) - KB(size);
+ else
+ gtt_entries = 0;
+ break;
+ case INTEL_GMCH_GMS_STOLEN_352M:
+ if (IS_I965 || IS_G4X)
+ gtt_entries = MB(352) - KB(size);
+ else
+ gtt_entries = 0;
+ break;
default:
gtt_entries = 0;
break;
@@ -793,7 +838,7 @@ static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start,
out:
ret = 0;
out_err:
- mem->is_flushed = 1;
+ mem->is_flushed = true;
return ret;
}
@@ -903,7 +948,7 @@ static void intel_i9xx_setup_flush(void)
intel_private.ifp_resource.flags = IORESOURCE_MEM;
/* Setup chipset flush for 915 */
- if (IS_I965 || IS_G33) {
+ if (IS_I965 || IS_G33 || IS_G4X) {
intel_i965_g33_setup_chipset_flush();
} else {
intel_i915_setup_chipset_flush();
@@ -1020,7 +1065,7 @@ static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
out:
ret = 0;
out_err:
- mem->is_flushed = 1;
+ mem->is_flushed = true;
return ret;
}
@@ -1134,53 +1179,64 @@ static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
return addr | bridge->driver->masks[type].mask;
}
+static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
+{
+ switch (agp_bridge->dev->device) {
+ case PCI_DEVICE_ID_INTEL_IGD_HB:
+ case PCI_DEVICE_ID_INTEL_IGD_E_HB:
+ case PCI_DEVICE_ID_INTEL_Q45_HB:
+ case PCI_DEVICE_ID_INTEL_G45_HB:
+ *gtt_offset = *gtt_size = MB(2);
+ break;
+ default:
+ *gtt_offset = *gtt_size = KB(512);
+ }
+}
+
/* The intel i965 automatically initializes the agp aperture during POST.
* Use the memory already set aside for in the GTT.
*/
static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
{
- int page_order;
- struct aper_size_info_fixed *size;
- int num_entries;
- u32 temp;
- int gtt_offset, gtt_size;
+ int page_order;
+ struct aper_size_info_fixed *size;
+ int num_entries;
+ u32 temp;
+ int gtt_offset, gtt_size;
- size = agp_bridge->current_size;
- page_order = size->page_order;
- num_entries = size->num_entries;
- agp_bridge->gatt_table_real = NULL;
+ size = agp_bridge->current_size;
+ page_order = size->page_order;
+ num_entries = size->num_entries;
+ agp_bridge->gatt_table_real = NULL;
- pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
+ pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
- temp &= 0xfff00000;
+ temp &= 0xfff00000;
- if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGD_HB)
- gtt_offset = gtt_size = MB(2);
- else
- gtt_offset = gtt_size = KB(512);
+ intel_i965_get_gtt_range(&gtt_offset, &gtt_size);
- intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size);
+ intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size);
- if (!intel_private.gtt)
- return -ENOMEM;
+ if (!intel_private.gtt)
+ return -ENOMEM;
- intel_private.registers = ioremap(temp, 128 * 4096);
- if (!intel_private.registers) {
+ intel_private.registers = ioremap(temp, 128 * 4096);
+ if (!intel_private.registers) {
iounmap(intel_private.gtt);
return -ENOMEM;
}
- temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
- global_cache_flush(); /* FIXME: ? */
+ temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
+ global_cache_flush(); /* FIXME: ? */
- /* we have to call this as early as possible after the MMIO base address is known */
- intel_i830_init_gtt_entries();
+ /* we have to call this as early as possible after the MMIO base address is known */
+ intel_i830_init_gtt_entries();
- agp_bridge->gatt_table = NULL;
+ agp_bridge->gatt_table = NULL;
- agp_bridge->gatt_bus_addr = temp;
+ agp_bridge->gatt_bus_addr = temp;
- return 0;
+ return 0;
}
@@ -1656,7 +1712,7 @@ static const struct agp_bridge_driver intel_810_driver = {
.aperture_sizes = intel_i810_sizes,
.size_type = FIXED_APER_SIZE,
.num_aperture_sizes = 2,
- .needs_scratch_page = TRUE,
+ .needs_scratch_page = true,
.configure = intel_i810_configure,
.fetch_size = intel_i810_fetch_size,
.cleanup = intel_i810_cleanup,
@@ -1697,7 +1753,7 @@ static const struct agp_bridge_driver intel_815_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
- .agp_type_to_mask_type = agp_generic_type_to_mask_type,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
static const struct agp_bridge_driver intel_830_driver = {
@@ -1705,7 +1761,7 @@ static const struct agp_bridge_driver intel_830_driver = {
.aperture_sizes = intel_i830_sizes,
.size_type = FIXED_APER_SIZE,
.num_aperture_sizes = 4,
- .needs_scratch_page = TRUE,
+ .needs_scratch_page = true,
.configure = intel_i830_configure,
.fetch_size = intel_i830_fetch_size,
.cleanup = intel_i830_cleanup,
@@ -1876,7 +1932,7 @@ static const struct agp_bridge_driver intel_915_driver = {
.aperture_sizes = intel_i830_sizes,
.size_type = FIXED_APER_SIZE,
.num_aperture_sizes = 4,
- .needs_scratch_page = TRUE,
+ .needs_scratch_page = true,
.configure = intel_i915_configure,
.fetch_size = intel_i9xx_fetch_size,
.cleanup = intel_i915_cleanup,
@@ -1898,28 +1954,28 @@ static const struct agp_bridge_driver intel_915_driver = {
};
static const struct agp_bridge_driver intel_i965_driver = {
- .owner = THIS_MODULE,
- .aperture_sizes = intel_i830_sizes,
- .size_type = FIXED_APER_SIZE,
- .num_aperture_sizes = 4,
- .needs_scratch_page = TRUE,
- .configure = intel_i915_configure,
- .fetch_size = intel_i9xx_fetch_size,
- .cleanup = intel_i915_cleanup,
- .tlb_flush = intel_i810_tlbflush,
- .mask_memory = intel_i965_mask_memory,
- .masks = intel_i810_masks,
- .agp_enable = intel_i810_agp_enable,
- .cache_flush = global_cache_flush,
- .create_gatt_table = intel_i965_create_gatt_table,
- .free_gatt_table = intel_i830_free_gatt_table,
- .insert_memory = intel_i915_insert_entries,
- .remove_memory = intel_i915_remove_entries,
- .alloc_by_type = intel_i830_alloc_by_type,
- .free_by_type = intel_i810_free_by_type,
- .agp_alloc_page = agp_generic_alloc_page,
- .agp_destroy_page = agp_generic_destroy_page,
- .agp_type_to_mask_type = intel_i830_type_to_mask_type,
+ .owner = THIS_MODULE,
+ .aperture_sizes = intel_i830_sizes,
+ .size_type = FIXED_APER_SIZE,
+ .num_aperture_sizes = 4,
+ .needs_scratch_page = true,
+ .configure = intel_i915_configure,
+ .fetch_size = intel_i9xx_fetch_size,
+ .cleanup = intel_i915_cleanup,
+ .tlb_flush = intel_i810_tlbflush,
+ .mask_memory = intel_i965_mask_memory,
+ .masks = intel_i810_masks,
+ .agp_enable = intel_i810_agp_enable,
+ .cache_flush = global_cache_flush,
+ .create_gatt_table = intel_i965_create_gatt_table,
+ .free_gatt_table = intel_i830_free_gatt_table,
+ .insert_memory = intel_i915_insert_entries,
+ .remove_memory = intel_i915_remove_entries,
+ .alloc_by_type = intel_i830_alloc_by_type,
+ .free_by_type = intel_i810_free_by_type,
+ .agp_alloc_page = agp_generic_alloc_page,
+ .agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = intel_i830_type_to_mask_type,
.chipset_flush = intel_i915_chipset_flush,
};
@@ -1948,28 +2004,28 @@ static const struct agp_bridge_driver intel_7505_driver = {
};
static const struct agp_bridge_driver intel_g33_driver = {
- .owner = THIS_MODULE,
- .aperture_sizes = intel_i830_sizes,
- .size_type = FIXED_APER_SIZE,
- .num_aperture_sizes = 4,
- .needs_scratch_page = TRUE,
- .configure = intel_i915_configure,
- .fetch_size = intel_i9xx_fetch_size,
- .cleanup = intel_i915_cleanup,
- .tlb_flush = intel_i810_tlbflush,
- .mask_memory = intel_i965_mask_memory,
- .masks = intel_i810_masks,
- .agp_enable = intel_i810_agp_enable,
- .cache_flush = global_cache_flush,
- .create_gatt_table = intel_i915_create_gatt_table,
- .free_gatt_table = intel_i830_free_gatt_table,
- .insert_memory = intel_i915_insert_entries,
- .remove_memory = intel_i915_remove_entries,
- .alloc_by_type = intel_i830_alloc_by_type,
- .free_by_type = intel_i810_free_by_type,
- .agp_alloc_page = agp_generic_alloc_page,
- .agp_destroy_page = agp_generic_destroy_page,
- .agp_type_to_mask_type = intel_i830_type_to_mask_type,
+ .owner = THIS_MODULE,
+ .aperture_sizes = intel_i830_sizes,
+ .size_type = FIXED_APER_SIZE,
+ .num_aperture_sizes = 4,
+ .needs_scratch_page = true,
+ .configure = intel_i915_configure,
+ .fetch_size = intel_i9xx_fetch_size,
+ .cleanup = intel_i915_cleanup,
+ .tlb_flush = intel_i810_tlbflush,
+ .mask_memory = intel_i965_mask_memory,
+ .masks = intel_i810_masks,
+ .agp_enable = intel_i810_agp_enable,
+ .cache_flush = global_cache_flush,
+ .create_gatt_table = intel_i915_create_gatt_table,
+ .free_gatt_table = intel_i830_free_gatt_table,
+ .insert_memory = intel_i915_insert_entries,
+ .remove_memory = intel_i915_remove_entries,
+ .alloc_by_type = intel_i830_alloc_by_type,
+ .free_by_type = intel_i810_free_by_type,
+ .agp_alloc_page = agp_generic_alloc_page,
+ .agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = intel_i830_type_to_mask_type,
.chipset_flush = intel_i915_chipset_flush,
};
@@ -2063,6 +2119,12 @@ static const struct intel_driver_description {
NULL, &intel_g33_driver },
{ PCI_DEVICE_ID_INTEL_IGD_HB, PCI_DEVICE_ID_INTEL_IGD_IG, 0,
"Intel Integrated Graphics Device", NULL, &intel_i965_driver },
+ { PCI_DEVICE_ID_INTEL_IGD_E_HB, PCI_DEVICE_ID_INTEL_IGD_E_IG, 0,
+ "Intel Integrated Graphics Device", NULL, &intel_i965_driver },
+ { PCI_DEVICE_ID_INTEL_Q45_HB, PCI_DEVICE_ID_INTEL_Q45_IG, 0,
+ "Q45/Q43", NULL, &intel_i965_driver },
+ { PCI_DEVICE_ID_INTEL_G45_HB, PCI_DEVICE_ID_INTEL_G45_IG, 0,
+ "G45/G43", NULL, &intel_i965_driver },
{ 0, 0, 0, NULL, NULL, NULL }
};
@@ -2254,6 +2316,9 @@ static struct pci_device_id agp_intel_pci_table[] = {
ID(PCI_DEVICE_ID_INTEL_Q35_HB),
ID(PCI_DEVICE_ID_INTEL_Q33_HB),
ID(PCI_DEVICE_ID_INTEL_IGD_HB),
+ ID(PCI_DEVICE_ID_INTEL_IGD_E_HB),
+ ID(PCI_DEVICE_ID_INTEL_Q45_HB),
+ ID(PCI_DEVICE_ID_INTEL_G45_HB),
{ }
};
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index 225ed2a53d45..eaceb61ba2dc 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -214,9 +214,9 @@ static int nvidia_insert_memory(struct agp_memory *mem, off_t pg_start, int type
return -EBUSY;
}
- if (mem->is_flushed == FALSE) {
+ if (!mem->is_flushed) {
global_cache_flush();
- mem->is_flushed = TRUE;
+ mem->is_flushed = true;
}
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
writel(agp_bridge->driver->mask_memory(agp_bridge,
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
index 2939e3570f9d..8c42dcc5958c 100644
--- a/drivers/char/agp/parisc-agp.c
+++ b/drivers/char/agp/parisc-agp.c
@@ -141,9 +141,9 @@ parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
j++;
}
- if (mem->is_flushed == FALSE) {
+ if (!mem->is_flushed) {
global_cache_flush();
- mem->is_flushed = TRUE;
+ mem->is_flushed = true;
}
for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
@@ -226,7 +226,7 @@ static const struct agp_bridge_driver parisc_agp_driver = {
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
- .cant_use_aperture = 1,
+ .cant_use_aperture = true,
};
static int __init
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
index 98cf8abb3e57..b972d83bb1b2 100644
--- a/drivers/char/agp/sgi-agp.c
+++ b/drivers/char/agp/sgi-agp.c
@@ -182,9 +182,9 @@ static int sgi_tioca_insert_memory(struct agp_memory *mem, off_t pg_start,
j++;
}
- if (mem->is_flushed == FALSE) {
+ if (!mem->is_flushed) {
bridge->driver->cache_flush();
- mem->is_flushed = TRUE;
+ mem->is_flushed = true;
}
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
@@ -264,8 +264,8 @@ const struct agp_bridge_driver sgi_tioca_driver = {
.agp_alloc_page = sgi_tioca_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
- .cant_use_aperture = 1,
- .needs_scratch_page = 0,
+ .cant_use_aperture = true,
+ .needs_scratch_page = false,
.num_aperture_sizes = 1,
};
diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
index e08934e58f32..0e054c134490 100644
--- a/drivers/char/agp/sworks-agp.c
+++ b/drivers/char/agp/sworks-agp.c
@@ -339,9 +339,9 @@ static int serverworks_insert_memory(struct agp_memory *mem,
j++;
}
- if (mem->is_flushed == FALSE) {
+ if (!mem->is_flushed) {
global_cache_flush();
- mem->is_flushed = TRUE;
+ mem->is_flushed = true;
}
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
@@ -412,7 +412,7 @@ static void serverworks_agp_enable(struct agp_bridge_data *bridge, u32 mode)
bridge->capndx + PCI_AGP_COMMAND,
command);
- agp_device_command(command, 0);
+ agp_device_command(command, false);
}
static const struct agp_bridge_driver sworks_driver = {
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index 42c0a600b1ac..d2fa3cfca02a 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -281,10 +281,10 @@ static void uninorth_agp_enable(struct agp_bridge_data *bridge, u32 mode)
if (uninorth_rev >= 0x30) {
/* This is an AGP V3 */
- agp_device_command(command, (status & AGPSTAT_MODE_3_0));
+ agp_device_command(command, (status & AGPSTAT_MODE_3_0) != 0);
} else {
/* AGP V2 */
- agp_device_command(command, 0);
+ agp_device_command(command, false);
}
uninorth_tlbflush(NULL);
@@ -511,7 +511,7 @@ const struct agp_bridge_driver uninorth_agp_driver = {
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
- .cant_use_aperture = 1,
+ .cant_use_aperture = true,
};
const struct agp_bridge_driver u3_agp_driver = {
@@ -536,8 +536,8 @@ const struct agp_bridge_driver u3_agp_driver = {
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
- .cant_use_aperture = 1,
- .needs_scratch_page = 1,
+ .cant_use_aperture = true,
+ .needs_scratch_page = true,
};
static struct agp_device_ids uninorth_agp_device_ids[] __devinitdata = {
diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
index 0ecc54d327bc..7b36476dff41 100644
--- a/drivers/char/agp/via-agp.c
+++ b/drivers/char/agp/via-agp.c
@@ -389,11 +389,20 @@ static struct agp_device_ids via_agp_device_ids[] __devinitdata =
.device_id = PCI_DEVICE_ID_VIA_VT3324,
.chipset_name = "CX700",
},
- /* VT3336 */
+ /* VT3336 - this is a chipset for AMD Athlon/K8 CPU. Due to K8's unique
+ * architecture, the AGP resource and behavior are different from
+ * the traditional AGP which resides only in chipset. AGP is used
+ * by 3D driver which wasn't available for the VT3336 and VT3364
+ * generation until now. Unfortunately, by testing, VT3364 works
+ * but VT3336 doesn't. - explaination from via, just leave this as
+ * as a placeholder to avoid future patches adding it back in.
+ */
+#if 0
{
.device_id = PCI_DEVICE_ID_VIA_VT3336,
.chipset_name = "VT3336",
},
+#endif
/* P4M890 */
{
.device_id = PCI_DEVICE_ID_VIA_P4M890,
@@ -546,8 +555,8 @@ static const struct pci_device_id agp_via_pci_table[] = {
ID(PCI_DEVICE_ID_VIA_3296_0),
ID(PCI_DEVICE_ID_VIA_P4M800CE),
ID(PCI_DEVICE_ID_VIA_VT3324),
- ID(PCI_DEVICE_ID_VIA_VT3336),
ID(PCI_DEVICE_ID_VIA_P4M890),
+ ID(PCI_DEVICE_ID_VIA_VT3364),
{ }
};
diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c
index b710426bab3e..c533d0c9ec61 100644
--- a/drivers/char/drm/ati_pcigart.c
+++ b/drivers/char/drm/ati_pcigart.c
@@ -76,7 +76,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info
for (i = 0; i < pages; i++) {
if (!entry->busaddr[i])
break;
- pci_unmap_single(dev->pdev, entry->busaddr[i],
+ pci_unmap_page(dev->pdev, entry->busaddr[i],
PAGE_SIZE, PCI_DMA_TODEVICE);
}
@@ -137,10 +137,8 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga
for (i = 0; i < pages; i++) {
/* we need to support large memory configurations */
- entry->busaddr[i] = pci_map_single(dev->pdev,
- page_address(entry->
- pagelist[i]),
- PAGE_SIZE, PCI_DMA_TODEVICE);
+ entry->busaddr[i] = pci_map_page(dev->pdev, entry->pagelist[i],
+ 0, PAGE_SIZE, PCI_DMA_TODEVICE);
if (entry->busaddr[i] == 0) {
DRM_ERROR("unable to map PCIGART pages!\n");
drm_ati_pcigart_cleanup(dev, gart_info);
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
index 6874f31ca8ca..38d3c6b8276a 100644
--- a/drivers/char/drm/drm.h
+++ b/drivers/char/drm/drm.h
@@ -471,7 +471,6 @@ struct drm_irq_busid {
enum drm_vblank_seq_type {
_DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */
_DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */
- _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */
_DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */
_DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */
_DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */
@@ -504,21 +503,6 @@ union drm_wait_vblank {
struct drm_wait_vblank_reply reply;
};
-enum drm_modeset_ctl_cmd {
- _DRM_PRE_MODESET = 1,
- _DRM_POST_MODESET = 2,
-};
-
-/**
- * DRM_IOCTL_MODESET_CTL ioctl argument type
- *
- * \sa drmModesetCtl().
- */
-struct drm_modeset_ctl {
- unsigned long arg;
- enum drm_modeset_ctl_cmd cmd;
-};
-
/**
* DRM_IOCTL_AGP_ENABLE ioctl argument type.
*
@@ -603,7 +587,6 @@ struct drm_set_version {
#define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client)
#define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats)
#define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version)
-#define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl)
#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique)
#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth)
@@ -645,7 +628,7 @@ struct drm_set_version {
#define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, struct drm_agp_binding)
#define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, struct drm_agp_binding)
-#define DRM_IOCTL_SG_ALLOC DRM_IOW( 0x38, struct drm_scatter_gather)
+#define DRM_IOCTL_SG_ALLOC DRM_IOWR(0x38, struct drm_scatter_gather)
#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, struct drm_scatter_gather)
#define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, union drm_wait_vblank)
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 213b3ca3468e..0764b662b339 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -100,8 +100,10 @@ struct drm_device;
#define DRIVER_HAVE_DMA 0x20
#define DRIVER_HAVE_IRQ 0x40
#define DRIVER_IRQ_SHARED 0x80
+#define DRIVER_IRQ_VBL 0x100
#define DRIVER_DMA_QUEUE 0x200
#define DRIVER_FB_DMA 0x400
+#define DRIVER_IRQ_VBL2 0x800
/***********************************************************************/
/** \name Begin the DRM... */
@@ -577,52 +579,10 @@ struct drm_driver {
int (*context_dtor) (struct drm_device *dev, int context);
int (*kernel_context_switch) (struct drm_device *dev, int old,
int new);
- void (*kernel_context_switch_unlock) (struct drm_device * dev);
- /**
- * get_vblank_counter - get raw hardware vblank counter
- * @dev: DRM device
- * @crtc: counter to fetch
- *
- * Driver callback for fetching a raw hardware vblank counter
- * for @crtc. If a device doesn't have a hardware counter, the
- * driver can simply return the value of drm_vblank_count and
- * make the enable_vblank() and disable_vblank() hooks into no-ops,
- * leaving interrupts enabled at all times.
- *
- * Wraparound handling and loss of events due to modesetting is dealt
- * with in the DRM core code.
- *
- * RETURNS
- * Raw vblank counter value.
- */
- u32 (*get_vblank_counter) (struct drm_device *dev, int crtc);
-
- /**
- * enable_vblank - enable vblank interrupt events
- * @dev: DRM device
- * @crtc: which irq to enable
- *
- * Enable vblank interrupts for @crtc. If the device doesn't have
- * a hardware vblank counter, this routine should be a no-op, since
- * interrupts will have to stay on to keep the count accurate.
- *
- * RETURNS
- * Zero on success, appropriate errno if the given @crtc's vblank
- * interrupt cannot be enabled.
- */
- int (*enable_vblank) (struct drm_device *dev, int crtc);
-
- /**
- * disable_vblank - disable vblank interrupt events
- * @dev: DRM device
- * @crtc: which irq to enable
- *
- * Disable vblank interrupts for @crtc. If the device doesn't have
- * a hardware vblank counter, this routine should be a no-op, since
- * interrupts will have to stay on to keep the count accurate.
- */
- void (*disable_vblank) (struct drm_device *dev, int crtc);
- int (*dri_library_name) (struct drm_device *dev, char * buf);
+ void (*kernel_context_switch_unlock) (struct drm_device *dev);
+ int (*vblank_wait) (struct drm_device *dev, unsigned int *sequence);
+ int (*vblank_wait2) (struct drm_device *dev, unsigned int *sequence);
+ int (*dri_library_name) (struct drm_device *dev, char *buf);
/**
* Called by \c drm_device_is_agp. Typically used to determine if a
@@ -641,7 +601,7 @@ struct drm_driver {
irqreturn_t(*irq_handler) (DRM_IRQ_ARGS);
void (*irq_preinstall) (struct drm_device *dev);
- int (*irq_postinstall) (struct drm_device *dev);
+ void (*irq_postinstall) (struct drm_device *dev);
void (*irq_uninstall) (struct drm_device *dev);
void (*reclaim_buffers) (struct drm_device *dev,
struct drm_file * file_priv);
@@ -770,21 +730,13 @@ struct drm_device {
/** \name VBLANK IRQ support */
/*@{ */
- wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */
- atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */
+ wait_queue_head_t vbl_queue; /**< VBLANK wait queue */
+ atomic_t vbl_received;
+ atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */
spinlock_t vbl_lock;
- struct list_head *vbl_sigs; /**< signal list to send on VBLANK */
- atomic_t vbl_signal_pending; /* number of signals pending on all crtcs*/
- atomic_t *vblank_refcount; /* number of users of vblank interrupts per crtc */
- u32 *last_vblank; /* protected by dev->vbl_lock, used */
- /* for wraparound handling */
- u32 *vblank_offset; /* used to track how many vblanks */
- int *vblank_enabled; /* so we don't call enable more than
- once per disable */
- u32 *vblank_premodeset; /* were lost during modeset */
- struct timer_list vblank_disable_timer;
-
- unsigned long max_vblank_count; /**< size of vblank counter register */
+ struct list_head vbl_sigs; /**< signal list to send on VBLANK */
+ struct list_head vbl_sigs2; /**< signals to send on secondary VBLANK */
+ unsigned int vbl_pending;
spinlock_t tasklet_lock; /**< For drm_locked_tasklet */
void (*locked_tasklet_func)(struct drm_device *dev);
@@ -804,7 +756,6 @@ struct drm_device {
#ifdef __alpha__
struct pci_controller *hose;
#endif
- int num_crtcs; /**< Number of CRTCs on this device */
struct drm_sg_mem *sg; /**< Scatter gather memory */
void *dev_private; /**< device private data */
struct drm_sigdata sigdata; /**< For block_all_signals */
@@ -1039,19 +990,11 @@ extern void drm_driver_irq_preinstall(struct drm_device *dev);
extern void drm_driver_irq_postinstall(struct drm_device *dev);
extern void drm_driver_irq_uninstall(struct drm_device *dev);
-extern int drm_vblank_init(struct drm_device *dev, int num_crtcs);
-extern int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *filp);
-extern int drm_vblank_wait(struct drm_device * dev, unsigned int *vbl_seq);
-extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*));
-extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
-extern void drm_update_vblank_count(struct drm_device *dev, int crtc);
-extern void drm_handle_vblank(struct drm_device *dev, int crtc);
-extern int drm_vblank_get(struct drm_device *dev, int crtc);
-extern void drm_vblank_put(struct drm_device *dev, int crtc);
-
- /* Modesetting support */
-extern int drm_modeset_ctl(struct drm_device *dev, void *data,
+extern int drm_wait_vblank(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq);
+extern void drm_vbl_send_signals(struct drm_device *dev);
+extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*));
/* AGP/GART support (drm_agpsupport.h) */
extern struct drm_agp_head *drm_agp_init(struct drm_device *dev);
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index fc54140551a7..564138714bb5 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -470,17 +470,18 @@ int drm_ioctl(struct inode *inode, struct file *filp,
if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) &&
(nr < DRM_COMMAND_BASE + dev->driver->num_ioctls))
ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
- else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE))
+ else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) {
ioctl = &drm_ioctls[nr];
- else
+ cmd = ioctl->cmd;
+ } else
goto err_i1;
+ /* Do not trust userspace, use our own definition */
func = ioctl->func;
/* is there a local override? */
if ((nr == DRM_IOCTL_NR(DRM_IOCTL_DMA)) && dev->driver->dma_ioctl)
func = dev->driver->dma_ioctl;
-
if (!func) {
DRM_DEBUG("no function\n");
retcode = -EINVAL;
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
index 7a25726f07f7..851a53f1acce 100644
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -328,7 +328,6 @@ int drm_release(struct inode *inode, struct file *filp)
struct drm_file *file_priv = filp->private_data;
struct drm_device *dev = file_priv->minor->dev;
int retcode = 0;
- unsigned long irqflags;
lock_kernel();
@@ -360,11 +359,9 @@ int drm_release(struct inode *inode, struct file *filp)
*/
do{
- spin_lock_irqsave(&dev->lock.spinlock,
- irqflags);
+ spin_lock_bh(&dev->lock.spinlock);
locked = dev->lock.idle_has_lock;
- spin_unlock_irqrestore(&dev->lock.spinlock,
- irqflags);
+ spin_unlock_bh(&dev->lock.spinlock);
if (locked)
break;
schedule();
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
index 286f9d61e7d5..089c015c01d1 100644
--- a/drivers/char/drm/drm_irq.c
+++ b/drivers/char/drm/drm_irq.c
@@ -71,117 +71,6 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
return 0;
}
-static void vblank_disable_fn(unsigned long arg)
-{
- struct drm_device *dev = (struct drm_device *)arg;
- unsigned long irqflags;
- int i;
-
- for (i = 0; i < dev->num_crtcs; i++) {
- spin_lock_irqsave(&dev->vbl_lock, irqflags);
- if (atomic_read(&dev->vblank_refcount[i]) == 0 &&
- dev->vblank_enabled[i]) {
- dev->driver->disable_vblank(dev, i);
- dev->vblank_enabled[i] = 0;
- }
- spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
- }
-}
-
-static void drm_vblank_cleanup(struct drm_device *dev)
-{
- /* Bail if the driver didn't call drm_vblank_init() */
- if (dev->num_crtcs == 0)
- return;
-
- del_timer(&dev->vblank_disable_timer);
-
- vblank_disable_fn((unsigned long)dev);
-
- drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs,
- DRM_MEM_DRIVER);
- drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs,
- DRM_MEM_DRIVER);
- drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) *
- dev->num_crtcs, DRM_MEM_DRIVER);
- drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) *
- dev->num_crtcs, DRM_MEM_DRIVER);
- drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) *
- dev->num_crtcs, DRM_MEM_DRIVER);
- drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs,
- DRM_MEM_DRIVER);
- drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) *
- dev->num_crtcs, DRM_MEM_DRIVER);
- drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs,
- DRM_MEM_DRIVER);
-
- dev->num_crtcs = 0;
-}
-
-int drm_vblank_init(struct drm_device *dev, int num_crtcs)
-{
- int i, ret = -ENOMEM;
-
- setup_timer(&dev->vblank_disable_timer, vblank_disable_fn,
- (unsigned long)dev);
- spin_lock_init(&dev->vbl_lock);
- atomic_set(&dev->vbl_signal_pending, 0);
- dev->num_crtcs = num_crtcs;
-
- dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs,
- DRM_MEM_DRIVER);
- if (!dev->vbl_queue)
- goto err;
-
- dev->vbl_sigs = drm_alloc(sizeof(struct list_head) * num_crtcs,
- DRM_MEM_DRIVER);
- if (!dev->vbl_sigs)
- goto err;
-
- dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs,
- DRM_MEM_DRIVER);
- if (!dev->_vblank_count)
- goto err;
-
- dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs,
- DRM_MEM_DRIVER);
- if (!dev->vblank_refcount)
- goto err;
-
- dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int),
- DRM_MEM_DRIVER);
- if (!dev->vblank_enabled)
- goto err;
-
- dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER);
- if (!dev->last_vblank)
- goto err;
-
- dev->vblank_premodeset = drm_calloc(num_crtcs, sizeof(u32),
- DRM_MEM_DRIVER);
- if (!dev->vblank_premodeset)
- goto err;
-
- dev->vblank_offset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER);
- if (!dev->vblank_offset)
- goto err;
-
- /* Zero per-crtc vblank stuff */
- for (i = 0; i < num_crtcs; i++) {
- init_waitqueue_head(&dev->vbl_queue[i]);
- INIT_LIST_HEAD(&dev->vbl_sigs[i]);
- atomic_set(&dev->_vblank_count[i], 0);
- atomic_set(&dev->vblank_refcount[i], 0);
- }
-
- return 0;
-
-err:
- drm_vblank_cleanup(dev);
- return ret;
-}
-EXPORT_SYMBOL(drm_vblank_init);
-
/**
* Install IRQ handler.
*
@@ -220,6 +109,17 @@ static int drm_irq_install(struct drm_device * dev)
DRM_DEBUG("irq=%d\n", dev->irq);
+ if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) {
+ init_waitqueue_head(&dev->vbl_queue);
+
+ spin_lock_init(&dev->vbl_lock);
+
+ INIT_LIST_HEAD(&dev->vbl_sigs);
+ INIT_LIST_HEAD(&dev->vbl_sigs2);
+
+ dev->vbl_pending = 0;
+ }
+
/* Before installing handler */
dev->driver->irq_preinstall(dev);
@@ -237,14 +137,9 @@ static int drm_irq_install(struct drm_device * dev)
}
/* After installing handler */
- ret = dev->driver->irq_postinstall(dev);
- if (ret < 0) {
- mutex_lock(&dev->struct_mutex);
- dev->irq_enabled = 0;
- mutex_unlock(&dev->struct_mutex);
- }
+ dev->driver->irq_postinstall(dev);
- return ret;
+ return 0;
}
/**
@@ -275,8 +170,6 @@ int drm_irq_uninstall(struct drm_device * dev)
free_irq(dev->irq, dev);
- drm_vblank_cleanup(dev);
-
dev->locked_tasklet_func = NULL;
return 0;
@@ -321,148 +214,6 @@ int drm_control(struct drm_device *dev, void *data,
}
/**
- * drm_vblank_count - retrieve "cooked" vblank counter value
- * @dev: DRM device
- * @crtc: which counter to retrieve
- *
- * Fetches the "cooked" vblank count value that represents the number of
- * vblank events since the system was booted, including lost events due to
- * modesetting activity.
- */
-u32 drm_vblank_count(struct drm_device *dev, int crtc)
-{
- return atomic_read(&dev->_vblank_count[crtc]) +
- dev->vblank_offset[crtc];
-}
-EXPORT_SYMBOL(drm_vblank_count);
-
-/**
- * drm_update_vblank_count - update the master vblank counter
- * @dev: DRM device
- * @crtc: counter to update
- *
- * Call back into the driver to update the appropriate vblank counter
- * (specified by @crtc). Deal with wraparound, if it occurred, and
- * update the last read value so we can deal with wraparound on the next
- * call if necessary.
- */
-void drm_update_vblank_count(struct drm_device *dev, int crtc)
-{
- unsigned long irqflags;
- u32 cur_vblank, diff;
-
- /*
- * Interrupts were disabled prior to this call, so deal with counter
- * wrap if needed.
- * NOTE! It's possible we lost a full dev->max_vblank_count events
- * here if the register is small or we had vblank interrupts off for
- * a long time.
- */
- cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
- spin_lock_irqsave(&dev->vbl_lock, irqflags);
- if (cur_vblank < dev->last_vblank[crtc]) {
- diff = dev->max_vblank_count -
- dev->last_vblank[crtc];
- diff += cur_vblank;
- } else {
- diff = cur_vblank - dev->last_vblank[crtc];
- }
- dev->last_vblank[crtc] = cur_vblank;
- spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
-
- atomic_add(diff, &dev->_vblank_count[crtc]);
-}
-EXPORT_SYMBOL(drm_update_vblank_count);
-
-/**
- * drm_vblank_get - get a reference count on vblank events
- * @dev: DRM device
- * @crtc: which CRTC to own
- *
- * Acquire a reference count on vblank events to avoid having them disabled
- * while in use. Note callers will probably want to update the master counter
- * using drm_update_vblank_count() above before calling this routine so that
- * wakeups occur on the right vblank event.
- *
- * RETURNS
- * Zero on success, nonzero on failure.
- */
-int drm_vblank_get(struct drm_device *dev, int crtc)
-{
- unsigned long irqflags;
- int ret = 0;
-
- spin_lock_irqsave(&dev->vbl_lock, irqflags);
- /* Going from 0->1 means we have to enable interrupts again */
- if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 &&
- !dev->vblank_enabled[crtc]) {
- ret = dev->driver->enable_vblank(dev, crtc);
- if (ret)
- atomic_dec(&dev->vblank_refcount[crtc]);
- else
- dev->vblank_enabled[crtc] = 1;
- }
- spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
-
- return ret;
-}
-EXPORT_SYMBOL(drm_vblank_get);
-
-/**
- * drm_vblank_put - give up ownership of vblank events
- * @dev: DRM device
- * @crtc: which counter to give up
- *
- * Release ownership of a given vblank counter, turning off interrupts
- * if possible.
- */
-void drm_vblank_put(struct drm_device *dev, int crtc)
-{
- /* Last user schedules interrupt disable */
- if (atomic_dec_and_test(&dev->vblank_refcount[crtc]))
- mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ);
-}
-EXPORT_SYMBOL(drm_vblank_put);
-
-/**
- * drm_modeset_ctl - handle vblank event counter changes across mode switch
- * @DRM_IOCTL_ARGS: standard ioctl arguments
- *
- * Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET
- * ioctls around modesetting so that any lost vblank events are accounted for.
- */
-int drm_modeset_ctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- struct drm_modeset_ctl *modeset = data;
- int crtc, ret = 0;
- u32 new;
-
- crtc = modeset->arg;
- if (crtc >= dev->num_crtcs) {
- ret = -EINVAL;
- goto out;
- }
-
- switch (modeset->cmd) {
- case _DRM_PRE_MODESET:
- dev->vblank_premodeset[crtc] =
- dev->driver->get_vblank_counter(dev, crtc);
- break;
- case _DRM_POST_MODESET:
- new = dev->driver->get_vblank_counter(dev, crtc);
- dev->vblank_offset[crtc] = dev->vblank_premodeset[crtc] - new;
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
-out:
- return ret;
-}
-
-/**
* Wait for VBLANK.
*
* \param inode device inode.
@@ -481,13 +232,12 @@ out:
*
* If a signal is not requested, then calls vblank_wait().
*/
-int drm_wait_vblank(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
union drm_wait_vblank *vblwait = data;
struct timeval now;
int ret = 0;
- unsigned int flags, seq, crtc;
+ unsigned int flags, seq;
if ((!dev->irq) || (!dev->irq_enabled))
return -EINVAL;
@@ -501,13 +251,13 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
}
flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
- crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
- if (crtc >= dev->num_crtcs)
+ if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
+ DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
return -EINVAL;
- drm_update_vblank_count(dev, crtc);
- seq = drm_vblank_count(dev, crtc);
+ seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2
+ : &dev->vbl_received);
switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {
case _DRM_VBLANK_RELATIVE:
@@ -526,7 +276,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
if (flags & _DRM_VBLANK_SIGNAL) {
unsigned long irqflags;
- struct list_head *vbl_sigs = &dev->vbl_sigs[crtc];
+ struct list_head *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
+ ? &dev->vbl_sigs2 : &dev->vbl_sigs;
struct drm_vbl_sig *vbl_sig;
spin_lock_irqsave(&dev->vbl_lock, irqflags);
@@ -547,26 +298,22 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
}
}
- if (atomic_read(&dev->vbl_signal_pending) >= 100) {
+ if (dev->vbl_pending >= 100) {
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
return -EBUSY;
}
+ dev->vbl_pending++;
+
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
- vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig),
- DRM_MEM_DRIVER);
- if (!vbl_sig)
+ if (!
+ (vbl_sig =
+ drm_alloc(sizeof(struct drm_vbl_sig), DRM_MEM_DRIVER))) {
return -ENOMEM;
-
- ret = drm_vblank_get(dev, crtc);
- if (ret) {
- drm_free(vbl_sig, sizeof(struct drm_vbl_sig),
- DRM_MEM_DRIVER);
- return ret;
}
- atomic_inc(&dev->vbl_signal_pending);
+ memset((void *)vbl_sig, 0, sizeof(*vbl_sig));
vbl_sig->sequence = vblwait->request.sequence;
vbl_sig->info.si_signo = vblwait->request.signal;
@@ -580,20 +327,17 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
vblwait->reply.sequence = seq;
} else {
- unsigned long cur_vblank;
-
- ret = drm_vblank_get(dev, crtc);
- if (ret)
- return ret;
- DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
- (((cur_vblank = drm_vblank_count(dev, crtc))
- - vblwait->request.sequence) <= (1 << 23)));
- drm_vblank_put(dev, crtc);
- do_gettimeofday(&now);
+ if (flags & _DRM_VBLANK_SECONDARY) {
+ if (dev->driver->vblank_wait2)
+ ret = dev->driver->vblank_wait2(dev, &vblwait->request.sequence);
+ } else if (dev->driver->vblank_wait)
+ ret =
+ dev->driver->vblank_wait(dev,
+ &vblwait->request.sequence);
+ do_gettimeofday(&now);
vblwait->reply.tval_sec = now.tv_sec;
vblwait->reply.tval_usec = now.tv_usec;
- vblwait->reply.sequence = cur_vblank;
}
done:
@@ -604,57 +348,44 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
* Send the VBLANK signals.
*
* \param dev DRM device.
- * \param crtc CRTC where the vblank event occurred
*
* Sends a signal for each task in drm_device::vbl_sigs and empties the list.
*
* If a signal is not requested, then calls vblank_wait().
*/
-static void drm_vbl_send_signals(struct drm_device * dev, int crtc)
+void drm_vbl_send_signals(struct drm_device * dev)
{
- struct drm_vbl_sig *vbl_sig, *tmp;
- struct list_head *vbl_sigs;
- unsigned int vbl_seq;
unsigned long flags;
+ int i;
spin_lock_irqsave(&dev->vbl_lock, flags);
- vbl_sigs = &dev->vbl_sigs[crtc];
- vbl_seq = drm_vblank_count(dev, crtc);
+ for (i = 0; i < 2; i++) {
+ struct drm_vbl_sig *vbl_sig, *tmp;
+ struct list_head *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
+ unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 :
+ &dev->vbl_received);
- list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) {
- if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
- vbl_sig->info.si_code = vbl_seq;
- send_sig_info(vbl_sig->info.si_signo,
- &vbl_sig->info, vbl_sig->task);
+ list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) {
+ if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
+ vbl_sig->info.si_code = vbl_seq;
+ send_sig_info(vbl_sig->info.si_signo,
+ &vbl_sig->info, vbl_sig->task);
- list_del(&vbl_sig->head);
+ list_del(&vbl_sig->head);
- drm_free(vbl_sig, sizeof(*vbl_sig),
- DRM_MEM_DRIVER);
- atomic_dec(&dev->vbl_signal_pending);
- drm_vblank_put(dev, crtc);
- }
+ drm_free(vbl_sig, sizeof(*vbl_sig),
+ DRM_MEM_DRIVER);
+
+ dev->vbl_pending--;
+ }
+ }
}
spin_unlock_irqrestore(&dev->vbl_lock, flags);
}
-/**
- * drm_handle_vblank - handle a vblank event
- * @dev: DRM device
- * @crtc: where this event occurred
- *
- * Drivers should call this routine in their vblank interrupt handlers to
- * update the vblank counter and send any signals that may be pending.
- */
-void drm_handle_vblank(struct drm_device *dev, int crtc)
-{
- drm_update_vblank_count(dev, crtc);
- DRM_WAKEUP(&dev->vbl_queue[crtc]);
- drm_vbl_send_signals(dev, crtc);
-}
-EXPORT_SYMBOL(drm_handle_vblank);
+EXPORT_SYMBOL(drm_vbl_send_signals);
/**
* Tasklet wrapper function.
diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c
index 12dcdd1832f0..0998723cde79 100644
--- a/drivers/char/drm/drm_lock.c
+++ b/drivers/char/drm/drm_lock.c
@@ -53,7 +53,6 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
DECLARE_WAITQUEUE(entry, current);
struct drm_lock *lock = data;
int ret = 0;
- unsigned long irqflags;
++file_priv->lock_count;
@@ -72,9 +71,9 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
return -EINVAL;
add_wait_queue(&dev->lock.lock_queue, &entry);
- spin_lock_irqsave(&dev->lock.spinlock, irqflags);
+ spin_lock_bh(&dev->lock.spinlock);
dev->lock.user_waiters++;
- spin_unlock_irqrestore(&dev->lock.spinlock, irqflags);
+ spin_unlock_bh(&dev->lock.spinlock);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
if (!dev->lock.hw_lock) {
@@ -96,9 +95,9 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
break;
}
}
- spin_lock_irqsave(&dev->lock.spinlock, irqflags);
+ spin_lock_bh(&dev->lock.spinlock);
dev->lock.user_waiters--;
- spin_unlock_irqrestore(&dev->lock.spinlock, irqflags);
+ spin_unlock_bh(&dev->lock.spinlock);
__set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->lock.lock_queue, &entry);
@@ -199,9 +198,8 @@ int drm_lock_take(struct drm_lock_data *lock_data,
{
unsigned int old, new, prev;
volatile unsigned int *lock = &lock_data->hw_lock->lock;
- unsigned long irqflags;
- spin_lock_irqsave(&lock_data->spinlock, irqflags);
+ spin_lock_bh(&lock_data->spinlock);
do {
old = *lock;
if (old & _DRM_LOCK_HELD)
@@ -213,7 +211,7 @@ int drm_lock_take(struct drm_lock_data *lock_data,
}
prev = cmpxchg(lock, old, new);
} while (prev != old);
- spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
+ spin_unlock_bh(&lock_data->spinlock);
if (_DRM_LOCKING_CONTEXT(old) == context) {
if (old & _DRM_LOCK_HELD) {
@@ -274,16 +272,15 @@ int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context)
{
unsigned int old, new, prev;
volatile unsigned int *lock = &lock_data->hw_lock->lock;
- unsigned long irqflags;
- spin_lock_irqsave(&lock_data->spinlock, irqflags);
+ spin_lock_bh(&lock_data->spinlock);
if (lock_data->kernel_waiters != 0) {
drm_lock_transfer(lock_data, 0);
lock_data->idle_has_lock = 1;
- spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
+ spin_unlock_bh(&lock_data->spinlock);
return 1;
}
- spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
+ spin_unlock_bh(&lock_data->spinlock);
do {
old = *lock;
@@ -347,20 +344,19 @@ static int drm_notifier(void *priv)
void drm_idlelock_take(struct drm_lock_data *lock_data)
{
int ret = 0;
- unsigned long irqflags;
- spin_lock_irqsave(&lock_data->spinlock, irqflags);
+ spin_lock_bh(&lock_data->spinlock);
lock_data->kernel_waiters++;
if (!lock_data->idle_has_lock) {
- spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
+ spin_unlock_bh(&lock_data->spinlock);
ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT);
- spin_lock_irqsave(&lock_data->spinlock, irqflags);
+ spin_lock_bh(&lock_data->spinlock);
if (ret == 1)
lock_data->idle_has_lock = 1;
}
- spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
+ spin_unlock_bh(&lock_data->spinlock);
}
EXPORT_SYMBOL(drm_idlelock_take);
@@ -368,9 +364,8 @@ void drm_idlelock_release(struct drm_lock_data *lock_data)
{
unsigned int old, prev;
volatile unsigned int *lock = &lock_data->hw_lock->lock;
- unsigned long irqflags;
- spin_lock_irqsave(&lock_data->spinlock, irqflags);
+ spin_lock_bh(&lock_data->spinlock);
if (--lock_data->kernel_waiters == 0) {
if (lock_data->idle_has_lock) {
do {
@@ -381,7 +376,7 @@ void drm_idlelock_release(struct drm_lock_data *lock_data)
lock_data->idle_has_lock = 0;
}
}
- spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
+ spin_unlock_bh(&lock_data->spinlock);
}
EXPORT_SYMBOL(drm_idlelock_release);
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index a6a499f97e22..135bd19499fc 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -103,20 +103,18 @@
{0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \
{0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
- {0x1002, 0x5954, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
- {0x1002, 0x5955, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
- {0x1002, 0x5974, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
- {0x1002, 0x5975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
+ {0x1002, 0x5954, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
+ {0x1002, 0x5955, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
+ {0x1002, 0x5974, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
+ {0x1002, 0x5975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
{0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
{0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
{0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
{0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
{0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
{0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
- {0x1002, 0x5a41, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
- {0x1002, 0x5a42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
- {0x1002, 0x5a61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
- {0x1002, 0x5a62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
+ {0x1002, 0x5a61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
+ {0x1002, 0x5a62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
{0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
{0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
{0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
@@ -411,4 +409,7 @@
{0x8086, 0x2a02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x8086, 0x2a12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x8086, 0x2a42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x8086, 0x2e02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x8086, 0x2e12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x8086, 0x2e22, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0, 0, 0}
diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c
index 9a32169e88fb..af211a0ef179 100644
--- a/drivers/char/drm/drm_sysfs.c
+++ b/drivers/char/drm/drm_sysfs.c
@@ -34,8 +34,6 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state)
struct drm_minor *drm_minor = to_drm_minor(dev);
struct drm_device *drm_dev = drm_minor->dev;
- printk(KERN_ERR "%s\n", __func__);
-
if (drm_dev->driver->suspend)
return drm_dev->driver->suspend(drm_dev, state);
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index f47e46e3529f..88974342933c 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -415,13 +415,10 @@ static void i915_emit_breadcrumb(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
- if (++dev_priv->counter > BREADCRUMB_MASK) {
- dev_priv->counter = 1;
- DRM_DEBUG("Breadcrumb counter wrapped around\n");
- }
+ dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
- if (dev_priv->sarea_priv)
- dev_priv->sarea_priv->last_enqueue = dev_priv->counter;
+ if (dev_priv->counter > 0x7FFFFFFFUL)
+ dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
BEGIN_LP_RING(4);
OUT_RING(CMD_STORE_DWORD_IDX);
@@ -431,26 +428,6 @@ static void i915_emit_breadcrumb(struct drm_device *dev)
ADVANCE_LP_RING();
}
-int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- uint32_t flush_cmd = CMD_MI_FLUSH;
- RING_LOCALS;
-
- flush_cmd |= flush;
-
- i915_kernel_lost_context(dev);
-
- BEGIN_LP_RING(4);
- OUT_RING(flush_cmd);
- OUT_RING(0);
- OUT_RING(0);
- OUT_RING(0);
- ADVANCE_LP_RING();
-
- return 0;
-}
-
static int i915_dispatch_cmdbuffer(struct drm_device * dev,
drm_i915_cmdbuffer_t * cmd)
{
@@ -534,74 +511,52 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
return 0;
}
-static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync)
+static int i915_dispatch_flip(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- u32 num_pages, current_page, next_page, dspbase;
- int shift = 2 * plane, x, y;
RING_LOCALS;
- /* Calculate display base offset */
- num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2;
- current_page = (dev_priv->sarea_priv->pf_current_page >> shift) & 0x3;
- next_page = (current_page + 1) % num_pages;
+ DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
+ __FUNCTION__,
+ dev_priv->current_page,
+ dev_priv->sarea_priv->pf_current_page);
- switch (next_page) {
- default:
- case 0:
- dspbase = dev_priv->sarea_priv->front_offset;
- break;
- case 1:
- dspbase = dev_priv->sarea_priv->back_offset;
- break;
- case 2:
- dspbase = dev_priv->sarea_priv->third_offset;
- break;
- }
+ i915_kernel_lost_context(dev);
+
+ BEGIN_LP_RING(2);
+ OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
+ OUT_RING(0);
+ ADVANCE_LP_RING();
- if (plane == 0) {
- x = dev_priv->sarea_priv->planeA_x;
- y = dev_priv->sarea_priv->planeA_y;
+ BEGIN_LP_RING(6);
+ OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP);
+ OUT_RING(0);
+ if (dev_priv->current_page == 0) {
+ OUT_RING(dev_priv->back_offset);
+ dev_priv->current_page = 1;
} else {
- x = dev_priv->sarea_priv->planeB_x;
- y = dev_priv->sarea_priv->planeB_y;
+ OUT_RING(dev_priv->front_offset);
+ dev_priv->current_page = 0;
}
+ OUT_RING(0);
+ ADVANCE_LP_RING();
- dspbase += (y * dev_priv->sarea_priv->pitch + x) * dev_priv->cpp;
+ BEGIN_LP_RING(2);
+ OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP);
+ OUT_RING(0);
+ ADVANCE_LP_RING();
- DRM_DEBUG("plane=%d current_page=%d dspbase=0x%x\n", plane, current_page,
- dspbase);
+ dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
BEGIN_LP_RING(4);
- OUT_RING(sync ? 0 :
- (MI_WAIT_FOR_EVENT | (plane ? MI_WAIT_FOR_PLANE_B_FLIP :
- MI_WAIT_FOR_PLANE_A_FLIP)));
- OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | (sync ? 0 : ASYNC_FLIP) |
- (plane ? DISPLAY_PLANE_B : DISPLAY_PLANE_A));
- OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp);
- OUT_RING(dspbase);
+ OUT_RING(CMD_STORE_DWORD_IDX);
+ OUT_RING(20);
+ OUT_RING(dev_priv->counter);
+ OUT_RING(0);
ADVANCE_LP_RING();
- dev_priv->sarea_priv->pf_current_page &= ~(0x3 << shift);
- dev_priv->sarea_priv->pf_current_page |= next_page << shift;
-}
-
-void i915_dispatch_flip(struct drm_device * dev, int planes, int sync)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- int i;
-
- DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n",
- planes, dev_priv->sarea_priv->pf_current_page);
-
- i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH);
-
- for (i = 0; i < 2; i++)
- if (planes & (1 << i))
- i915_do_dispatch_flip(dev, i, sync);
-
- i915_emit_breadcrumb(dev);
-
+ dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+ return 0;
}
static int i915_quiescent(struct drm_device * dev)
@@ -624,6 +579,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u32 *hw_status = dev_priv->hw_status_page;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv;
drm_i915_batchbuffer_t *batch = data;
@@ -646,7 +602,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
ret = i915_dispatch_batchbuffer(dev, batch);
- sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+ sarea_priv->last_dispatch = (int)hw_status[5];
return ret;
}
@@ -654,6 +610,7 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u32 *hw_status = dev_priv->hw_status_page;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv;
drm_i915_cmdbuffer_t *cmdbuf = data;
@@ -678,51 +635,18 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
return ret;
}
- sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
- return 0;
-}
-
-static int i915_do_cleanup_pageflip(struct drm_device * dev)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- int i, planes, num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2;
-
- DRM_DEBUG("\n");
-
- for (i = 0, planes = 0; i < 2; i++)
- if (dev_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) {
- dev_priv->sarea_priv->pf_current_page =
- (dev_priv->sarea_priv->pf_current_page &
- ~(0x3 << (2 * i))) | ((num_pages - 1) << (2 * i));
-
- planes |= 1 << i;
- }
-
- if (planes)
- i915_dispatch_flip(dev, planes, 0);
-
+ sarea_priv->last_dispatch = (int)hw_status[5];
return 0;
}
static int i915_flip_bufs(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- drm_i915_flip_t *param = data;
-
- DRM_DEBUG("\n");
+ DRM_DEBUG("%s\n", __FUNCTION__);
LOCK_TEST_WITH_RETURN(dev, file_priv);
- /* This is really planes */
- if (param->pipes & ~0x3) {
- DRM_ERROR("Invalid planes 0x%x, only <= 0x3 is valid\n",
- param->pipes);
- return -EINVAL;
- }
-
- i915_dispatch_flip(dev, param->pipes, 0);
-
- return 0;
+ return i915_dispatch_flip(dev);
}
static int i915_getparam(struct drm_device *dev, void *data,
@@ -883,8 +807,6 @@ void i915_driver_lastclose(struct drm_device * dev)
if (!dev_priv)
return;
- if (drm_getsarea(dev) && dev_priv->sarea_priv)
- i915_do_cleanup_pageflip(dev);
if (dev_priv->agp_heap)
i915_mem_takedown(&(dev_priv->agp_heap));
diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h
index 0431c00e2289..05c66cf03a9e 100644
--- a/drivers/char/drm/i915_drm.h
+++ b/drivers/char/drm/i915_drm.h
@@ -105,29 +105,14 @@ typedef struct _drm_i915_sarea {
unsigned int rotated_tiled;
unsigned int rotated2_tiled;
- int planeA_x;
- int planeA_y;
- int planeA_w;
- int planeA_h;
- int planeB_x;
- int planeB_y;
- int planeB_w;
- int planeB_h;
-
- /* Triple buffering */
- drm_handle_t third_handle;
- int third_offset;
- int third_size;
- unsigned int third_tiled;
-
- /* buffer object handles for the static buffers. May change
- * over the lifetime of the client, though it doesn't in our current
- * implementation.
- */
- unsigned int front_bo_handle;
- unsigned int back_bo_handle;
- unsigned int third_bo_handle;
- unsigned int depth_bo_handle;
+ int pipeA_x;
+ int pipeA_y;
+ int pipeA_w;
+ int pipeA_h;
+ int pipeB_x;
+ int pipeB_y;
+ int pipeB_w;
+ int pipeB_h;
} drm_i915_sarea_t;
/* Flags for perf_boxes
@@ -161,7 +146,7 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
-#define DRM_IOCTL_I915_FLIP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_FLIP, drm_i915_flip_t)
+#define DRM_IOCTL_I915_FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLIP)
#define DRM_IOCTL_I915_BATCHBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_BATCHBUFFER, drm_i915_batchbuffer_t)
#define DRM_IOCTL_I915_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_IRQ_EMIT, drm_i915_irq_emit_t)
#define DRM_IOCTL_I915_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_IRQ_WAIT, drm_i915_irq_wait_t)
@@ -176,18 +161,6 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t)
-/* Asynchronous page flipping:
- */
-typedef struct drm_i915_flip {
- /*
- * This is really talking about planes, and we could rename it
- * except for the fact that some of the duplicated i915_drm.h files
- * out there check for HAVE_I915_FLIP and so might pick up this
- * version.
- */
- int pipes;
-} drm_i915_flip_t;
-
/* Allow drivers to submit batchbuffers directly to hardware, relying
* on the security mechanisms provided by hardware.
*/
diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c
index bb8f1b2fb383..93aed1c38bd2 100644
--- a/drivers/char/drm/i915_drv.c
+++ b/drivers/char/drm/i915_drv.c
@@ -147,7 +147,7 @@ static void i915_save_vga(struct drm_device *dev)
i915_write_indexed(cr_index, cr_data, 0x11,
i915_read_indexed(cr_index, cr_data, 0x11) &
(~0x80));
- for (i = 0; i < 0x24; i++)
+ for (i = 0; i <= 0x24; i++)
dev_priv->saveCR[i] =
i915_read_indexed(cr_index, cr_data, i);
/* Make sure we don't turn off CR group 0 writes */
@@ -156,7 +156,7 @@ static void i915_save_vga(struct drm_device *dev)
/* Attribute controller registers */
inb(st01);
dev_priv->saveAR_INDEX = inb(VGA_AR_INDEX);
- for (i = 0; i < 20; i++)
+ for (i = 0; i <= 0x14; i++)
dev_priv->saveAR[i] = i915_read_ar(st01, i, 0);
inb(st01);
outb(dev_priv->saveAR_INDEX, VGA_AR_INDEX);
@@ -206,7 +206,7 @@ static void i915_restore_vga(struct drm_device *dev)
/* CRT controller regs */
/* Enable CR group 0 writes */
i915_write_indexed(cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]);
- for (i = 0; i < 0x24; i++)
+ for (i = 0; i <= 0x24; i++)
i915_write_indexed(cr_index, cr_data, i, dev_priv->saveCR[i]);
/* Graphics controller regs */
@@ -223,7 +223,7 @@ static void i915_restore_vga(struct drm_device *dev)
/* Attribute controller registers */
inb(st01);
- for (i = 0; i < 20; i++)
+ for (i = 0; i <= 0x14; i++)
i915_write_ar(st01, i, dev_priv->saveAR[i], 0);
inb(st01); /* switch back to index mode */
outb(dev_priv->saveAR_INDEX | 0x20, VGA_AR_INDEX);
@@ -256,6 +256,9 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
pci_save_state(dev->pdev);
pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
+ /* Display arbitration control */
+ dev_priv->saveDSPARB = I915_READ(DSPARB);
+
/* Pipe & plane A info */
dev_priv->savePIPEACONF = I915_READ(PIPEACONF);
dev_priv->savePIPEASRC = I915_READ(PIPEASRC);
@@ -349,6 +352,7 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
dev_priv->saveVGACNTRL = I915_READ(VGACNTRL);
/* Clock gating state */
+ dev_priv->saveD_STATE = I915_READ(D_STATE);
dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D);
/* Cache mode state */
@@ -385,9 +389,12 @@ static int i915_resume(struct drm_device *dev)
pci_restore_state(dev->pdev);
if (pci_enable_device(dev->pdev))
return -1;
+ pci_set_master(dev->pdev);
pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB);
+ I915_WRITE(DSPARB, dev_priv->saveDSPARB);
+
/* Pipe & plane A info */
/* Prime the clock */
if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
@@ -507,6 +514,7 @@ static int i915_resume(struct drm_device *dev)
udelay(150);
/* Clock gating state */
+ I915_WRITE (D_STATE, dev_priv->saveD_STATE);
I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D);
/* Cache mode state */
@@ -533,7 +541,8 @@ static struct drm_driver driver = {
*/
.driver_features =
DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/
- DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
+ DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL |
+ DRIVER_IRQ_VBL2,
.load = i915_driver_load,
.unload = i915_driver_unload,
.lastclose = i915_driver_lastclose,
@@ -541,9 +550,8 @@ static struct drm_driver driver = {
.suspend = i915_suspend,
.resume = i915_resume,
.device_is_agp = i915_driver_device_is_agp,
- .get_vblank_counter = i915_get_vblank_counter,
- .enable_vblank = i915_enable_vblank,
- .disable_vblank = i915_disable_vblank,
+ .vblank_wait = i915_driver_vblank_wait,
+ .vblank_wait2 = i915_driver_vblank_wait2,
.irq_preinstall = i915_driver_irq_preinstall,
.irq_postinstall = i915_driver_irq_postinstall,
.irq_uninstall = i915_driver_irq_uninstall,
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index db7001f22561..d7326d92a237 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -76,9 +76,8 @@ struct mem_block {
typedef struct _drm_i915_vbl_swap {
struct list_head head;
drm_drawable_t drw_id;
- unsigned int plane;
+ unsigned int pipe;
unsigned int sequence;
- int flip;
} drm_i915_vbl_swap_t;
typedef struct drm_i915_private {
@@ -91,7 +90,7 @@ typedef struct drm_i915_private {
drm_dma_handle_t *status_page_dmah;
void *hw_status_page;
dma_addr_t dma_status_page;
- uint32_t counter;
+ unsigned long counter;
unsigned int status_gfx_addr;
drm_local_map_t hws_map;
@@ -104,18 +103,13 @@ typedef struct drm_i915_private {
wait_queue_head_t irq_queue;
atomic_t irq_received;
- atomic_t irq_emited;
+ atomic_t irq_emitted;
int tex_lru_log_granularity;
int allow_batchbuffer;
struct mem_block *agp_heap;
unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
int vblank_pipe;
- spinlock_t user_irq_lock;
- int user_irq_refcount;
- int fence_irq_on;
- uint32_t irq_enable_reg;
- int irq_enabled;
spinlock_t swaps_lock;
drm_i915_vbl_swap_t vbl_swaps;
@@ -125,6 +119,7 @@ typedef struct drm_i915_private {
u8 saveLBB;
u32 saveDSPACNTR;
u32 saveDSPBCNTR;
+ u32 saveDSPARB;
u32 savePIPEACONF;
u32 savePIPEBCONF;
u32 savePIPEASRC;
@@ -194,6 +189,7 @@ typedef struct drm_i915_private {
u32 saveIIR;
u32 saveIMR;
u32 saveCACHE_MODE_0;
+ u32 saveD_STATE;
u32 saveDSPCLK_GATE_D;
u32 saveMI_ARB_STATE;
u32 saveSWF0[16];
@@ -203,10 +199,10 @@ typedef struct drm_i915_private {
u8 saveSR[8];
u8 saveGR[25];
u8 saveAR_INDEX;
- u8 saveAR[20];
+ u8 saveAR[21];
u8 saveDACMASK;
u8 saveDACDATA[256*3]; /* 256 3-byte colors */
- u8 saveCR[36];
+ u8 saveCR[37];
} drm_i915_private_t;
extern struct drm_ioctl_desc i915_ioctls[];
@@ -222,7 +218,7 @@ extern void i915_driver_preclose(struct drm_device *dev,
extern int i915_driver_device_is_agp(struct drm_device * dev);
extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
-extern void i915_dispatch_flip(struct drm_device * dev, int pipes, int sync);
+
/* i915_irq.c */
extern int i915_irq_emit(struct drm_device *dev, void *data,
struct drm_file *file_priv);
@@ -233,7 +229,7 @@ extern int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequenc
extern int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence);
extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
extern void i915_driver_irq_preinstall(struct drm_device * dev);
-extern int i915_driver_irq_postinstall(struct drm_device * dev);
+extern void i915_driver_irq_postinstall(struct drm_device * dev);
extern void i915_driver_irq_uninstall(struct drm_device * dev);
extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
struct drm_file *file_priv);
@@ -241,9 +237,6 @@ extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int i915_vblank_swap(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-extern int i915_enable_vblank(struct drm_device *dev, int crtc);
-extern void i915_disable_vblank(struct drm_device *dev, int crtc);
-extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc);
/* i915_mem.c */
extern int i915_mem_alloc(struct drm_device *dev, void *data,
@@ -388,91 +381,21 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
/* Interrupt bits:
*/
-#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18)
-#define I915_DISPLAY_PORT_INTERRUPT (1<<17)
-#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15)
-#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14)
-#define I915_HWB_OOM_INTERRUPT (1<<13) /* binner out of memory */
-#define I915_SYNC_STATUS_INTERRUPT (1<<12)
-#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11)
-#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10)
-#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9)
-#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8)
-#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7)
-#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6)
-#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5)
-#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4)
-#define I915_DEBUG_INTERRUPT (1<<2)
-#define I915_USER_INTERRUPT (1<<1)
-
+#define USER_INT_FLAG (1<<1)
+#define VSYNC_PIPEB_FLAG (1<<5)
+#define VSYNC_PIPEA_FLAG (1<<7)
+#define HWB_OOM_FLAG (1<<13) /* binner out of memory */
#define I915REG_HWSTAM 0x02098
#define I915REG_INT_IDENTITY_R 0x020a4
#define I915REG_INT_MASK_R 0x020a8
#define I915REG_INT_ENABLE_R 0x020a0
-#define I915REG_INSTPM 0x020c0
-
-#define PIPEADSL 0x70000
-#define PIPEBDSL 0x71000
#define I915REG_PIPEASTAT 0x70024
#define I915REG_PIPEBSTAT 0x71024
-/*
- * The two pipe frame counter registers are not synchronized, so
- * reading a stable value is somewhat tricky. The following code
- * should work:
- *
- * do {
- * high1 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >>
- * PIPE_FRAME_HIGH_SHIFT;
- * low1 = ((INREG(PIPEAFRAMEPIXEL) & PIPE_FRAME_LOW_MASK) >>
- * PIPE_FRAME_LOW_SHIFT);
- * high2 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >>
- * PIPE_FRAME_HIGH_SHIFT);
- * } while (high1 != high2);
- * frame = (high1 << 8) | low1;
- */
-#define PIPEAFRAMEHIGH 0x70040
-#define PIPEBFRAMEHIGH 0x71040
-#define PIPE_FRAME_HIGH_MASK 0x0000ffff
-#define PIPE_FRAME_HIGH_SHIFT 0
-#define PIPEAFRAMEPIXEL 0x70044
-#define PIPEBFRAMEPIXEL 0x71044
-#define PIPE_FRAME_LOW_MASK 0xff000000
-#define PIPE_FRAME_LOW_SHIFT 24
-/*
- * Pixel within the current frame is counted in the PIPEAFRAMEPIXEL register
- * and is 24 bits wide.
- */
-#define PIPE_PIXEL_MASK 0x00ffffff
-#define PIPE_PIXEL_SHIFT 0
-
-#define I915_FIFO_UNDERRUN_STATUS (1UL<<31)
-#define I915_CRC_ERROR_ENABLE (1UL<<29)
-#define I915_CRC_DONE_ENABLE (1UL<<28)
-#define I915_GMBUS_EVENT_ENABLE (1UL<<27)
-#define I915_VSYNC_INTERRUPT_ENABLE (1UL<<25)
-#define I915_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24)
-#define I915_DPST_EVENT_ENABLE (1UL<<23)
-#define I915_LEGACY_BLC_EVENT_ENABLE (1UL<<22)
-#define I915_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21)
-#define I915_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20)
-#define I915_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */
-#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17)
-#define I915_OVERLAY_UPDATED_ENABLE (1UL<<16)
-#define I915_CRC_ERROR_INTERRUPT_STATUS (1UL<<13)
-#define I915_CRC_DONE_INTERRUPT_STATUS (1UL<<12)
-#define I915_GMBUS_INTERRUPT_STATUS (1UL<<11)
-#define I915_VSYNC_INTERRUPT_STATUS (1UL<<9)
-#define I915_DISPLAY_LINE_COMPARE_STATUS (1UL<<8)
-#define I915_DPST_EVENT_STATUS (1UL<<7)
-#define I915_LEGACY_BLC_EVENT_STATUS (1UL<<6)
-#define I915_ODD_FIELD_INTERRUPT_STATUS (1UL<<5)
-#define I915_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4)
-#define I915_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */
-#define I915_VBLANK_INTERRUPT_STATUS (1UL<<1)
-#define I915_OVERLAY_UPDATED_STATUS (1UL<<0)
+#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17)
+#define I915_VBLANK_CLEAR (1UL<<1)
#define SRX_INDEX 0x3c4
#define SRX_DATA 0x3c5
@@ -749,6 +672,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
/** P1 value is 2 greater than this field */
# define VGA0_PD_P1_MASK (0x1f << 0)
+/* PCI D state control register */
+#define D_STATE 0x6104
#define DSPCLK_GATE_D 0x6200
/* I830 CRTC registers */
@@ -1059,6 +984,12 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21)
#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21)
+#define DSPARB 0x70030
+#define DSPARB_CSTART_MASK (0x7f << 7)
+#define DSPARB_CSTART_SHIFT 7
+#define DSPARB_BSTART_MASK (0x7f)
+#define DSPARB_BSTART_SHIFT 0
+
#define PIPEBCONF 0x71008
#define PIPEBCONF_ENABLE (1<<31)
#define PIPEBCONF_DISABLE 0
@@ -1181,12 +1112,19 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
(dev)->pci_device == 0x29A2 || \
(dev)->pci_device == 0x2A02 || \
(dev)->pci_device == 0x2A12 || \
- (dev)->pci_device == 0x2A42)
+ (dev)->pci_device == 0x2A42 || \
+ (dev)->pci_device == 0x2E02 || \
+ (dev)->pci_device == 0x2E12 || \
+ (dev)->pci_device == 0x2E22)
#define IS_I965GM(dev) ((dev)->pci_device == 0x2A02)
#define IS_IGD_GM(dev) ((dev)->pci_device == 0x2A42)
+#define IS_G4X(dev) ((dev)->pci_device == 0x2E02 || \
+ (dev)->pci_device == 0x2E12 || \
+ (dev)->pci_device == 0x2E22)
+
#define IS_G33(dev) ((dev)->pci_device == 0x29C2 || \
(dev)->pci_device == 0x29B2 || \
(dev)->pci_device == 0x29D2)
@@ -1197,7 +1135,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \
IS_I945GM(dev) || IS_I965GM(dev) || IS_IGD_GM(dev))
-#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_IGD_GM(dev))
+#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_IGD_GM(dev) || IS_G4X(dev))
#define PRIMARY_RINGBUFFER_SIZE (128*1024)
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index 023ce66ef3ab..df036118b8b1 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -38,109 +38,6 @@
#define MAX_NOPID ((u32)~0)
/**
- * i915_get_pipe - return the the pipe associated with a given plane
- * @dev: DRM device
- * @plane: plane to look for
- *
- * The Intel Mesa & 2D drivers call the vblank routines with a plane number
- * rather than a pipe number, since they may not always be equal. This routine
- * maps the given @plane back to a pipe number.
- */
-static int
-i915_get_pipe(struct drm_device *dev, int plane)
-{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u32 dspcntr;
-
- dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR);
-
- return dspcntr & DISPPLANE_SEL_PIPE_MASK ? 1 : 0;
-}
-
-/**
- * i915_get_plane - return the the plane associated with a given pipe
- * @dev: DRM device
- * @pipe: pipe to look for
- *
- * The Intel Mesa & 2D drivers call the vblank routines with a plane number
- * rather than a plane number, since they may not always be equal. This routine
- * maps the given @pipe back to a plane number.
- */
-static int
-i915_get_plane(struct drm_device *dev, int pipe)
-{
- if (i915_get_pipe(dev, 0) == pipe)
- return 0;
- return 1;
-}
-
-/**
- * i915_pipe_enabled - check if a pipe is enabled
- * @dev: DRM device
- * @pipe: pipe to check
- *
- * Reading certain registers when the pipe is disabled can hang the chip.
- * Use this routine to make sure the PLL is running and the pipe is active
- * before reading such registers if unsure.
- */
-static int
-i915_pipe_enabled(struct drm_device *dev, int pipe)
-{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF;
-
- if (I915_READ(pipeconf) & PIPEACONF_ENABLE)
- return 1;
-
- return 0;
-}
-
-/**
- * Emit a synchronous flip.
- *
- * This function must be called with the drawable spinlock held.
- */
-static void
-i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw,
- int plane)
-{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
- u16 x1, y1, x2, y2;
- int pf_planes = 1 << plane;
-
- /* If the window is visible on the other plane, we have to flip on that
- * plane as well.
- */
- if (plane == 1) {
- x1 = sarea_priv->planeA_x;
- y1 = sarea_priv->planeA_y;
- x2 = x1 + sarea_priv->planeA_w;
- y2 = y1 + sarea_priv->planeA_h;
- } else {
- x1 = sarea_priv->planeB_x;
- y1 = sarea_priv->planeB_y;
- x2 = x1 + sarea_priv->planeB_w;
- y2 = y1 + sarea_priv->planeB_h;
- }
-
- if (x2 > 0 && y2 > 0) {
- int i, num_rects = drw->num_rects;
- struct drm_clip_rect *rect = drw->rects;
-
- for (i = 0; i < num_rects; i++)
- if (!(rect[i].x1 >= x2 || rect[i].y1 >= y2 ||
- rect[i].x2 <= x1 || rect[i].y2 <= y1)) {
- pf_planes = 0x3;
-
- break;
- }
- }
-
- i915_dispatch_flip(dev, pf_planes, 1);
-}
-
-/**
* Emit blits for scheduled buffer swaps.
*
* This function will be called with the HW lock held.
@@ -148,59 +45,50 @@ i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw,
static void i915_vblank_tasklet(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long irqflags;
struct list_head *list, *tmp, hits, *hit;
- int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages;
- unsigned counter[2];
+ int nhits, nrects, slice[2], upper[2], lower[2], i;
+ unsigned counter[2] = { atomic_read(&dev->vbl_received),
+ atomic_read(&dev->vbl_received2) };
struct drm_drawable_info *drw;
drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
- u32 cpp = dev_priv->cpp, offsets[3];
+ u32 cpp = dev_priv->cpp;
u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |
XY_SRC_COPY_BLT_WRITE_ALPHA |
XY_SRC_COPY_BLT_WRITE_RGB)
: XY_SRC_COPY_BLT_CMD;
u32 src_pitch = sarea_priv->pitch * cpp;
u32 dst_pitch = sarea_priv->pitch * cpp;
- /* COPY rop (0xcc), map cpp to magic color depth constants */
u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24);
RING_LOCALS;
- if (sarea_priv->front_tiled) {
+ if (IS_I965G(dev) && sarea_priv->front_tiled) {
cmd |= XY_SRC_COPY_BLT_DST_TILED;
dst_pitch >>= 2;
}
- if (sarea_priv->back_tiled) {
+ if (IS_I965G(dev) && sarea_priv->back_tiled) {
cmd |= XY_SRC_COPY_BLT_SRC_TILED;
src_pitch >>= 2;
}
- counter[0] = drm_vblank_count(dev, 0);
- counter[1] = drm_vblank_count(dev, 1);
-
DRM_DEBUG("\n");
INIT_LIST_HEAD(&hits);
nhits = nrects = 0;
- /* No irqsave/restore necessary. This tasklet may be run in an
- * interrupt context or normal context, but we don't have to worry
- * about getting interrupted by something acquiring the lock, because
- * we are the interrupt context thing that acquires the lock.
- */
- spin_lock(&dev_priv->swaps_lock);
+ spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
/* Find buffer swaps scheduled for this vertical blank */
list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
drm_i915_vbl_swap_t *vbl_swap =
list_entry(list, drm_i915_vbl_swap_t, head);
- int pipe = i915_get_pipe(dev, vbl_swap->plane);
- if ((counter[pipe] - vbl_swap->sequence) > (1<<23))
+ if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23))
continue;
list_del(list);
dev_priv->swaps_pending--;
- drm_vblank_put(dev, pipe);
spin_unlock(&dev_priv->swaps_lock);
spin_lock(&dev->drw_lock);
@@ -238,23 +126,43 @@ static void i915_vblank_tasklet(struct drm_device *dev)
spin_lock(&dev_priv->swaps_lock);
}
- spin_unlock(&dev_priv->swaps_lock);
-
- if (nhits == 0)
+ if (nhits == 0) {
+ spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
return;
+ }
+
+ spin_unlock(&dev_priv->swaps_lock);
i915_kernel_lost_context(dev);
- upper[0] = upper[1] = 0;
- slice[0] = max(sarea_priv->planeA_h / nhits, 1);
- slice[1] = max(sarea_priv->planeB_h / nhits, 1);
- lower[0] = sarea_priv->planeA_y + slice[0];
- lower[1] = sarea_priv->planeB_y + slice[0];
+ if (IS_I965G(dev)) {
+ BEGIN_LP_RING(4);
+
+ OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
+ OUT_RING(0);
+ OUT_RING(((sarea_priv->width - 1) & 0xffff) | ((sarea_priv->height - 1) << 16));
+ OUT_RING(0);
+ ADVANCE_LP_RING();
+ } else {
+ BEGIN_LP_RING(6);
- offsets[0] = sarea_priv->front_offset;
- offsets[1] = sarea_priv->back_offset;
- offsets[2] = sarea_priv->third_offset;
- num_pages = sarea_priv->third_handle ? 3 : 2;
+ OUT_RING(GFX_OP_DRAWRECT_INFO);
+ OUT_RING(0);
+ OUT_RING(0);
+ OUT_RING(sarea_priv->width | sarea_priv->height << 16);
+ OUT_RING(sarea_priv->width | sarea_priv->height << 16);
+ OUT_RING(0);
+
+ ADVANCE_LP_RING();
+ }
+
+ sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT;
+
+ upper[0] = upper[1] = 0;
+ slice[0] = max(sarea_priv->pipeA_h / nhits, 1);
+ slice[1] = max(sarea_priv->pipeB_h / nhits, 1);
+ lower[0] = sarea_priv->pipeA_y + slice[0];
+ lower[1] = sarea_priv->pipeB_y + slice[0];
spin_lock(&dev->drw_lock);
@@ -266,8 +174,6 @@ static void i915_vblank_tasklet(struct drm_device *dev)
for (i = 0; i++ < nhits;
upper[0] = lower[0], lower[0] += slice[0],
upper[1] = lower[1], lower[1] += slice[1]) {
- int init_drawrect = 1;
-
if (i == nhits)
lower[0] = lower[1] = sarea_priv->height;
@@ -275,7 +181,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
drm_i915_vbl_swap_t *swap_hit =
list_entry(hit, drm_i915_vbl_swap_t, head);
struct drm_clip_rect *rect;
- int num_rects, plane, front, back;
+ int num_rects, pipe;
unsigned short top, bottom;
drw = drm_get_drawable_info(dev, swap_hit->drw_id);
@@ -283,50 +189,10 @@ static void i915_vblank_tasklet(struct drm_device *dev)
if (!drw)
continue;
- plane = swap_hit->plane;
-
- if (swap_hit->flip) {
- i915_dispatch_vsync_flip(dev, drw, plane);
- continue;
- }
-
- if (init_drawrect) {
- int width = sarea_priv->width;
- int height = sarea_priv->height;
- if (IS_I965G(dev)) {
- BEGIN_LP_RING(4);
-
- OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
- OUT_RING(0);
- OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16));
- OUT_RING(0);
-
- ADVANCE_LP_RING();
- } else {
- BEGIN_LP_RING(6);
-
- OUT_RING(GFX_OP_DRAWRECT_INFO);
- OUT_RING(0);
- OUT_RING(0);
- OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16));
- OUT_RING(0);
- OUT_RING(0);
-
- ADVANCE_LP_RING();
- }
-
- sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT;
-
- init_drawrect = 0;
- }
-
rect = drw->rects;
- top = upper[plane];
- bottom = lower[plane];
-
- front = (dev_priv->sarea_priv->pf_current_page >>
- (2 * plane)) & 0x3;
- back = (front + 1) % num_pages;
+ pipe = swap_hit->pipe;
+ top = upper[pipe];
+ bottom = lower[pipe];
for (num_rects = drw->num_rects; num_rects--; rect++) {
int y1 = max(rect->y1, top);
@@ -341,17 +207,17 @@ static void i915_vblank_tasklet(struct drm_device *dev)
OUT_RING(ropcpp | dst_pitch);
OUT_RING((y1 << 16) | rect->x1);
OUT_RING((y2 << 16) | rect->x2);
- OUT_RING(offsets[front]);
+ OUT_RING(sarea_priv->front_offset);
OUT_RING((y1 << 16) | rect->x1);
OUT_RING(src_pitch);
- OUT_RING(offsets[back]);
+ OUT_RING(sarea_priv->back_offset);
ADVANCE_LP_RING();
}
}
}
- spin_unlock(&dev->drw_lock);
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
list_for_each_safe(hit, tmp, &hits) {
drm_i915_vbl_swap_t *swap_hit =
@@ -363,112 +229,67 @@ static void i915_vblank_tasklet(struct drm_device *dev)
}
}
-u32 i915_get_vblank_counter(struct drm_device *dev, int plane)
-{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- unsigned long high_frame;
- unsigned long low_frame;
- u32 high1, high2, low, count;
- int pipe;
-
- pipe = i915_get_pipe(dev, plane);
- high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
- low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
-
- if (!i915_pipe_enabled(dev, pipe)) {
- printk(KERN_ERR "trying to get vblank count for disabled "
- "pipe %d\n", pipe);
- return 0;
- }
-
- /*
- * High & low register fields aren't synchronized, so make sure
- * we get a low value that's stable across two reads of the high
- * register.
- */
- do {
- high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
- PIPE_FRAME_HIGH_SHIFT);
- low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
- PIPE_FRAME_LOW_SHIFT);
- high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
- PIPE_FRAME_HIGH_SHIFT);
- } while (high1 != high2);
-
- count = (high1 << 8) | low;
-
- /* count may be reset by other driver(e.g. 2D driver),
- we have no way to know if it is wrapped or resetted
- when count is zero. do a rough guess.
- */
- if (count == 0 && dev->last_vblank[pipe] < dev->max_vblank_count/2)
- dev->last_vblank[pipe] = 0;
-
- return count;
-}
-
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u32 iir;
+ u16 temp;
u32 pipea_stats, pipeb_stats;
- int vblank = 0;
-
- iir = I915_READ(I915REG_INT_IDENTITY_R);
- if (iir == 0) {
- DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n",
- iir,
- I915_READ(I915REG_INT_MASK_R),
- I915_READ(I915REG_INT_ENABLE_R),
- I915_READ(I915REG_PIPEASTAT),
- I915_READ(I915REG_PIPEBSTAT));
- return IRQ_NONE;
- }
- /*
- * Clear the PIPE(A|B)STAT regs before the IIR otherwise
- * we may get extra interrupts.
- */
- if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) {
- pipea_stats = I915_READ(I915REG_PIPEASTAT);
- if (pipea_stats & (I915_START_VBLANK_INTERRUPT_STATUS|
- I915_VBLANK_INTERRUPT_STATUS))
- {
- vblank++;
- drm_handle_vblank(dev, i915_get_plane(dev, 0));
- }
- I915_WRITE(I915REG_PIPEASTAT, pipea_stats);
- }
- if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) {
- pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
- if (pipeb_stats & (I915_START_VBLANK_INTERRUPT_STATUS|
- I915_VBLANK_INTERRUPT_STATUS))
- {
- vblank++;
- drm_handle_vblank(dev, i915_get_plane(dev, 1));
- }
- I915_WRITE(I915REG_PIPEBSTAT, pipeb_stats);
- }
+ pipea_stats = I915_READ(I915REG_PIPEASTAT);
+ pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
- if (dev_priv->sarea_priv)
- dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+ temp = I915_READ16(I915REG_INT_IDENTITY_R);
- I915_WRITE(I915REG_INT_IDENTITY_R, iir);
- (void) I915_READ(I915REG_INT_IDENTITY_R); /* Flush posted write */
+ temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG);
- if (iir & I915_USER_INTERRUPT) {
+ DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
+
+ if (temp == 0)
+ return IRQ_NONE;
+
+ I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
+ (void) I915_READ16(I915REG_INT_IDENTITY_R);
+ DRM_READMEMORYBARRIER();
+
+ dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+
+ if (temp & USER_INT_FLAG)
DRM_WAKEUP(&dev_priv->irq_queue);
- }
- if (vblank) {
+
+ if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
+ int vblank_pipe = dev_priv->vblank_pipe;
+
+ if ((vblank_pipe &
+ (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
+ == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
+ if (temp & VSYNC_PIPEA_FLAG)
+ atomic_inc(&dev->vbl_received);
+ if (temp & VSYNC_PIPEB_FLAG)
+ atomic_inc(&dev->vbl_received2);
+ } else if (((temp & VSYNC_PIPEA_FLAG) &&
+ (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
+ ((temp & VSYNC_PIPEB_FLAG) &&
+ (vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
+ atomic_inc(&dev->vbl_received);
+
+ DRM_WAKEUP(&dev->vbl_queue);
+ drm_vbl_send_signals(dev);
+
if (dev_priv->swaps_pending > 0)
drm_locked_tasklet(dev, i915_vblank_tasklet);
+ I915_WRITE(I915REG_PIPEASTAT,
+ pipea_stats|I915_VBLANK_INTERRUPT_ENABLE|
+ I915_VBLANK_CLEAR);
+ I915_WRITE(I915REG_PIPEBSTAT,
+ pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE|
+ I915_VBLANK_CLEAR);
}
return IRQ_HANDLED;
}
-static int i915_emit_irq(struct drm_device *dev)
+static int i915_emit_irq(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -515,12 +336,42 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
}
- if (dev_priv->sarea_priv)
- dev_priv->sarea_priv->last_dispatch =
- READ_BREADCRUMB(dev_priv);
+ dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
return ret;
}
+static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence,
+ atomic_t *counter)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ unsigned int cur_vblank;
+ int ret = 0;
+
+ if (!dev_priv) {
+ DRM_ERROR("called with no initialization\n");
+ return -EINVAL;
+ }
+
+ DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
+ (((cur_vblank = atomic_read(counter))
+ - *sequence) <= (1<<23)));
+
+ *sequence = cur_vblank;
+
+ return ret;
+}
+
+
+int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
+{
+ return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
+}
+
+int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
+{
+ return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2);
+}
+
/* Needs the lock as it touches the ring.
*/
int i915_irq_emit(struct drm_device *dev, void *data,
@@ -563,96 +414,18 @@ int i915_irq_wait(struct drm_device *dev, void *data,
return i915_wait_irq(dev, irqwait->irq_seq);
}
-int i915_enable_vblank(struct drm_device *dev, int plane)
-{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- int pipe = i915_get_pipe(dev, plane);
- u32 pipestat_reg = 0;
- u32 pipestat;
-
- switch (pipe) {
- case 0:
- pipestat_reg = I915REG_PIPEASTAT;
- dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
- break;
- case 1:
- pipestat_reg = I915REG_PIPEBSTAT;
- dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
- break;
- default:
- DRM_ERROR("tried to enable vblank on non-existent pipe %d\n",
- pipe);
- break;
- }
-
- if (pipestat_reg)
- {
- pipestat = I915_READ (pipestat_reg);
- /*
- * Older chips didn't have the start vblank interrupt,
- * but
- */
- if (IS_I965G (dev))
- pipestat |= I915_START_VBLANK_INTERRUPT_ENABLE;
- else
- pipestat |= I915_VBLANK_INTERRUPT_ENABLE;
- /*
- * Clear any pending status
- */
- pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS |
- I915_VBLANK_INTERRUPT_STATUS);
- I915_WRITE(pipestat_reg, pipestat);
- }
- I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
-
- return 0;
-}
-
-void i915_disable_vblank(struct drm_device *dev, int plane)
-{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- int pipe = i915_get_pipe(dev, plane);
- u32 pipestat_reg = 0;
- u32 pipestat;
-
- switch (pipe) {
- case 0:
- pipestat_reg = I915REG_PIPEASTAT;
- dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
- break;
- case 1:
- pipestat_reg = I915REG_PIPEBSTAT;
- dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
- break;
- default:
- DRM_ERROR("tried to disable vblank on non-existent pipe %d\n",
- pipe);
- break;
- }
-
- I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
- if (pipestat_reg)
- {
- pipestat = I915_READ (pipestat_reg);
- pipestat &= ~(I915_START_VBLANK_INTERRUPT_ENABLE |
- I915_VBLANK_INTERRUPT_ENABLE);
- /*
- * Clear any pending status
- */
- pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS |
- I915_VBLANK_INTERRUPT_STATUS);
- I915_WRITE(pipestat_reg, pipestat);
- }
-}
-
static void i915_enable_interrupt (struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u16 flag;
- dev_priv->irq_enable_reg |= I915_USER_INTERRUPT;
+ flag = 0;
+ if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
+ flag |= VSYNC_PIPEA_FLAG;
+ if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
+ flag |= VSYNC_PIPEB_FLAG;
- I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
- dev_priv->irq_enabled = 1;
+ I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag);
}
/* Set the vblank monitor pipe
@@ -675,6 +448,8 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data,
dev_priv->vblank_pipe = pipe->pipe;
+ i915_enable_interrupt (dev);
+
return 0;
}
@@ -692,9 +467,9 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data,
flag = I915_READ(I915REG_INT_ENABLE_R);
pipe->pipe = 0;
- if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT)
+ if (flag & VSYNC_PIPEA_FLAG)
pipe->pipe |= DRM_I915_VBLANK_PIPE_A;
- if (flag & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
+ if (flag & VSYNC_PIPEB_FLAG)
pipe->pipe |= DRM_I915_VBLANK_PIPE_B;
return 0;
@@ -709,30 +484,27 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_vblank_swap_t *swap = data;
drm_i915_vbl_swap_t *vbl_swap;
- unsigned int pipe, seqtype, curseq, plane;
+ unsigned int pipe, seqtype, curseq;
unsigned long irqflags;
struct list_head *list;
- int ret;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __func__);
return -EINVAL;
}
- if (!dev_priv->sarea_priv || dev_priv->sarea_priv->rotation) {
+ if (dev_priv->sarea_priv->rotation) {
DRM_DEBUG("Rotation not supported\n");
return -EINVAL;
}
if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
- _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS |
- _DRM_VBLANK_FLIP)) {
+ _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) {
DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype);
return -EINVAL;
}
- plane = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
- pipe = i915_get_pipe(dev, plane);
+ pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
@@ -743,11 +515,6 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
spin_lock_irqsave(&dev->drw_lock, irqflags);
- /* It makes no sense to schedule a swap for a drawable that doesn't have
- * valid information at this point. E.g. this could mean that the X
- * server is too old to push drawable information to the DRM, in which
- * case all such swaps would become ineffective.
- */
if (!drm_get_drawable_info(dev, swap->drawable)) {
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable);
@@ -756,8 +523,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
- drm_update_vblank_count(dev, pipe);
- curseq = drm_vblank_count(dev, pipe);
+ curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
if (seqtype == _DRM_VBLANK_RELATIVE)
swap->sequence += curseq;
@@ -771,43 +537,14 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
}
}
- if (swap->seqtype & _DRM_VBLANK_FLIP) {
- swap->sequence--;
-
- if ((curseq - swap->sequence) <= (1<<23)) {
- struct drm_drawable_info *drw;
-
- LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- spin_lock_irqsave(&dev->drw_lock, irqflags);
-
- drw = drm_get_drawable_info(dev, swap->drawable);
-
- if (!drw) {
- spin_unlock_irqrestore(&dev->drw_lock,
- irqflags);
- DRM_DEBUG("Invalid drawable ID %d\n",
- swap->drawable);
- return -EINVAL;
- }
-
- i915_dispatch_vsync_flip(dev, drw, plane);
-
- spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-
- return 0;
- }
- }
-
spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
list_for_each(list, &dev_priv->vbl_swaps.head) {
vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
if (vbl_swap->drw_id == swap->drawable &&
- vbl_swap->plane == plane &&
+ vbl_swap->pipe == pipe &&
vbl_swap->sequence == swap->sequence) {
- vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP);
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
DRM_DEBUG("Already scheduled\n");
return 0;
@@ -830,19 +567,9 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
DRM_DEBUG("\n");
- ret = drm_vblank_get(dev, pipe);
- if (ret) {
- drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
- return ret;
- }
-
vbl_swap->drw_id = swap->drawable;
- vbl_swap->plane = plane;
+ vbl_swap->pipe = pipe;
vbl_swap->sequence = swap->sequence;
- vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP);
-
- if (vbl_swap->flip)
- swap->sequence++;
spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
@@ -860,57 +587,37 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- I915_WRITE16(I915REG_HWSTAM, 0xeffe);
+ I915_WRITE16(I915REG_HWSTAM, 0xfffe);
I915_WRITE16(I915REG_INT_MASK_R, 0x0);
I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
}
-int i915_driver_irq_postinstall(struct drm_device * dev)
+void i915_driver_irq_postinstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- int ret, num_pipes = 2;
spin_lock_init(&dev_priv->swaps_lock);
INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
dev_priv->swaps_pending = 0;
- dev_priv->user_irq_refcount = 0;
- dev_priv->irq_enable_reg = 0;
-
- ret = drm_vblank_init(dev, num_pipes);
- if (ret)
- return ret;
-
- dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
-
+ if (!dev_priv->vblank_pipe)
+ dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
i915_enable_interrupt(dev);
DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
-
- /*
- * Initialize the hardware status page IRQ location.
- */
-
- I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21));
- return 0;
}
void i915_driver_irq_uninstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u32 temp;
+ u16 temp;
if (!dev_priv)
return;
- dev_priv->irq_enabled = 0;
- I915_WRITE(I915REG_HWSTAM, 0xffffffff);
- I915_WRITE(I915REG_INT_MASK_R, 0xffffffff);
- I915_WRITE(I915REG_INT_ENABLE_R, 0x0);
-
- temp = I915_READ(I915REG_PIPEASTAT);
- I915_WRITE(I915REG_PIPEASTAT, temp);
- temp = I915_READ(I915REG_PIPEBSTAT);
- I915_WRITE(I915REG_PIPEBSTAT, temp);
- temp = I915_READ(I915REG_INT_IDENTITY_R);
- I915_WRITE(I915REG_INT_IDENTITY_R, temp);
+ I915_WRITE16(I915REG_HWSTAM, 0xffff);
+ I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
+ I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
+
+ temp = I915_READ16(I915REG_INT_IDENTITY_R);
+ I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
}
diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c
index 6b3790939e76..5572939fc7d1 100644
--- a/drivers/char/drm/mga_drv.c
+++ b/drivers/char/drm/mga_drv.c
@@ -45,16 +45,15 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA |
- DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
+ DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
+ DRIVER_IRQ_VBL,
.dev_priv_size = sizeof(drm_mga_buf_priv_t),
.load = mga_driver_load,
.unload = mga_driver_unload,
.lastclose = mga_driver_lastclose,
.dma_quiescent = mga_driver_dma_quiescent,
.device_is_agp = mga_driver_device_is_agp,
- .get_vblank_counter = mga_get_vblank_counter,
- .enable_vblank = mga_enable_vblank,
- .disable_vblank = mga_disable_vblank,
+ .vblank_wait = mga_driver_vblank_wait,
.irq_preinstall = mga_driver_irq_preinstall,
.irq_postinstall = mga_driver_irq_postinstall,
.irq_uninstall = mga_driver_irq_uninstall,
diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h
index 8f7291f36363..f6ebd24bd587 100644
--- a/drivers/char/drm/mga_drv.h
+++ b/drivers/char/drm/mga_drv.h
@@ -120,7 +120,6 @@ typedef struct drm_mga_private {
u32 clear_cmd;
u32 maccess;
- atomic_t vbl_received; /**< Number of vblanks received. */
wait_queue_head_t fence_queue;
atomic_t last_fence_retired;
u32 next_fence_to_post;
@@ -182,14 +181,11 @@ extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv);
extern int mga_warp_init(drm_mga_private_t * dev_priv);
/* mga_irq.c */
-extern int mga_enable_vblank(struct drm_device *dev, int crtc);
-extern void mga_disable_vblank(struct drm_device *dev, int crtc);
-extern u32 mga_get_vblank_counter(struct drm_device *dev, int crtc);
extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence);
extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
extern void mga_driver_irq_preinstall(struct drm_device * dev);
-extern int mga_driver_irq_postinstall(struct drm_device * dev);
+extern void mga_driver_irq_postinstall(struct drm_device * dev);
extern void mga_driver_irq_uninstall(struct drm_device * dev);
extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
diff --git a/drivers/char/drm/mga_irq.c b/drivers/char/drm/mga_irq.c
index 06852fb4b278..9302cb8f0f83 100644
--- a/drivers/char/drm/mga_irq.c
+++ b/drivers/char/drm/mga_irq.c
@@ -35,20 +35,6 @@
#include "mga_drm.h"
#include "mga_drv.h"
-u32 mga_get_vblank_counter(struct drm_device *dev, int crtc)
-{
- const drm_mga_private_t *const dev_priv =
- (drm_mga_private_t *) dev->dev_private;
-
- if (crtc != 0) {
- return 0;
- }
-
-
- return atomic_read(&dev_priv->vbl_received);
-}
-
-
irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
@@ -61,8 +47,9 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
/* VBLANK interrupt */
if (status & MGA_VLINEPEN) {
MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR);
- atomic_inc(&dev_priv->vbl_received);
- drm_handle_vblank(dev, 0);
+ atomic_inc(&dev->vbl_received);
+ DRM_WAKEUP(&dev->vbl_queue);
+ drm_vbl_send_signals(dev);
handled = 1;
}
@@ -91,34 +78,22 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
return IRQ_NONE;
}
-int mga_enable_vblank(struct drm_device *dev, int crtc)
+int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
{
- drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
-
- if (crtc != 0) {
- DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
- crtc);
- return 0;
- }
-
- MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
- return 0;
-}
+ unsigned int cur_vblank;
+ int ret = 0;
+ /* Assume that the user has missed the current sequence number
+ * by about a day rather than she wants to wait for years
+ * using vertical blanks...
+ */
+ DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
+ (((cur_vblank = atomic_read(&dev->vbl_received))
+ - *sequence) <= (1 << 23)));
-void mga_disable_vblank(struct drm_device *dev, int crtc)
-{
- if (crtc != 0) {
- DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
- crtc);
- }
+ *sequence = cur_vblank;
- /* Do *NOT* disable the vertical refresh interrupt. MGA doesn't have
- * a nice hardware counter that tracks the number of refreshes when
- * the interrupt is disabled, and the kernel doesn't know the refresh
- * rate to calculate an estimate.
- */
- /* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */
+ return ret;
}
int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence)
@@ -150,22 +125,14 @@ void mga_driver_irq_preinstall(struct drm_device * dev)
MGA_WRITE(MGA_ICLEAR, ~0);
}
-int mga_driver_irq_postinstall(struct drm_device * dev)
+void mga_driver_irq_postinstall(struct drm_device * dev)
{
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
- int ret;
-
- ret = drm_vblank_init(dev, 1);
- if (ret)
- return ret;
DRM_INIT_WAITQUEUE(&dev_priv->fence_queue);
- /* Turn on soft trap interrupt. Vertical blank interrupts are enabled
- * in mga_enable_vblank.
- */
- MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN);
- return 0;
+ /* Turn on vertical blank interrupt and soft trap interrupt. */
+ MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
}
void mga_driver_irq_uninstall(struct drm_device * dev)
diff --git a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c
index 2888aa01ebc7..6108e7587e12 100644
--- a/drivers/char/drm/r128_drv.c
+++ b/drivers/char/drm/r128_drv.c
@@ -43,13 +43,12 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
- DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
+ DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
+ DRIVER_IRQ_VBL,
.dev_priv_size = sizeof(drm_r128_buf_priv_t),
.preclose = r128_driver_preclose,
.lastclose = r128_driver_lastclose,
- .get_vblank_counter = r128_get_vblank_counter,
- .enable_vblank = r128_enable_vblank,
- .disable_vblank = r128_disable_vblank,
+ .vblank_wait = r128_driver_vblank_wait,
.irq_preinstall = r128_driver_irq_preinstall,
.irq_postinstall = r128_driver_irq_postinstall,
.irq_uninstall = r128_driver_irq_uninstall,
diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h
index 80af9e09e75d..011105e51ac6 100644
--- a/drivers/char/drm/r128_drv.h
+++ b/drivers/char/drm/r128_drv.h
@@ -97,8 +97,6 @@ typedef struct drm_r128_private {
u32 crtc_offset;
u32 crtc_offset_cntl;
- atomic_t vbl_received;
-
u32 color_fmt;
unsigned int front_offset;
unsigned int front_pitch;
@@ -151,12 +149,11 @@ extern int r128_wait_ring(drm_r128_private_t * dev_priv, int n);
extern int r128_do_cce_idle(drm_r128_private_t * dev_priv);
extern int r128_do_cleanup_cce(struct drm_device * dev);
-extern int r128_enable_vblank(struct drm_device *dev, int crtc);
-extern void r128_disable_vblank(struct drm_device *dev, int crtc);
-extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc);
+extern int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
+
extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS);
extern void r128_driver_irq_preinstall(struct drm_device * dev);
-extern int r128_driver_irq_postinstall(struct drm_device * dev);
+extern void r128_driver_irq_postinstall(struct drm_device * dev);
extern void r128_driver_irq_uninstall(struct drm_device * dev);
extern void r128_driver_lastclose(struct drm_device * dev);
extern void r128_driver_preclose(struct drm_device * dev,
diff --git a/drivers/char/drm/r128_irq.c b/drivers/char/drm/r128_irq.c
index 5b95bd898f95..c76fdca7662d 100644
--- a/drivers/char/drm/r128_irq.c
+++ b/drivers/char/drm/r128_irq.c
@@ -35,16 +35,6 @@
#include "r128_drm.h"
#include "r128_drv.h"
-u32 r128_get_vblank_counter(struct drm_device *dev, int crtc)
-{
- const drm_r128_private_t *dev_priv = dev->dev_private;
-
- if (crtc != 0)
- return 0;
-
- return atomic_read(&dev_priv->vbl_received);
-}
-
irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
@@ -56,38 +46,30 @@ irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
/* VBLANK interrupt */
if (status & R128_CRTC_VBLANK_INT) {
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
- atomic_inc(&dev_priv->vbl_received);
- drm_handle_vblank(dev, 0);
+ atomic_inc(&dev->vbl_received);
+ DRM_WAKEUP(&dev->vbl_queue);
+ drm_vbl_send_signals(dev);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
-int r128_enable_vblank(struct drm_device *dev, int crtc)
+int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
{
- drm_r128_private_t *dev_priv = dev->dev_private;
-
- if (crtc != 0) {
- DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc);
- return -EINVAL;
- }
+ unsigned int cur_vblank;
+ int ret = 0;
- R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
- return 0;
-}
+ /* Assume that the user has missed the current sequence number
+ * by about a day rather than she wants to wait for years
+ * using vertical blanks...
+ */
+ DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
+ (((cur_vblank = atomic_read(&dev->vbl_received))
+ - *sequence) <= (1 << 23)));
-void r128_disable_vblank(struct drm_device *dev, int crtc)
-{
- if (crtc != 0)
- DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc);
+ *sequence = cur_vblank;
- /*
- * FIXME: implement proper interrupt disable by using the vblank
- * counter register (if available)
- *
- * R128_WRITE(R128_GEN_INT_CNTL,
- * R128_READ(R128_GEN_INT_CNTL) & ~R128_CRTC_VBLANK_INT_EN);
- */
+ return ret;
}
void r128_driver_irq_preinstall(struct drm_device * dev)
@@ -100,9 +82,12 @@ void r128_driver_irq_preinstall(struct drm_device * dev)
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
}
-int r128_driver_irq_postinstall(struct drm_device * dev)
+void r128_driver_irq_postinstall(struct drm_device * dev)
{
- return drm_vblank_init(dev, 1);
+ drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
+
+ /* Turn on VBL interrupt */
+ R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
}
void r128_driver_irq_uninstall(struct drm_device * dev)
diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c
index f535812e4057..702df45320f7 100644
--- a/drivers/char/drm/r300_cmdbuf.c
+++ b/drivers/char/drm/r300_cmdbuf.c
@@ -189,18 +189,12 @@ void r300_init_reg_flags(struct drm_device *dev)
ADD_RANGE(R300_RE_CULL_CNTL, 1);
ADD_RANGE(0x42C0, 2);
ADD_RANGE(R300_RS_CNTL_0, 2);
- ADD_RANGE(R300_RS_INTERP_0, 8);
- ADD_RANGE(R300_RS_ROUTE_0, 8);
- ADD_RANGE(0x43A4, 2);
+
+ ADD_RANGE(R300_SC_HYPERZ, 2);
ADD_RANGE(0x43E8, 1);
- ADD_RANGE(R300_PFS_CNTL_0, 3);
- ADD_RANGE(R300_PFS_NODE_0, 4);
- ADD_RANGE(R300_PFS_TEXI_0, 64);
+
ADD_RANGE(0x46A4, 5);
- ADD_RANGE(R300_PFS_INSTR0_0, 64);
- ADD_RANGE(R300_PFS_INSTR1_0, 64);
- ADD_RANGE(R300_PFS_INSTR2_0, 64);
- ADD_RANGE(R300_PFS_INSTR3_0, 64);
+
ADD_RANGE(R300_RE_FOG_STATE, 1);
ADD_RANGE(R300_FOG_COLOR_R, 3);
ADD_RANGE(R300_PP_ALPHA_TEST, 2);
@@ -215,14 +209,12 @@ void r300_init_reg_flags(struct drm_device *dev)
ADD_RANGE(0x4E50, 9);
ADD_RANGE(0x4E88, 1);
ADD_RANGE(0x4EA0, 2);
- ADD_RANGE(R300_RB3D_ZSTENCIL_CNTL_0, 3);
- ADD_RANGE(R300_RB3D_ZSTENCIL_FORMAT, 4);
- ADD_RANGE_MARK(R300_RB3D_DEPTHOFFSET, 1, MARK_CHECK_OFFSET); /* check offset */
- ADD_RANGE(R300_RB3D_DEPTHPITCH, 1);
- ADD_RANGE(0x4F28, 1);
- ADD_RANGE(0x4F30, 2);
- ADD_RANGE(0x4F44, 1);
- ADD_RANGE(0x4F54, 1);
+ ADD_RANGE(R300_ZB_CNTL, 3);
+ ADD_RANGE(R300_ZB_FORMAT, 4);
+ ADD_RANGE_MARK(R300_ZB_DEPTHOFFSET, 1, MARK_CHECK_OFFSET); /* check offset */
+ ADD_RANGE(R300_ZB_DEPTHPITCH, 1);
+ ADD_RANGE(R300_ZB_DEPTHCLEARVALUE, 1);
+ ADD_RANGE(R300_ZB_ZMASK_OFFSET, 13);
ADD_RANGE(R300_TX_FILTER_0, 16);
ADD_RANGE(R300_TX_FILTER1_0, 16);
@@ -235,13 +227,32 @@ void r300_init_reg_flags(struct drm_device *dev)
ADD_RANGE(R300_TX_BORDER_COLOR_0, 16);
/* Sporadic registers used as primitives are emitted */
- ADD_RANGE(R300_RB3D_ZCACHE_CTLSTAT, 1);
+ ADD_RANGE(R300_ZB_ZCACHE_CTLSTAT, 1);
ADD_RANGE(R300_RB3D_DSTCACHE_CTLSTAT, 1);
ADD_RANGE(R300_VAP_INPUT_ROUTE_0_0, 8);
ADD_RANGE(R300_VAP_INPUT_ROUTE_1_0, 8);
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) {
- ADD_RANGE(0x4074, 16);
+ ADD_RANGE(R500_VAP_INDEX_OFFSET, 1);
+ ADD_RANGE(R500_US_CONFIG, 2);
+ ADD_RANGE(R500_US_CODE_ADDR, 3);
+ ADD_RANGE(R500_US_FC_CTRL, 1);
+ ADD_RANGE(R500_RS_IP_0, 16);
+ ADD_RANGE(R500_RS_INST_0, 16);
+ ADD_RANGE(R500_RB3D_COLOR_CLEAR_VALUE_AR, 2);
+ ADD_RANGE(R500_RB3D_CONSTANT_COLOR_AR, 2);
+ ADD_RANGE(R500_ZB_FIFO_SIZE, 2);
+ } else {
+ ADD_RANGE(R300_PFS_CNTL_0, 3);
+ ADD_RANGE(R300_PFS_NODE_0, 4);
+ ADD_RANGE(R300_PFS_TEXI_0, 64);
+ ADD_RANGE(R300_PFS_INSTR0_0, 64);
+ ADD_RANGE(R300_PFS_INSTR1_0, 64);
+ ADD_RANGE(R300_PFS_INSTR2_0, 64);
+ ADD_RANGE(R300_PFS_INSTR3_0, 64);
+ ADD_RANGE(R300_RS_INTERP_0, 8);
+ ADD_RANGE(R300_RS_ROUTE_0, 8);
+
}
}
@@ -707,8 +718,9 @@ static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv)
BEGIN_RING(6);
OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
OUT_RING(R300_RB3D_DSTCACHE_UNKNOWN_0A);
- OUT_RING(CP_PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0));
- OUT_RING(R300_RB3D_ZCACHE_UNKNOWN_03);
+ OUT_RING(CP_PACKET0(R300_ZB_ZCACHE_CTLSTAT, 0));
+ OUT_RING(R300_ZB_ZCACHE_CTLSTAT_ZC_FLUSH_FLUSH_AND_FREE|
+ R300_ZB_ZCACHE_CTLSTAT_ZC_FREE_FREE);
OUT_RING(CP_PACKET3(RADEON_CP_NOP, 0));
OUT_RING(0x0);
ADVANCE_RING();
@@ -829,6 +841,54 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
}
/**
+ * Uploads user-supplied vertex program instructions or parameters onto
+ * the graphics card.
+ * Called by r300_do_cp_cmdbuf.
+ */
+static inline int r300_emit_r500fp(drm_radeon_private_t *dev_priv,
+ drm_radeon_kcmd_buffer_t *cmdbuf,
+ drm_r300_cmd_header_t header)
+{
+ int sz;
+ int addr;
+ int type;
+ int clamp;
+ int stride;
+ RING_LOCALS;
+
+ sz = header.r500fp.count;
+ /* address is 9 bits 0 - 8, bit 1 of flags is part of address */
+ addr = ((header.r500fp.adrhi_flags & 1) << 8) | header.r500fp.adrlo;
+
+ type = !!(header.r500fp.adrhi_flags & R500FP_CONSTANT_TYPE);
+ clamp = !!(header.r500fp.adrhi_flags & R500FP_CONSTANT_CLAMP);
+
+ addr |= (type << 16);
+ addr |= (clamp << 17);
+
+ stride = type ? 4 : 6;
+
+ DRM_DEBUG("r500fp %d %d type: %d\n", sz, addr, type);
+ if (!sz)
+ return 0;
+ if (sz * stride * 4 > cmdbuf->bufsz)
+ return -EINVAL;
+
+ BEGIN_RING(3 + sz * stride);
+ OUT_RING_REG(R500_GA_US_VECTOR_INDEX, addr);
+ OUT_RING(CP_PACKET0_TABLE(R500_GA_US_VECTOR_DATA, sz * stride - 1));
+ OUT_RING_TABLE((int *)cmdbuf->buf, sz * stride);
+
+ ADVANCE_RING();
+
+ cmdbuf->buf += sz * stride * 4;
+ cmdbuf->bufsz -= sz * stride * 4;
+
+ return 0;
+}
+
+
+/**
* Parses and validates a user-supplied command buffer and emits appropriate
* commands on the DMA ring buffer.
* Called by the ioctl handler function radeon_cp_cmdbuf.
@@ -963,6 +1023,19 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
}
break;
+ case R300_CMD_R500FP:
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_RV515) {
+ DRM_ERROR("Calling r500 command on r300 card\n");
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ DRM_DEBUG("R300_CMD_R500FP\n");
+ ret = r300_emit_r500fp(dev_priv, cmdbuf, header);
+ if (ret) {
+ DRM_ERROR("r300_emit_r500fp failed\n");
+ goto cleanup;
+ }
+ break;
default:
DRM_ERROR("bad cmd_type %i at %p\n",
header.header.cmd_type,
diff --git a/drivers/char/drm/r300_reg.h b/drivers/char/drm/r300_reg.h
index 8f664af9c4a4..a6802f26afc4 100644
--- a/drivers/char/drm/r300_reg.h
+++ b/drivers/char/drm/r300_reg.h
@@ -702,6 +702,27 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
# define R300_RS_ROUTE_1_UNKNOWN11 (1 << 11)
/* END: Rasterization / Interpolators - many guesses */
+/* Hierarchical Z Enable */
+#define R300_SC_HYPERZ 0x43a4
+# define R300_SC_HYPERZ_DISABLE (0 << 0)
+# define R300_SC_HYPERZ_ENABLE (1 << 0)
+# define R300_SC_HYPERZ_MIN (0 << 1)
+# define R300_SC_HYPERZ_MAX (1 << 1)
+# define R300_SC_HYPERZ_ADJ_256 (0 << 2)
+# define R300_SC_HYPERZ_ADJ_128 (1 << 2)
+# define R300_SC_HYPERZ_ADJ_64 (2 << 2)
+# define R300_SC_HYPERZ_ADJ_32 (3 << 2)
+# define R300_SC_HYPERZ_ADJ_16 (4 << 2)
+# define R300_SC_HYPERZ_ADJ_8 (5 << 2)
+# define R300_SC_HYPERZ_ADJ_4 (6 << 2)
+# define R300_SC_HYPERZ_ADJ_2 (7 << 2)
+# define R300_SC_HYPERZ_HZ_Z0MIN_NO (0 << 5)
+# define R300_SC_HYPERZ_HZ_Z0MIN (1 << 5)
+# define R300_SC_HYPERZ_HZ_Z0MAX_NO (0 << 6)
+# define R300_SC_HYPERZ_HZ_Z0MAX (1 << 6)
+
+#define R300_SC_EDGERULE 0x43a8
+
/* BEGIN: Scissors and cliprects */
/* There are four clipping rectangles. Their corner coordinates are inclusive.
@@ -1346,7 +1367,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
/* Guess by Vladimir.
* Set to 0A before 3D operations, set to 02 afterwards.
*/
-#define R300_RB3D_DSTCACHE_CTLSTAT 0x4E4C
+/*#define R300_RB3D_DSTCACHE_CTLSTAT 0x4E4C*/
# define R300_RB3D_DSTCACHE_UNKNOWN_02 0x00000002
# define R300_RB3D_DSTCACHE_UNKNOWN_0A 0x0000000A
@@ -1355,19 +1376,14 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
* for this.
* Bit (1<<8) is the "test" bit. so plain write is 6 - vd
*/
-#define R300_RB3D_ZSTENCIL_CNTL_0 0x4F00
-# define R300_RB3D_Z_DISABLED_1 0x00000010
-# define R300_RB3D_Z_DISABLED_2 0x00000014
-# define R300_RB3D_Z_TEST 0x00000012
-# define R300_RB3D_Z_TEST_AND_WRITE 0x00000016
-# define R300_RB3D_Z_WRITE_ONLY 0x00000006
-
-# define R300_RB3D_Z_TEST 0x00000012
-# define R300_RB3D_Z_TEST_AND_WRITE 0x00000016
-# define R300_RB3D_Z_WRITE_ONLY 0x00000006
-# define R300_RB3D_STENCIL_ENABLE 0x00000001
-
-#define R300_RB3D_ZSTENCIL_CNTL_1 0x4F04
+#define R300_ZB_CNTL 0x4F00
+# define R300_STENCIL_ENABLE (1 << 0)
+# define R300_Z_ENABLE (1 << 1)
+# define R300_Z_WRITE_ENABLE (1 << 2)
+# define R300_Z_SIGNED_COMPARE (1 << 3)
+# define R300_STENCIL_FRONT_BACK (1 << 4)
+
+#define R300_ZB_ZSTENCILCNTL 0x4f04
/* functions */
# define R300_ZS_NEVER 0
# define R300_ZS_LESS 1
@@ -1387,52 +1403,166 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
# define R300_ZS_INVERT 5
# define R300_ZS_INCR_WRAP 6
# define R300_ZS_DECR_WRAP 7
+# define R300_Z_FUNC_SHIFT 0
/* front and back refer to operations done for front
and back faces, i.e. separate stencil function support */
-# define R300_RB3D_ZS1_DEPTH_FUNC_SHIFT 0
-# define R300_RB3D_ZS1_FRONT_FUNC_SHIFT 3
-# define R300_RB3D_ZS1_FRONT_FAIL_OP_SHIFT 6
-# define R300_RB3D_ZS1_FRONT_ZPASS_OP_SHIFT 9
-# define R300_RB3D_ZS1_FRONT_ZFAIL_OP_SHIFT 12
-# define R300_RB3D_ZS1_BACK_FUNC_SHIFT 15
-# define R300_RB3D_ZS1_BACK_FAIL_OP_SHIFT 18
-# define R300_RB3D_ZS1_BACK_ZPASS_OP_SHIFT 21
-# define R300_RB3D_ZS1_BACK_ZFAIL_OP_SHIFT 24
-
-#define R300_RB3D_ZSTENCIL_CNTL_2 0x4F08
-# define R300_RB3D_ZS2_STENCIL_REF_SHIFT 0
-# define R300_RB3D_ZS2_STENCIL_MASK 0xFF
-# define R300_RB3D_ZS2_STENCIL_MASK_SHIFT 8
-# define R300_RB3D_ZS2_STENCIL_WRITE_MASK_SHIFT 16
+# define R300_S_FRONT_FUNC_SHIFT 3
+# define R300_S_FRONT_SFAIL_OP_SHIFT 6
+# define R300_S_FRONT_ZPASS_OP_SHIFT 9
+# define R300_S_FRONT_ZFAIL_OP_SHIFT 12
+# define R300_S_BACK_FUNC_SHIFT 15
+# define R300_S_BACK_SFAIL_OP_SHIFT 18
+# define R300_S_BACK_ZPASS_OP_SHIFT 21
+# define R300_S_BACK_ZFAIL_OP_SHIFT 24
+
+#define R300_ZB_STENCILREFMASK 0x4f08
+# define R300_STENCILREF_SHIFT 0
+# define R300_STENCILREF_MASK 0x000000ff
+# define R300_STENCILMASK_SHIFT 8
+# define R300_STENCILMASK_MASK 0x0000ff00
+# define R300_STENCILWRITEMASK_SHIFT 16
+# define R300_STENCILWRITEMASK_MASK 0x00ff0000
/* gap */
-#define R300_RB3D_ZSTENCIL_FORMAT 0x4F10
-# define R300_DEPTH_FORMAT_16BIT_INT_Z (0 << 0)
-# define R300_DEPTH_FORMAT_24BIT_INT_Z (2 << 0)
- /* 16 bit format or some aditional bit ? */
-# define R300_DEPTH_FORMAT_UNK32 (32 << 0)
+#define R300_ZB_FORMAT 0x4f10
+# define R300_DEPTHFORMAT_16BIT_INT_Z (0 << 0)
+# define R300_DEPTHFORMAT_16BIT_13E3 (1 << 0)
+# define R300_DEPTHFORMAT_24BIT_INT_Z_8BIT_STENCIL (2 << 0)
+/* reserved up to (15 << 0) */
+# define R300_INVERT_13E3_LEADING_ONES (0 << 4)
+# define R300_INVERT_13E3_LEADING_ZEROS (1 << 4)
-#define R300_RB3D_EARLY_Z 0x4F14
-# define R300_EARLY_Z_DISABLE (0 << 0)
-# define R300_EARLY_Z_ENABLE (1 << 0)
+#define R300_ZB_ZTOP 0x4F14
+# define R300_ZTOP_DISABLE (0 << 0)
+# define R300_ZTOP_ENABLE (1 << 0)
/* gap */
-#define R300_RB3D_ZCACHE_CTLSTAT 0x4F18 /* GUESS */
-# define R300_RB3D_ZCACHE_UNKNOWN_01 0x1
-# define R300_RB3D_ZCACHE_UNKNOWN_03 0x3
+#define R300_ZB_ZCACHE_CTLSTAT 0x4f18
+# define R300_ZB_ZCACHE_CTLSTAT_ZC_FLUSH_NO_EFFECT (0 << 0)
+# define R300_ZB_ZCACHE_CTLSTAT_ZC_FLUSH_FLUSH_AND_FREE (1 << 0)
+# define R300_ZB_ZCACHE_CTLSTAT_ZC_FREE_NO_EFFECT (0 << 1)
+# define R300_ZB_ZCACHE_CTLSTAT_ZC_FREE_FREE (1 << 1)
+# define R300_ZB_ZCACHE_CTLSTAT_ZC_BUSY_IDLE (0 << 31)
+# define R300_ZB_ZCACHE_CTLSTAT_ZC_BUSY_BUSY (1 << 31)
+
+#define R300_ZB_BW_CNTL 0x4f1c
+# define R300_HIZ_DISABLE (0 << 0)
+# define R300_HIZ_ENABLE (1 << 0)
+# define R300_HIZ_MIN (0 << 1)
+# define R300_HIZ_MAX (1 << 1)
+# define R300_FAST_FILL_DISABLE (0 << 2)
+# define R300_FAST_FILL_ENABLE (1 << 2)
+# define R300_RD_COMP_DISABLE (0 << 3)
+# define R300_RD_COMP_ENABLE (1 << 3)
+# define R300_WR_COMP_DISABLE (0 << 4)
+# define R300_WR_COMP_ENABLE (1 << 4)
+# define R300_ZB_CB_CLEAR_RMW (0 << 5)
+# define R300_ZB_CB_CLEAR_CACHE_LINEAR (1 << 5)
+# define R300_FORCE_COMPRESSED_STENCIL_VALUE_DISABLE (0 << 6)
+# define R300_FORCE_COMPRESSED_STENCIL_VALUE_ENABLE (1 << 6)
+
+# define R500_ZEQUAL_OPTIMIZE_ENABLE (0 << 7)
+# define R500_ZEQUAL_OPTIMIZE_DISABLE (1 << 7)
+# define R500_SEQUAL_OPTIMIZE_ENABLE (0 << 8)
+# define R500_SEQUAL_OPTIMIZE_DISABLE (1 << 8)
+
+# define R500_BMASK_ENABLE (0 << 10)
+# define R500_BMASK_DISABLE (1 << 10)
+# define R500_HIZ_EQUAL_REJECT_DISABLE (0 << 11)
+# define R500_HIZ_EQUAL_REJECT_ENABLE (1 << 11)
+# define R500_HIZ_FP_EXP_BITS_DISABLE (0 << 12)
+# define R500_HIZ_FP_EXP_BITS_1 (1 << 12)
+# define R500_HIZ_FP_EXP_BITS_2 (2 << 12)
+# define R500_HIZ_FP_EXP_BITS_3 (3 << 12)
+# define R500_HIZ_FP_EXP_BITS_4 (4 << 12)
+# define R500_HIZ_FP_EXP_BITS_5 (5 << 12)
+# define R500_HIZ_FP_INVERT_LEADING_ONES (0 << 15)
+# define R500_HIZ_FP_INVERT_LEADING_ZEROS (1 << 15)
+# define R500_TILE_OVERWRITE_RECOMPRESSION_ENABLE (0 << 16)
+# define R500_TILE_OVERWRITE_RECOMPRESSION_DISABLE (1 << 16)
+# define R500_CONTIGUOUS_6XAA_SAMPLES_ENABLE (0 << 17)
+# define R500_CONTIGUOUS_6XAA_SAMPLES_DISABLE (1 << 17)
+# define R500_PEQ_PACKING_DISABLE (0 << 18)
+# define R500_PEQ_PACKING_ENABLE (1 << 18)
+# define R500_COVERED_PTR_MASKING_DISABLE (0 << 18)
+# define R500_COVERED_PTR_MASKING_ENABLE (1 << 18)
+
/* gap */
-#define R300_RB3D_DEPTHOFFSET 0x4F20
-#define R300_RB3D_DEPTHPITCH 0x4F24
-# define R300_DEPTHPITCH_MASK 0x00001FF8 /* GUESS */
-# define R300_DEPTH_TILE_ENABLE (1 << 16) /* GUESS */
-# define R300_DEPTH_MICROTILE_ENABLE (1 << 17) /* GUESS */
-# define R300_DEPTH_ENDIAN_NO_SWAP (0 << 18) /* GUESS */
-# define R300_DEPTH_ENDIAN_WORD_SWAP (1 << 18) /* GUESS */
-# define R300_DEPTH_ENDIAN_DWORD_SWAP (2 << 18) /* GUESS */
+/* Z Buffer Address Offset.
+ * Bits 31 to 5 are used for aligned Z buffer address offset for macro tiles.
+ */
+#define R300_ZB_DEPTHOFFSET 0x4f20
+
+/* Z Buffer Pitch and Endian Control */
+#define R300_ZB_DEPTHPITCH 0x4f24
+# define R300_DEPTHPITCH_MASK 0x00003FFC
+# define R300_DEPTHMACROTILE_DISABLE (0 << 16)
+# define R300_DEPTHMACROTILE_ENABLE (1 << 16)
+# define R300_DEPTHMICROTILE_LINEAR (0 << 17)
+# define R300_DEPTHMICROTILE_TILED (1 << 17)
+# define R300_DEPTHMICROTILE_TILED_SQUARE (2 << 17)
+# define R300_DEPTHENDIAN_NO_SWAP (0 << 18)
+# define R300_DEPTHENDIAN_WORD_SWAP (1 << 18)
+# define R300_DEPTHENDIAN_DWORD_SWAP (2 << 18)
+# define R300_DEPTHENDIAN_HALF_DWORD_SWAP (3 << 18)
+
+/* Z Buffer Clear Value */
+#define R300_ZB_DEPTHCLEARVALUE 0x4f28
+
+#define R300_ZB_ZMASK_OFFSET 0x4f30
+#define R300_ZB_ZMASK_PITCH 0x4f34
+#define R300_ZB_ZMASK_WRINDEX 0x4f38
+#define R300_ZB_ZMASK_DWORD 0x4f3c
+#define R300_ZB_ZMASK_RDINDEX 0x4f40
+
+/* Hierarchical Z Memory Offset */
+#define R300_ZB_HIZ_OFFSET 0x4f44
+
+/* Hierarchical Z Write Index */
+#define R300_ZB_HIZ_WRINDEX 0x4f48
+
+/* Hierarchical Z Data */
+#define R300_ZB_HIZ_DWORD 0x4f4c
+
+/* Hierarchical Z Read Index */
+#define R300_ZB_HIZ_RDINDEX 0x4f50
+
+/* Hierarchical Z Pitch */
+#define R300_ZB_HIZ_PITCH 0x4f54
+
+/* Z Buffer Z Pass Counter Data */
+#define R300_ZB_ZPASS_DATA 0x4f58
+
+/* Z Buffer Z Pass Counter Address */
+#define R300_ZB_ZPASS_ADDR 0x4f5c
+
+/* Depth buffer X and Y coordinate offset */
+#define R300_ZB_DEPTHXY_OFFSET 0x4f60
+# define R300_DEPTHX_OFFSET_SHIFT 1
+# define R300_DEPTHX_OFFSET_MASK 0x000007FE
+# define R300_DEPTHY_OFFSET_SHIFT 17
+# define R300_DEPTHY_OFFSET_MASK 0x07FE0000
+
+/* Sets the fifo sizes */
+#define R500_ZB_FIFO_SIZE 0x4fd0
+# define R500_OP_FIFO_SIZE_FULL (0 << 0)
+# define R500_OP_FIFO_SIZE_HALF (1 << 0)
+# define R500_OP_FIFO_SIZE_QUATER (2 << 0)
+# define R500_OP_FIFO_SIZE_EIGTHS (4 << 0)
+
+/* Stencil Reference Value and Mask for backfacing quads */
+/* R300_ZB_STENCILREFMASK handles front face */
+#define R500_ZB_STENCILREFMASK_BF 0x4fd4
+# define R500_STENCILREF_SHIFT 0
+# define R500_STENCILREF_MASK 0x000000ff
+# define R500_STENCILMASK_SHIFT 8
+# define R500_STENCILMASK_MASK 0x0000ff00
+# define R500_STENCILWRITEMASK_SHIFT 16
+# define R500_STENCILWRITEMASK_MASK 0x00ff0000
/* BEGIN: Vertex program instruction set */
@@ -1623,4 +1753,20 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define R300_CP_CMD_BITBLT_MULTI 0xC0009B00
+#define R500_VAP_INDEX_OFFSET 0x208c
+
+#define R500_GA_US_VECTOR_INDEX 0x4250
+#define R500_GA_US_VECTOR_DATA 0x4254
+
+#define R500_RS_IP_0 0x4074
+#define R500_RS_INST_0 0x4320
+
+#define R500_US_CONFIG 0x4600
+
+#define R500_US_FC_CTRL 0x4624
+#define R500_US_CODE_ADDR 0x4630
+
+#define R500_RB3D_COLOR_CLEAR_VALUE_AR 0x46c0
+#define R500_RB3D_CONSTANT_COLOR_AR 0x4ef8
+
#endif /* _R300_REG_H */
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index f6f6c92bf771..e53158f0ecb5 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -2,6 +2,7 @@
/*
* Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Fremont, California.
+ * Copyright 2007 Advanced Micro Devices, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -34,789 +35,13 @@
#include "radeon_drv.h"
#include "r300_reg.h"
+#include "radeon_microcode.h"
+
#define RADEON_FIFO_DEBUG 0
static int radeon_do_cleanup_cp(struct drm_device * dev);
-/* CP microcode (from ATI) */
-static const u32 R200_cp_microcode[][2] = {
- {0x21007000, 0000000000},
- {0x20007000, 0000000000},
- {0x000000ab, 0x00000004},
- {0x000000af, 0x00000004},
- {0x66544a49, 0000000000},
- {0x49494174, 0000000000},
- {0x54517d83, 0000000000},
- {0x498d8b64, 0000000000},
- {0x49494949, 0000000000},
- {0x49da493c, 0000000000},
- {0x49989898, 0000000000},
- {0xd34949d5, 0000000000},
- {0x9dc90e11, 0000000000},
- {0xce9b9b9b, 0000000000},
- {0x000f0000, 0x00000016},
- {0x352e232c, 0000000000},
- {0x00000013, 0x00000004},
- {0x000f0000, 0x00000016},
- {0x352e272c, 0000000000},
- {0x000f0001, 0x00000016},
- {0x3239362f, 0000000000},
- {0x000077ef, 0x00000002},
- {0x00061000, 0x00000002},
- {0x00000020, 0x0000001a},
- {0x00004000, 0x0000001e},
- {0x00061000, 0x00000002},
- {0x00000020, 0x0000001a},
- {0x00004000, 0x0000001e},
- {0x00061000, 0x00000002},
- {0x00000020, 0x0000001a},
- {0x00004000, 0x0000001e},
- {0x00000016, 0x00000004},
- {0x0003802a, 0x00000002},
- {0x040067e0, 0x00000002},
- {0x00000016, 0x00000004},
- {0x000077e0, 0x00000002},
- {0x00065000, 0x00000002},
- {0x000037e1, 0x00000002},
- {0x040067e1, 0x00000006},
- {0x000077e0, 0x00000002},
- {0x000077e1, 0x00000002},
- {0x000077e1, 0x00000006},
- {0xffffffff, 0000000000},
- {0x10000000, 0000000000},
- {0x0003802a, 0x00000002},
- {0x040067e0, 0x00000006},
- {0x00007675, 0x00000002},
- {0x00007676, 0x00000002},
- {0x00007677, 0x00000002},
- {0x00007678, 0x00000006},
- {0x0003802b, 0x00000002},
- {0x04002676, 0x00000002},
- {0x00007677, 0x00000002},
- {0x00007678, 0x00000006},
- {0x0000002e, 0x00000018},
- {0x0000002e, 0x00000018},
- {0000000000, 0x00000006},
- {0x0000002f, 0x00000018},
- {0x0000002f, 0x00000018},
- {0000000000, 0x00000006},
- {0x01605000, 0x00000002},
- {0x00065000, 0x00000002},
- {0x00098000, 0x00000002},
- {0x00061000, 0x00000002},
- {0x64c0603d, 0x00000004},
- {0x00080000, 0x00000016},
- {0000000000, 0000000000},
- {0x0400251d, 0x00000002},
- {0x00007580, 0x00000002},
- {0x00067581, 0x00000002},
- {0x04002580, 0x00000002},
- {0x00067581, 0x00000002},
- {0x00000046, 0x00000004},
- {0x00005000, 0000000000},
- {0x00061000, 0x00000002},
- {0x0000750e, 0x00000002},
- {0x00019000, 0x00000002},
- {0x00011055, 0x00000014},
- {0x00000055, 0x00000012},
- {0x0400250f, 0x00000002},
- {0x0000504a, 0x00000004},
- {0x00007565, 0x00000002},
- {0x00007566, 0x00000002},
- {0x00000051, 0x00000004},
- {0x01e655b4, 0x00000002},
- {0x4401b0dc, 0x00000002},
- {0x01c110dc, 0x00000002},
- {0x2666705d, 0x00000018},
- {0x040c2565, 0x00000002},
- {0x0000005d, 0x00000018},
- {0x04002564, 0x00000002},
- {0x00007566, 0x00000002},
- {0x00000054, 0x00000004},
- {0x00401060, 0x00000008},
- {0x00101000, 0x00000002},
- {0x000d80ff, 0x00000002},
- {0x00800063, 0x00000008},
- {0x000f9000, 0x00000002},
- {0x000e00ff, 0x00000002},
- {0000000000, 0x00000006},
- {0x00000080, 0x00000018},
- {0x00000054, 0x00000004},
- {0x00007576, 0x00000002},
- {0x00065000, 0x00000002},
- {0x00009000, 0x00000002},
- {0x00041000, 0x00000002},
- {0x0c00350e, 0x00000002},
- {0x00049000, 0x00000002},
- {0x00051000, 0x00000002},
- {0x01e785f8, 0x00000002},
- {0x00200000, 0x00000002},
- {0x00600073, 0x0000000c},
- {0x00007563, 0x00000002},
- {0x006075f0, 0x00000021},
- {0x20007068, 0x00000004},
- {0x00005068, 0x00000004},
- {0x00007576, 0x00000002},
- {0x00007577, 0x00000002},
- {0x0000750e, 0x00000002},
- {0x0000750f, 0x00000002},
- {0x00a05000, 0x00000002},
- {0x00600076, 0x0000000c},
- {0x006075f0, 0x00000021},
- {0x000075f8, 0x00000002},
- {0x00000076, 0x00000004},
- {0x000a750e, 0x00000002},
- {0x0020750f, 0x00000002},
- {0x00600079, 0x00000004},
- {0x00007570, 0x00000002},
- {0x00007571, 0x00000002},
- {0x00007572, 0x00000006},
- {0x00005000, 0x00000002},
- {0x00a05000, 0x00000002},
- {0x00007568, 0x00000002},
- {0x00061000, 0x00000002},
- {0x00000084, 0x0000000c},
- {0x00058000, 0x00000002},
- {0x0c607562, 0x00000002},
- {0x00000086, 0x00000004},
- {0x00600085, 0x00000004},
- {0x400070dd, 0000000000},
- {0x000380dd, 0x00000002},
- {0x00000093, 0x0000001c},
- {0x00065095, 0x00000018},
- {0x040025bb, 0x00000002},
- {0x00061096, 0x00000018},
- {0x040075bc, 0000000000},
- {0x000075bb, 0x00000002},
- {0x000075bc, 0000000000},
- {0x00090000, 0x00000006},
- {0x00090000, 0x00000002},
- {0x000d8002, 0x00000006},
- {0x00005000, 0x00000002},
- {0x00007821, 0x00000002},
- {0x00007800, 0000000000},
- {0x00007821, 0x00000002},
- {0x00007800, 0000000000},
- {0x01665000, 0x00000002},
- {0x000a0000, 0x00000002},
- {0x000671cc, 0x00000002},
- {0x0286f1cd, 0x00000002},
- {0x000000a3, 0x00000010},
- {0x21007000, 0000000000},
- {0x000000aa, 0x0000001c},
- {0x00065000, 0x00000002},
- {0x000a0000, 0x00000002},
- {0x00061000, 0x00000002},
- {0x000b0000, 0x00000002},
- {0x38067000, 0x00000002},
- {0x000a00a6, 0x00000004},
- {0x20007000, 0000000000},
- {0x01200000, 0x00000002},
- {0x20077000, 0x00000002},
- {0x01200000, 0x00000002},
- {0x20007000, 0000000000},
- {0x00061000, 0x00000002},
- {0x0120751b, 0x00000002},
- {0x8040750a, 0x00000002},
- {0x8040750b, 0x00000002},
- {0x00110000, 0x00000002},
- {0x000380dd, 0x00000002},
- {0x000000bd, 0x0000001c},
- {0x00061096, 0x00000018},
- {0x844075bd, 0x00000002},
- {0x00061095, 0x00000018},
- {0x840075bb, 0x00000002},
- {0x00061096, 0x00000018},
- {0x844075bc, 0x00000002},
- {0x000000c0, 0x00000004},
- {0x804075bd, 0x00000002},
- {0x800075bb, 0x00000002},
- {0x804075bc, 0x00000002},
- {0x00108000, 0x00000002},
- {0x01400000, 0x00000002},
- {0x006000c4, 0x0000000c},
- {0x20c07000, 0x00000020},
- {0x000000c6, 0x00000012},
- {0x00800000, 0x00000006},
- {0x0080751d, 0x00000006},
- {0x000025bb, 0x00000002},
- {0x000040c0, 0x00000004},
- {0x0000775c, 0x00000002},
- {0x00a05000, 0x00000002},
- {0x00661000, 0x00000002},
- {0x0460275d, 0x00000020},
- {0x00004000, 0000000000},
- {0x00007999, 0x00000002},
- {0x00a05000, 0x00000002},
- {0x00661000, 0x00000002},
- {0x0460299b, 0x00000020},
- {0x00004000, 0000000000},
- {0x01e00830, 0x00000002},
- {0x21007000, 0000000000},
- {0x00005000, 0x00000002},
- {0x00038042, 0x00000002},
- {0x040025e0, 0x00000002},
- {0x000075e1, 0000000000},
- {0x00000001, 0000000000},
- {0x000380d9, 0x00000002},
- {0x04007394, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
-};
-
-static const u32 radeon_cp_microcode[][2] = {
- {0x21007000, 0000000000},
- {0x20007000, 0000000000},
- {0x000000b4, 0x00000004},
- {0x000000b8, 0x00000004},
- {0x6f5b4d4c, 0000000000},
- {0x4c4c427f, 0000000000},
- {0x5b568a92, 0000000000},
- {0x4ca09c6d, 0000000000},
- {0xad4c4c4c, 0000000000},
- {0x4ce1af3d, 0000000000},
- {0xd8afafaf, 0000000000},
- {0xd64c4cdc, 0000000000},
- {0x4cd10d10, 0000000000},
- {0x000f0000, 0x00000016},
- {0x362f242d, 0000000000},
- {0x00000012, 0x00000004},
- {0x000f0000, 0x00000016},
- {0x362f282d, 0000000000},
- {0x000380e7, 0x00000002},
- {0x04002c97, 0x00000002},
- {0x000f0001, 0x00000016},
- {0x333a3730, 0000000000},
- {0x000077ef, 0x00000002},
- {0x00061000, 0x00000002},
- {0x00000021, 0x0000001a},
- {0x00004000, 0x0000001e},
- {0x00061000, 0x00000002},
- {0x00000021, 0x0000001a},
- {0x00004000, 0x0000001e},
- {0x00061000, 0x00000002},
- {0x00000021, 0x0000001a},
- {0x00004000, 0x0000001e},
- {0x00000017, 0x00000004},
- {0x0003802b, 0x00000002},
- {0x040067e0, 0x00000002},
- {0x00000017, 0x00000004},
- {0x000077e0, 0x00000002},
- {0x00065000, 0x00000002},
- {0x000037e1, 0x00000002},
- {0x040067e1, 0x00000006},
- {0x000077e0, 0x00000002},
- {0x000077e1, 0x00000002},
- {0x000077e1, 0x00000006},
- {0xffffffff, 0000000000},
- {0x10000000, 0000000000},
- {0x0003802b, 0x00000002},
- {0x040067e0, 0x00000006},
- {0x00007675, 0x00000002},
- {0x00007676, 0x00000002},
- {0x00007677, 0x00000002},
- {0x00007678, 0x00000006},
- {0x0003802c, 0x00000002},
- {0x04002676, 0x00000002},
- {0x00007677, 0x00000002},
- {0x00007678, 0x00000006},
- {0x0000002f, 0x00000018},
- {0x0000002f, 0x00000018},
- {0000000000, 0x00000006},
- {0x00000030, 0x00000018},
- {0x00000030, 0x00000018},
- {0000000000, 0x00000006},
- {0x01605000, 0x00000002},
- {0x00065000, 0x00000002},
- {0x00098000, 0x00000002},
- {0x00061000, 0x00000002},
- {0x64c0603e, 0x00000004},
- {0x000380e6, 0x00000002},
- {0x040025c5, 0x00000002},
- {0x00080000, 0x00000016},
- {0000000000, 0000000000},
- {0x0400251d, 0x00000002},
- {0x00007580, 0x00000002},
- {0x00067581, 0x00000002},
- {0x04002580, 0x00000002},
- {0x00067581, 0x00000002},
- {0x00000049, 0x00000004},
- {0x00005000, 0000000000},
- {0x000380e6, 0x00000002},
- {0x040025c5, 0x00000002},
- {0x00061000, 0x00000002},
- {0x0000750e, 0x00000002},
- {0x00019000, 0x00000002},
- {0x00011055, 0x00000014},
- {0x00000055, 0x00000012},
- {0x0400250f, 0x00000002},
- {0x0000504f, 0x00000004},
- {0x000380e6, 0x00000002},
- {0x040025c5, 0x00000002},
- {0x00007565, 0x00000002},
- {0x00007566, 0x00000002},
- {0x00000058, 0x00000004},
- {0x000380e6, 0x00000002},
- {0x040025c5, 0x00000002},
- {0x01e655b4, 0x00000002},
- {0x4401b0e4, 0x00000002},
- {0x01c110e4, 0x00000002},
- {0x26667066, 0x00000018},
- {0x040c2565, 0x00000002},
- {0x00000066, 0x00000018},
- {0x04002564, 0x00000002},
- {0x00007566, 0x00000002},
- {0x0000005d, 0x00000004},
- {0x00401069, 0x00000008},
- {0x00101000, 0x00000002},
- {0x000d80ff, 0x00000002},
- {0x0080006c, 0x00000008},
- {0x000f9000, 0x00000002},
- {0x000e00ff, 0x00000002},
- {0000000000, 0x00000006},
- {0x0000008f, 0x00000018},
- {0x0000005b, 0x00000004},
- {0x000380e6, 0x00000002},
- {0x040025c5, 0x00000002},
- {0x00007576, 0x00000002},
- {0x00065000, 0x00000002},
- {0x00009000, 0x00000002},
- {0x00041000, 0x00000002},
- {0x0c00350e, 0x00000002},
- {0x00049000, 0x00000002},
- {0x00051000, 0x00000002},
- {0x01e785f8, 0x00000002},
- {0x00200000, 0x00000002},
- {0x0060007e, 0x0000000c},
- {0x00007563, 0x00000002},
- {0x006075f0, 0x00000021},
- {0x20007073, 0x00000004},
- {0x00005073, 0x00000004},
- {0x000380e6, 0x00000002},
- {0x040025c5, 0x00000002},
- {0x00007576, 0x00000002},
- {0x00007577, 0x00000002},
- {0x0000750e, 0x00000002},
- {0x0000750f, 0x00000002},
- {0x00a05000, 0x00000002},
- {0x00600083, 0x0000000c},
- {0x006075f0, 0x00000021},
- {0x000075f8, 0x00000002},
- {0x00000083, 0x00000004},
- {0x000a750e, 0x00000002},
- {0x000380e6, 0x00000002},
- {0x040025c5, 0x00000002},
- {0x0020750f, 0x00000002},
- {0x00600086, 0x00000004},
- {0x00007570, 0x00000002},
- {0x00007571, 0x00000002},
- {0x00007572, 0x00000006},
- {0x000380e6, 0x00000002},
- {0x040025c5, 0x00000002},
- {0x00005000, 0x00000002},
- {0x00a05000, 0x00000002},
- {0x00007568, 0x00000002},
- {0x00061000, 0x00000002},
- {0x00000095, 0x0000000c},
- {0x00058000, 0x00000002},
- {0x0c607562, 0x00000002},
- {0x00000097, 0x00000004},
- {0x000380e6, 0x00000002},
- {0x040025c5, 0x00000002},
- {0x00600096, 0x00000004},
- {0x400070e5, 0000000000},
- {0x000380e6, 0x00000002},
- {0x040025c5, 0x00000002},
- {0x000380e5, 0x00000002},
- {0x000000a8, 0x0000001c},
- {0x000650aa, 0x00000018},
- {0x040025bb, 0x00000002},
- {0x000610ab, 0x00000018},
- {0x040075bc, 0000000000},
- {0x000075bb, 0x00000002},
- {0x000075bc, 0000000000},
- {0x00090000, 0x00000006},
- {0x00090000, 0x00000002},
- {0x000d8002, 0x00000006},
- {0x00007832, 0x00000002},
- {0x00005000, 0x00000002},
- {0x000380e7, 0x00000002},
- {0x04002c97, 0x00000002},
- {0x00007820, 0x00000002},
- {0x00007821, 0x00000002},
- {0x00007800, 0000000000},
- {0x01200000, 0x00000002},
- {0x20077000, 0x00000002},
- {0x01200000, 0x00000002},
- {0x20007000, 0x00000002},
- {0x00061000, 0x00000002},
- {0x0120751b, 0x00000002},
- {0x8040750a, 0x00000002},
- {0x8040750b, 0x00000002},
- {0x00110000, 0x00000002},
- {0x000380e5, 0x00000002},
- {0x000000c6, 0x0000001c},
- {0x000610ab, 0x00000018},
- {0x844075bd, 0x00000002},
- {0x000610aa, 0x00000018},
- {0x840075bb, 0x00000002},
- {0x000610ab, 0x00000018},
- {0x844075bc, 0x00000002},
- {0x000000c9, 0x00000004},
- {0x804075bd, 0x00000002},
- {0x800075bb, 0x00000002},
- {0x804075bc, 0x00000002},
- {0x00108000, 0x00000002},
- {0x01400000, 0x00000002},
- {0x006000cd, 0x0000000c},
- {0x20c07000, 0x00000020},
- {0x000000cf, 0x00000012},
- {0x00800000, 0x00000006},
- {0x0080751d, 0x00000006},
- {0000000000, 0000000000},
- {0x0000775c, 0x00000002},
- {0x00a05000, 0x00000002},
- {0x00661000, 0x00000002},
- {0x0460275d, 0x00000020},
- {0x00004000, 0000000000},
- {0x01e00830, 0x00000002},
- {0x21007000, 0000000000},
- {0x6464614d, 0000000000},
- {0x69687420, 0000000000},
- {0x00000073, 0000000000},
- {0000000000, 0000000000},
- {0x00005000, 0x00000002},
- {0x000380d0, 0x00000002},
- {0x040025e0, 0x00000002},
- {0x000075e1, 0000000000},
- {0x00000001, 0000000000},
- {0x000380e0, 0x00000002},
- {0x04002394, 0x00000002},
- {0x00005000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0x00000008, 0000000000},
- {0x00000004, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
-};
-
-static const u32 R300_cp_microcode[][2] = {
- {0x4200e000, 0000000000},
- {0x4000e000, 0000000000},
- {0x000000af, 0x00000008},
- {0x000000b3, 0x00000008},
- {0x6c5a504f, 0000000000},
- {0x4f4f497a, 0000000000},
- {0x5a578288, 0000000000},
- {0x4f91906a, 0000000000},
- {0x4f4f4f4f, 0000000000},
- {0x4fe24f44, 0000000000},
- {0x4f9c9c9c, 0000000000},
- {0xdc4f4fde, 0000000000},
- {0xa1cd4f4f, 0000000000},
- {0xd29d9d9d, 0000000000},
- {0x4f0f9fd7, 0000000000},
- {0x000ca000, 0x00000004},
- {0x000d0012, 0x00000038},
- {0x0000e8b4, 0x00000004},
- {0x000d0014, 0x00000038},
- {0x0000e8b6, 0x00000004},
- {0x000d0016, 0x00000038},
- {0x0000e854, 0x00000004},
- {0x000d0018, 0x00000038},
- {0x0000e855, 0x00000004},
- {0x000d001a, 0x00000038},
- {0x0000e856, 0x00000004},
- {0x000d001c, 0x00000038},
- {0x0000e857, 0x00000004},
- {0x000d001e, 0x00000038},
- {0x0000e824, 0x00000004},
- {0x000d0020, 0x00000038},
- {0x0000e825, 0x00000004},
- {0x000d0022, 0x00000038},
- {0x0000e830, 0x00000004},
- {0x000d0024, 0x00000038},
- {0x0000f0c0, 0x00000004},
- {0x000d0026, 0x00000038},
- {0x0000f0c1, 0x00000004},
- {0x000d0028, 0x00000038},
- {0x0000f041, 0x00000004},
- {0x000d002a, 0x00000038},
- {0x0000f184, 0x00000004},
- {0x000d002c, 0x00000038},
- {0x0000f185, 0x00000004},
- {0x000d002e, 0x00000038},
- {0x0000f186, 0x00000004},
- {0x000d0030, 0x00000038},
- {0x0000f187, 0x00000004},
- {0x000d0032, 0x00000038},
- {0x0000f180, 0x00000004},
- {0x000d0034, 0x00000038},
- {0x0000f393, 0x00000004},
- {0x000d0036, 0x00000038},
- {0x0000f38a, 0x00000004},
- {0x000d0038, 0x00000038},
- {0x0000f38e, 0x00000004},
- {0x0000e821, 0x00000004},
- {0x0140a000, 0x00000004},
- {0x00000043, 0x00000018},
- {0x00cce800, 0x00000004},
- {0x001b0001, 0x00000004},
- {0x08004800, 0x00000004},
- {0x001b0001, 0x00000004},
- {0x08004800, 0x00000004},
- {0x001b0001, 0x00000004},
- {0x08004800, 0x00000004},
- {0x0000003a, 0x00000008},
- {0x0000a000, 0000000000},
- {0x02c0a000, 0x00000004},
- {0x000ca000, 0x00000004},
- {0x00130000, 0x00000004},
- {0x000c2000, 0x00000004},
- {0xc980c045, 0x00000008},
- {0x2000451d, 0x00000004},
- {0x0000e580, 0x00000004},
- {0x000ce581, 0x00000004},
- {0x08004580, 0x00000004},
- {0x000ce581, 0x00000004},
- {0x0000004c, 0x00000008},
- {0x0000a000, 0000000000},
- {0x000c2000, 0x00000004},
- {0x0000e50e, 0x00000004},
- {0x00032000, 0x00000004},
- {0x00022056, 0x00000028},
- {0x00000056, 0x00000024},
- {0x0800450f, 0x00000004},
- {0x0000a050, 0x00000008},
- {0x0000e565, 0x00000004},
- {0x0000e566, 0x00000004},
- {0x00000057, 0x00000008},
- {0x03cca5b4, 0x00000004},
- {0x05432000, 0x00000004},
- {0x00022000, 0x00000004},
- {0x4ccce063, 0x00000030},
- {0x08274565, 0x00000004},
- {0x00000063, 0x00000030},
- {0x08004564, 0x00000004},
- {0x0000e566, 0x00000004},
- {0x0000005a, 0x00000008},
- {0x00802066, 0x00000010},
- {0x00202000, 0x00000004},
- {0x001b00ff, 0x00000004},
- {0x01000069, 0x00000010},
- {0x001f2000, 0x00000004},
- {0x001c00ff, 0x00000004},
- {0000000000, 0x0000000c},
- {0x00000085, 0x00000030},
- {0x0000005a, 0x00000008},
- {0x0000e576, 0x00000004},
- {0x000ca000, 0x00000004},
- {0x00012000, 0x00000004},
- {0x00082000, 0x00000004},
- {0x1800650e, 0x00000004},
- {0x00092000, 0x00000004},
- {0x000a2000, 0x00000004},
- {0x000f0000, 0x00000004},
- {0x00400000, 0x00000004},
- {0x00000079, 0x00000018},
- {0x0000e563, 0x00000004},
- {0x00c0e5f9, 0x000000c2},
- {0x0000006e, 0x00000008},
- {0x0000a06e, 0x00000008},
- {0x0000e576, 0x00000004},
- {0x0000e577, 0x00000004},
- {0x0000e50e, 0x00000004},
- {0x0000e50f, 0x00000004},
- {0x0140a000, 0x00000004},
- {0x0000007c, 0x00000018},
- {0x00c0e5f9, 0x000000c2},
- {0x0000007c, 0x00000008},
- {0x0014e50e, 0x00000004},
- {0x0040e50f, 0x00000004},
- {0x00c0007f, 0x00000008},
- {0x0000e570, 0x00000004},
- {0x0000e571, 0x00000004},
- {0x0000e572, 0x0000000c},
- {0x0000a000, 0x00000004},
- {0x0140a000, 0x00000004},
- {0x0000e568, 0x00000004},
- {0x000c2000, 0x00000004},
- {0x00000089, 0x00000018},
- {0x000b0000, 0x00000004},
- {0x18c0e562, 0x00000004},
- {0x0000008b, 0x00000008},
- {0x00c0008a, 0x00000008},
- {0x000700e4, 0x00000004},
- {0x00000097, 0x00000038},
- {0x000ca099, 0x00000030},
- {0x080045bb, 0x00000004},
- {0x000c209a, 0x00000030},
- {0x0800e5bc, 0000000000},
- {0x0000e5bb, 0x00000004},
- {0x0000e5bc, 0000000000},
- {0x00120000, 0x0000000c},
- {0x00120000, 0x00000004},
- {0x001b0002, 0x0000000c},
- {0x0000a000, 0x00000004},
- {0x0000e821, 0x00000004},
- {0x0000e800, 0000000000},
- {0x0000e821, 0x00000004},
- {0x0000e82e, 0000000000},
- {0x02cca000, 0x00000004},
- {0x00140000, 0x00000004},
- {0x000ce1cc, 0x00000004},
- {0x050de1cd, 0x00000004},
- {0x000000a7, 0x00000020},
- {0x4200e000, 0000000000},
- {0x000000ae, 0x00000038},
- {0x000ca000, 0x00000004},
- {0x00140000, 0x00000004},
- {0x000c2000, 0x00000004},
- {0x00160000, 0x00000004},
- {0x700ce000, 0x00000004},
- {0x001400aa, 0x00000008},
- {0x4000e000, 0000000000},
- {0x02400000, 0x00000004},
- {0x400ee000, 0x00000004},
- {0x02400000, 0x00000004},
- {0x4000e000, 0000000000},
- {0x000c2000, 0x00000004},
- {0x0240e51b, 0x00000004},
- {0x0080e50a, 0x00000005},
- {0x0080e50b, 0x00000005},
- {0x00220000, 0x00000004},
- {0x000700e4, 0x00000004},
- {0x000000c1, 0x00000038},
- {0x000c209a, 0x00000030},
- {0x0880e5bd, 0x00000005},
- {0x000c2099, 0x00000030},
- {0x0800e5bb, 0x00000005},
- {0x000c209a, 0x00000030},
- {0x0880e5bc, 0x00000005},
- {0x000000c4, 0x00000008},
- {0x0080e5bd, 0x00000005},
- {0x0000e5bb, 0x00000005},
- {0x0080e5bc, 0x00000005},
- {0x00210000, 0x00000004},
- {0x02800000, 0x00000004},
- {0x00c000c8, 0x00000018},
- {0x4180e000, 0x00000040},
- {0x000000ca, 0x00000024},
- {0x01000000, 0x0000000c},
- {0x0100e51d, 0x0000000c},
- {0x000045bb, 0x00000004},
- {0x000080c4, 0x00000008},
- {0x0000f3ce, 0x00000004},
- {0x0140a000, 0x00000004},
- {0x00cc2000, 0x00000004},
- {0x08c053cf, 0x00000040},
- {0x00008000, 0000000000},
- {0x0000f3d2, 0x00000004},
- {0x0140a000, 0x00000004},
- {0x00cc2000, 0x00000004},
- {0x08c053d3, 0x00000040},
- {0x00008000, 0000000000},
- {0x0000f39d, 0x00000004},
- {0x0140a000, 0x00000004},
- {0x00cc2000, 0x00000004},
- {0x08c0539e, 0x00000040},
- {0x00008000, 0000000000},
- {0x03c00830, 0x00000004},
- {0x4200e000, 0000000000},
- {0x0000a000, 0x00000004},
- {0x200045e0, 0x00000004},
- {0x0000e5e1, 0000000000},
- {0x00000001, 0000000000},
- {0x000700e1, 0x00000004},
- {0x0800e394, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
- {0000000000, 0000000000},
-};
-
-static u32 RADEON_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
+static u32 R500_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
{
u32 ret;
RADEON_WRITE(R520_MC_IND_INDEX, 0x7f0000 | (addr & 0xff));
@@ -825,21 +50,41 @@ static u32 RADEON_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
return ret;
}
+static u32 RS480_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
+{
+ u32 ret;
+ RADEON_WRITE(RS480_NB_MC_INDEX, addr & 0xff);
+ ret = RADEON_READ(RS480_NB_MC_DATA);
+ RADEON_WRITE(RS480_NB_MC_INDEX, 0xff);
+ return ret;
+}
+
static u32 RS690_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
{
+ u32 ret;
RADEON_WRITE(RS690_MC_INDEX, (addr & RS690_MC_INDEX_MASK));
- return RADEON_READ(RS690_MC_DATA);
+ ret = RADEON_READ(RS690_MC_DATA);
+ RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_MASK);
+ return ret;
+}
+
+static u32 IGP_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
+{
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+ return RS690_READ_MCIND(dev_priv, addr);
+ else
+ return RS480_READ_MCIND(dev_priv, addr);
}
u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)
{
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
- return RADEON_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION);
+ return R500_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
return RS690_READ_MCIND(dev_priv, RS690_MC_FB_LOCATION);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
- return RADEON_READ_MCIND(dev_priv, R520_MC_FB_LOCATION);
+ return R500_READ_MCIND(dev_priv, R520_MC_FB_LOCATION);
else
return RADEON_READ(RADEON_MC_FB_LOCATION);
}
@@ -847,11 +92,11 @@ u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)
static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc)
{
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
- RADEON_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc);
+ R500_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
- RADEON_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc);
+ R500_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc);
else
RADEON_WRITE(RADEON_MC_FB_LOCATION, fb_loc);
}
@@ -859,15 +104,39 @@ static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc)
static void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc)
{
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
- RADEON_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc);
+ R500_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, agp_loc);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
- RADEON_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc);
+ R500_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc);
else
RADEON_WRITE(RADEON_MC_AGP_LOCATION, agp_loc);
}
+static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base)
+{
+ u32 agp_base_hi = upper_32_bits(agp_base);
+ u32 agp_base_lo = agp_base & 0xffffffff;
+
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) {
+ R500_WRITE_MCIND(RV515_MC_AGP_BASE, agp_base_lo);
+ R500_WRITE_MCIND(RV515_MC_AGP_BASE_2, agp_base_hi);
+ } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
+ RS690_WRITE_MCIND(RS690_MC_AGP_BASE, agp_base_lo);
+ RS690_WRITE_MCIND(RS690_MC_AGP_BASE_2, agp_base_hi);
+ } else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) {
+ R500_WRITE_MCIND(R520_MC_AGP_BASE, agp_base_lo);
+ R500_WRITE_MCIND(R520_MC_AGP_BASE_2, agp_base_hi);
+ } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480) {
+ RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo);
+ RADEON_WRITE(RS480_AGP_BASE_2, 0);
+ } else {
+ RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo);
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R200)
+ RADEON_WRITE(RADEON_AGP_BASE_2, agp_base_hi);
+ }
+}
+
static int RADEON_READ_PLL(struct drm_device * dev, int addr)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -882,15 +151,6 @@ static u32 RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr)
return RADEON_READ(RADEON_PCIE_DATA);
}
-static u32 RADEON_READ_IGPGART(drm_radeon_private_t *dev_priv, int addr)
-{
- u32 ret;
- RADEON_WRITE(RADEON_IGPGART_INDEX, addr & 0x7f);
- ret = RADEON_READ(RADEON_IGPGART_DATA);
- RADEON_WRITE(RADEON_IGPGART_INDEX, 0x7f);
- return ret;
-}
-
#if RADEON_FIFO_DEBUG
static void radeon_status(drm_radeon_private_t * dev_priv)
{
@@ -925,16 +185,36 @@ static int radeon_do_pixcache_flush(drm_radeon_private_t * dev_priv)
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
- tmp = RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT);
- tmp |= RADEON_RB3D_DC_FLUSH_ALL;
- RADEON_WRITE(RADEON_RB3D_DSTCACHE_CTLSTAT, tmp);
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) {
+ tmp = RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT);
+ tmp |= RADEON_RB3D_DC_FLUSH_ALL;
+ RADEON_WRITE(RADEON_RB3D_DSTCACHE_CTLSTAT, tmp);
- for (i = 0; i < dev_priv->usec_timeout; i++) {
- if (!(RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT)
- & RADEON_RB3D_DC_BUSY)) {
- return 0;
+ for (i = 0; i < dev_priv->usec_timeout; i++) {
+ if (!(RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT)
+ & RADEON_RB3D_DC_BUSY)) {
+ return 0;
+ }
+ DRM_UDELAY(1);
+ }
+ } else {
+ /* 3D */
+ tmp = RADEON_READ(R300_RB3D_DSTCACHE_CTLSTAT);
+ tmp |= RADEON_RB3D_DC_FLUSH_ALL;
+ RADEON_WRITE(R300_RB3D_DSTCACHE_CTLSTAT, tmp);
+
+ /* 2D */
+ tmp = RADEON_READ(R300_DSTCACHE_CTLSTAT);
+ tmp |= RADEON_RB3D_DC_FLUSH_ALL;
+ RADEON_WRITE(R300_DSTCACHE_CTLSTAT, tmp);
+
+ for (i = 0; i < dev_priv->usec_timeout; i++) {
+ if (!(RADEON_READ(R300_DSTCACHE_CTLSTAT)
+ & RADEON_RB3D_DC_BUSY)) {
+ return 0;
+ }
+ DRM_UDELAY(1);
}
- DRM_UDELAY(1);
}
#if RADEON_FIFO_DEBUG
@@ -991,6 +271,50 @@ static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv)
return -EBUSY;
}
+static void radeon_init_pipes(drm_radeon_private_t *dev_priv)
+{
+ uint32_t gb_tile_config, gb_pipe_sel = 0;
+
+ /* RS4xx/RS6xx/R4xx/R5xx */
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R420) {
+ gb_pipe_sel = RADEON_READ(R400_GB_PIPE_SELECT);
+ dev_priv->num_gb_pipes = ((gb_pipe_sel >> 12) & 0x3) + 1;
+ } else {
+ /* R3xx */
+ if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R300) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R350)) {
+ dev_priv->num_gb_pipes = 2;
+ } else {
+ /* R3Vxx */
+ dev_priv->num_gb_pipes = 1;
+ }
+ }
+ DRM_INFO("Num pipes: %d\n", dev_priv->num_gb_pipes);
+
+ gb_tile_config = (R300_ENABLE_TILING | R300_TILE_SIZE_16 /*| R300_SUBPIXEL_1_16*/);
+
+ switch (dev_priv->num_gb_pipes) {
+ case 2: gb_tile_config |= R300_PIPE_COUNT_R300; break;
+ case 3: gb_tile_config |= R300_PIPE_COUNT_R420_3P; break;
+ case 4: gb_tile_config |= R300_PIPE_COUNT_R420; break;
+ default:
+ case 1: gb_tile_config |= R300_PIPE_COUNT_RV350; break;
+ }
+
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) {
+ RADEON_WRITE_PLL(R500_DYN_SCLK_PWMEM_PIPE, (1 | ((gb_pipe_sel >> 8) & 0xf) << 4));
+ RADEON_WRITE(R500_SU_REG_DEST, ((1 << dev_priv->num_gb_pipes) - 1));
+ }
+ RADEON_WRITE(R300_GB_TILE_CONFIG, gb_tile_config);
+ radeon_do_wait_for_idle(dev_priv);
+ RADEON_WRITE(R300_DST_PIPE_CONFIG, RADEON_READ(R300_DST_PIPE_CONFIG) | R300_PIPE_AUTO_CONFIG);
+ RADEON_WRITE(R300_RB2D_DSTCACHE_MODE, (RADEON_READ(R300_RB2D_DSTCACHE_MODE) |
+ R300_DC_AUTOFLUSH_ENABLE |
+ R300_DC_DC_DISABLE_IGNORE_PE));
+
+
+}
+
/* ================================================================
* CP control, initialization
*/
@@ -1004,8 +328,22 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
radeon_do_wait_for_idle(dev_priv);
RADEON_WRITE(RADEON_CP_ME_RAM_ADDR, 0);
-
- if (dev_priv->microcode_version == UCODE_R200) {
+ if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R100) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV100) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV200) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS100) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS200)) {
+ DRM_INFO("Loading R100 Microcode\n");
+ for (i = 0; i < 256; i++) {
+ RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
+ R100_cp_microcode[i][1]);
+ RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
+ R100_cp_microcode[i][0]);
+ }
+ } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R200) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV250) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV280) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS300)) {
DRM_INFO("Loading R200 Microcode\n");
for (i = 0; i < 256; i++) {
RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
@@ -1013,7 +351,11 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
R200_cp_microcode[i][0]);
}
- } else if (dev_priv->microcode_version == UCODE_R300) {
+ } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R300) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R350) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV350) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV380) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
DRM_INFO("Loading R300 Microcode\n");
for (i = 0; i < 256; i++) {
RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
@@ -1021,12 +363,35 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
R300_cp_microcode[i][0]);
}
- } else {
+ } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV410)) {
+ DRM_INFO("Loading R400 Microcode\n");
for (i = 0; i < 256; i++) {
RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
- radeon_cp_microcode[i][1]);
+ R420_cp_microcode[i][1]);
RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
- radeon_cp_microcode[i][0]);
+ R420_cp_microcode[i][0]);
+ }
+ } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
+ DRM_INFO("Loading RS690 Microcode\n");
+ for (i = 0; i < 256; i++) {
+ RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
+ RS690_cp_microcode[i][1]);
+ RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
+ RS690_cp_microcode[i][0]);
+ }
+ } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R520) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV530) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R580) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV560) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV570)) {
+ DRM_INFO("Loading R500 Microcode\n");
+ for (i = 0; i < 256; i++) {
+ RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
+ R520_cp_microcode[i][1]);
+ RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
+ R520_cp_microcode[i][0]);
}
}
}
@@ -1121,12 +486,13 @@ static void radeon_do_cp_stop(drm_radeon_private_t * dev_priv)
static int radeon_do_engine_reset(struct drm_device * dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
- u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset;
+ u32 clock_cntl_index = 0, mclk_cntl = 0, rbbm_soft_reset;
DRM_DEBUG("\n");
radeon_do_pixcache_flush(dev_priv);
- if ((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_RV515) {
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV410) {
+ /* may need something similar for newer chips */
clock_cntl_index = RADEON_READ(RADEON_CLOCK_CNTL_INDEX);
mclk_cntl = RADEON_READ_PLL(dev, RADEON_MCLK_CNTL);
@@ -1137,33 +503,39 @@ static int radeon_do_engine_reset(struct drm_device * dev)
RADEON_FORCEON_YCLKB |
RADEON_FORCEON_MC |
RADEON_FORCEON_AIC));
+ }
- rbbm_soft_reset = RADEON_READ(RADEON_RBBM_SOFT_RESET);
-
- RADEON_WRITE(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset |
- RADEON_SOFT_RESET_CP |
- RADEON_SOFT_RESET_HI |
- RADEON_SOFT_RESET_SE |
- RADEON_SOFT_RESET_RE |
- RADEON_SOFT_RESET_PP |
- RADEON_SOFT_RESET_E2 |
- RADEON_SOFT_RESET_RB));
- RADEON_READ(RADEON_RBBM_SOFT_RESET);
- RADEON_WRITE(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset &
- ~(RADEON_SOFT_RESET_CP |
- RADEON_SOFT_RESET_HI |
- RADEON_SOFT_RESET_SE |
- RADEON_SOFT_RESET_RE |
- RADEON_SOFT_RESET_PP |
- RADEON_SOFT_RESET_E2 |
- RADEON_SOFT_RESET_RB)));
- RADEON_READ(RADEON_RBBM_SOFT_RESET);
-
+ rbbm_soft_reset = RADEON_READ(RADEON_RBBM_SOFT_RESET);
+
+ RADEON_WRITE(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset |
+ RADEON_SOFT_RESET_CP |
+ RADEON_SOFT_RESET_HI |
+ RADEON_SOFT_RESET_SE |
+ RADEON_SOFT_RESET_RE |
+ RADEON_SOFT_RESET_PP |
+ RADEON_SOFT_RESET_E2 |
+ RADEON_SOFT_RESET_RB));
+ RADEON_READ(RADEON_RBBM_SOFT_RESET);
+ RADEON_WRITE(RADEON_RBBM_SOFT_RESET, (rbbm_soft_reset &
+ ~(RADEON_SOFT_RESET_CP |
+ RADEON_SOFT_RESET_HI |
+ RADEON_SOFT_RESET_SE |
+ RADEON_SOFT_RESET_RE |
+ RADEON_SOFT_RESET_PP |
+ RADEON_SOFT_RESET_E2 |
+ RADEON_SOFT_RESET_RB)));
+ RADEON_READ(RADEON_RBBM_SOFT_RESET);
+
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV410) {
RADEON_WRITE_PLL(RADEON_MCLK_CNTL, mclk_cntl);
RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, clock_cntl_index);
RADEON_WRITE(RADEON_RBBM_SOFT_RESET, rbbm_soft_reset);
}
+ /* setup the raster pipes */
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R300)
+ radeon_init_pipes(dev_priv);
+
/* Reset the CP ring */
radeon_do_cp_reset(dev_priv);
@@ -1194,7 +566,8 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
#if __OS_HAS_AGP
if (dev_priv->flags & RADEON_IS_AGP) {
- RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
+ radeon_write_agp_base(dev_priv, dev->agp->base);
+
radeon_write_agp_location(dev_priv,
(((dev_priv->gart_vm_start - 1 +
dev_priv->gart_size) & 0xffff0000) |
@@ -1339,102 +712,70 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv)
/* Enable or disable IGP GART on the chip */
static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on)
{
- u32 temp, tmp;
-
- tmp = RADEON_READ(RADEON_AIC_CNTL);
- if (on) {
- DRM_DEBUG("programming igpgart %08X %08lX %08X\n",
- dev_priv->gart_vm_start,
- (long)dev_priv->gart_info.bus_addr,
- dev_priv->gart_size);
-
- RADEON_WRITE_IGPGART(RADEON_IGPGART_UNK_18, 0x1000);
- RADEON_WRITE_IGPGART(RADEON_IGPGART_ENABLE, 0x1);
- RADEON_WRITE_IGPGART(RADEON_IGPGART_CTRL, 0x42040800);
- RADEON_WRITE_IGPGART(RADEON_IGPGART_BASE_ADDR,
- dev_priv->gart_info.bus_addr);
-
- temp = RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_UNK_39);
- RADEON_WRITE_IGPGART(RADEON_IGPGART_UNK_39, temp);
-
- RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev_priv->gart_vm_start);
- dev_priv->gart_size = 32*1024*1024;
- radeon_write_agp_location(dev_priv,
- (((dev_priv->gart_vm_start - 1 +
- dev_priv->gart_size) & 0xffff0000) |
- (dev_priv->gart_vm_start >> 16)));
-
- temp = RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_ENABLE);
- RADEON_WRITE_IGPGART(RADEON_IGPGART_ENABLE, temp);
-
- RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH);
- RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x1);
- RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH);
- RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x0);
- }
-}
-
-/* Enable or disable RS690 GART on the chip */
-static void radeon_set_rs690gart(drm_radeon_private_t *dev_priv, int on)
-{
u32 temp;
if (on) {
- DRM_DEBUG("programming rs690 gart %08X %08lX %08X\n",
+ DRM_DEBUG("programming igp gart %08X %08lX %08X\n",
dev_priv->gart_vm_start,
(long)dev_priv->gart_info.bus_addr,
dev_priv->gart_size);
- temp = RS690_READ_MCIND(dev_priv, RS690_MC_MISC_CNTL);
- RS690_WRITE_MCIND(RS690_MC_MISC_CNTL, 0x5000);
+ temp = IGP_READ_MCIND(dev_priv, RS480_MC_MISC_CNTL);
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690)
+ IGP_WRITE_MCIND(RS480_MC_MISC_CNTL, (RS480_GART_INDEX_REG_EN |
+ RS690_BLOCK_GFX_D3_EN));
+ else
+ IGP_WRITE_MCIND(RS480_MC_MISC_CNTL, RS480_GART_INDEX_REG_EN);
- RS690_WRITE_MCIND(RS690_MC_AGP_SIZE,
- RS690_MC_GART_EN | RS690_MC_AGP_SIZE_32MB);
+ IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN |
+ RS480_VA_SIZE_32MB));
- temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_FEATURE_ID);
- RS690_WRITE_MCIND(RS690_MC_GART_FEATURE_ID, 0x42040800);
+ temp = IGP_READ_MCIND(dev_priv, RS480_GART_FEATURE_ID);
+ IGP_WRITE_MCIND(RS480_GART_FEATURE_ID, (RS480_HANG_EN |
+ RS480_TLB_ENABLE |
+ RS480_GTW_LAC_EN |
+ RS480_1LEVEL_GART));
- RS690_WRITE_MCIND(RS690_MC_GART_BASE,
- dev_priv->gart_info.bus_addr);
+ temp = dev_priv->gart_info.bus_addr & 0xfffff000;
+ temp |= (upper_32_bits(dev_priv->gart_info.bus_addr) & 0xff) << 4;
+ IGP_WRITE_MCIND(RS480_GART_BASE, temp);
- temp = RS690_READ_MCIND(dev_priv, RS690_MC_AGP_MODE_CONTROL);
- RS690_WRITE_MCIND(RS690_MC_AGP_MODE_CONTROL, 0x01400000);
+ temp = IGP_READ_MCIND(dev_priv, RS480_AGP_MODE_CNTL);
+ IGP_WRITE_MCIND(RS480_AGP_MODE_CNTL, ((1 << RS480_REQ_TYPE_SNOOP_SHIFT) |
+ RS480_REQ_TYPE_SNOOP_DIS));
- RS690_WRITE_MCIND(RS690_MC_AGP_BASE,
- (unsigned int)dev_priv->gart_vm_start);
+ radeon_write_agp_base(dev_priv, dev_priv->gart_vm_start);
dev_priv->gart_size = 32*1024*1024;
temp = (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) &
0xffff0000) | (dev_priv->gart_vm_start >> 16));
- RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, temp);
+ radeon_write_agp_location(dev_priv, temp);
- temp = RS690_READ_MCIND(dev_priv, RS690_MC_AGP_SIZE);
- RS690_WRITE_MCIND(RS690_MC_AGP_SIZE,
- RS690_MC_GART_EN | RS690_MC_AGP_SIZE_32MB);
+ temp = IGP_READ_MCIND(dev_priv, RS480_AGP_ADDRESS_SPACE_SIZE);
+ IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN |
+ RS480_VA_SIZE_32MB));
do {
- temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_CACHE_CNTL);
- if ((temp & RS690_MC_GART_CLEAR_STATUS) ==
- RS690_MC_GART_CLEAR_DONE)
+ temp = IGP_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL);
+ if ((temp & RS480_GART_CACHE_INVALIDATE) == 0)
break;
DRM_UDELAY(1);
} while (1);
- RS690_WRITE_MCIND(RS690_MC_GART_CACHE_CNTL,
- RS690_MC_GART_CC_CLEAR);
+ IGP_WRITE_MCIND(RS480_GART_CACHE_CNTRL,
+ RS480_GART_CACHE_INVALIDATE);
+
do {
- temp = RS690_READ_MCIND(dev_priv, RS690_MC_GART_CACHE_CNTL);
- if ((temp & RS690_MC_GART_CLEAR_STATUS) ==
- RS690_MC_GART_CLEAR_DONE)
+ temp = IGP_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL);
+ if ((temp & RS480_GART_CACHE_INVALIDATE) == 0)
break;
DRM_UDELAY(1);
} while (1);
- RS690_WRITE_MCIND(RS690_MC_GART_CACHE_CNTL,
- RS690_MC_GART_CC_NO_CHANGE);
+ IGP_WRITE_MCIND(RS480_GART_CACHE_CNTRL, 0);
} else {
- RS690_WRITE_MCIND(RS690_MC_AGP_SIZE, RS690_MC_GART_DIS);
+ IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, 0);
}
}
@@ -1472,12 +813,8 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
{
u32 tmp;
- if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) {
- radeon_set_rs690gart(dev_priv, on);
- return;
- }
-
- if (dev_priv->flags & RADEON_IS_IGPGART) {
+ if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
+ (dev_priv->flags & RADEON_IS_IGPGART)) {
radeon_set_igpgart(dev_priv, on);
return;
}
@@ -1951,6 +1288,7 @@ static int radeon_do_resume_cp(struct drm_device * dev)
radeon_cp_init_ring_buffer(dev, dev_priv);
radeon_do_engine_reset(dev);
+ radeon_enable_interrupt(dev);
DRM_DEBUG("radeon_do_resume_cp() complete\n");
diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h
index aab82e121e07..73ff51f12311 100644
--- a/drivers/char/drm/radeon_drm.h
+++ b/drivers/char/drm/radeon_drm.h
@@ -240,6 +240,7 @@ typedef union {
# define R300_NEW_WAIT_2D_2D_CLEAN_3D_3D_CLEAN 0x8
#define R300_CMD_SCRATCH 8
+#define R300_CMD_R500FP 9
typedef union {
unsigned int u;
@@ -268,6 +269,9 @@ typedef union {
struct {
unsigned char cmd_type, reg, n_bufs, flags;
} scratch;
+ struct {
+ unsigned char cmd_type, count, adrlo, adrhi_flags;
+ } r500fp;
} drm_r300_cmd_header_t;
#define RADEON_FRONT 0x1
@@ -278,6 +282,9 @@ typedef union {
#define RADEON_USE_HIERZ 0x40000000
#define RADEON_USE_COMP_ZBUF 0x20000000
+#define R500FP_CONSTANT_TYPE (1 << 1)
+#define R500FP_CONSTANT_CLAMP (1 << 2)
+
/* Primitive types
*/
#define RADEON_POINTS 0x1
@@ -669,6 +676,7 @@ typedef struct drm_radeon_indirect {
#define RADEON_PARAM_CARD_TYPE 12
#define RADEON_PARAM_VBLANK_CRTC 13 /* VBLANK CRTC */
#define RADEON_PARAM_FB_LOCATION 14 /* FB location */
+#define RADEON_PARAM_NUM_GB_PIPES 15 /* num GB pipes */
typedef struct drm_radeon_getparam {
int param;
diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c
index a2610319624d..349ac3d3b848 100644
--- a/drivers/char/drm/radeon_drv.c
+++ b/drivers/char/drm/radeon_drv.c
@@ -59,7 +59,8 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
- DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED,
+ DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED |
+ DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2,
.dev_priv_size = sizeof(drm_radeon_buf_priv_t),
.load = radeon_driver_load,
.firstopen = radeon_driver_firstopen,
@@ -68,9 +69,8 @@ static struct drm_driver driver = {
.postclose = radeon_driver_postclose,
.lastclose = radeon_driver_lastclose,
.unload = radeon_driver_unload,
- .get_vblank_counter = radeon_get_vblank_counter,
- .enable_vblank = radeon_enable_vblank,
- .disable_vblank = radeon_disable_vblank,
+ .vblank_wait = radeon_driver_vblank_wait,
+ .vblank_wait2 = radeon_driver_vblank_wait2,
.dri_library_name = dri_library_name,
.irq_preinstall = radeon_driver_irq_preinstall,
.irq_postinstall = radeon_driver_irq_postinstall,
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index b791420bd3d9..3f0eca957aa7 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -38,7 +38,7 @@
#define DRIVER_NAME "radeon"
#define DRIVER_DESC "ATI Radeon"
-#define DRIVER_DATE "20060524"
+#define DRIVER_DATE "20080528"
/* Interface history:
*
@@ -98,9 +98,10 @@
* 1.26- Add support for variable size PCI(E) gart aperture
* 1.27- Add support for IGP GART
* 1.28- Add support for VBL on CRTC2
+ * 1.29- R500 3D cmd buffer support
*/
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 28
+#define DRIVER_MINOR 29
#define DRIVER_PATCHLEVEL 0
/*
@@ -122,7 +123,7 @@ enum radeon_family {
CHIP_RV380,
CHIP_R420,
CHIP_RV410,
- CHIP_RS400,
+ CHIP_RS480,
CHIP_RS690,
CHIP_RV515,
CHIP_R520,
@@ -294,6 +295,7 @@ typedef struct drm_radeon_private {
int vblank_crtc;
uint32_t irq_enable_reg;
int irq_enabled;
+ uint32_t r500_disp_irq_reg;
struct radeon_surface surfaces[RADEON_MAX_SURFACES];
struct radeon_virt_surface virt_surfaces[2 * RADEON_MAX_SURFACES];
@@ -304,12 +306,11 @@ typedef struct drm_radeon_private {
u32 scratch_ages[5];
- unsigned int crtc_last_cnt;
- unsigned int crtc2_last_cnt;
-
/* starting from here on, data is preserved accross an open */
uint32_t flags; /* see radeon_chip_flags */
unsigned long fb_aper_offset;
+
+ int num_gb_pipes;
} drm_radeon_private_t;
typedef struct drm_radeon_buf_priv {
@@ -377,14 +378,15 @@ extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *
extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern void radeon_do_release(struct drm_device * dev);
-extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc);
-extern int radeon_enable_vblank(struct drm_device *dev, int crtc);
-extern void radeon_disable_vblank(struct drm_device *dev, int crtc);
-extern void radeon_do_release(struct drm_device * dev);
+extern int radeon_driver_vblank_wait(struct drm_device * dev,
+ unsigned int *sequence);
+extern int radeon_driver_vblank_wait2(struct drm_device * dev,
+ unsigned int *sequence);
extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS);
extern void radeon_driver_irq_preinstall(struct drm_device * dev);
-extern int radeon_driver_irq_postinstall(struct drm_device * dev);
+extern void radeon_driver_irq_postinstall(struct drm_device * dev);
extern void radeon_driver_irq_uninstall(struct drm_device * dev);
+extern void radeon_enable_interrupt(struct drm_device *dev);
extern int radeon_vblank_crtc_get(struct drm_device *dev);
extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value);
@@ -447,13 +449,13 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
#define RADEON_PCIE_DATA 0x0034
#define RADEON_PCIE_TX_GART_CNTL 0x10
# define RADEON_PCIE_TX_GART_EN (1 << 0)
-# define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_PASS_THRU (0<<1)
-# define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_CLAMP_LO (1<<1)
-# define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD (3<<1)
-# define RADEON_PCIE_TX_GART_MODE_32_128_CACHE (0<<3)
-# define RADEON_PCIE_TX_GART_MODE_8_4_128_CACHE (1<<3)
-# define RADEON_PCIE_TX_GART_CHK_RW_VALID_EN (1<<5)
-# define RADEON_PCIE_TX_GART_INVALIDATE_TLB (1<<8)
+# define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_PASS_THRU (0 << 1)
+# define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_CLAMP_LO (1 << 1)
+# define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD (3 << 1)
+# define RADEON_PCIE_TX_GART_MODE_32_128_CACHE (0 << 3)
+# define RADEON_PCIE_TX_GART_MODE_8_4_128_CACHE (1 << 3)
+# define RADEON_PCIE_TX_GART_CHK_RW_VALID_EN (1 << 5)
+# define RADEON_PCIE_TX_GART_INVALIDATE_TLB (1 << 8)
#define RADEON_PCIE_TX_DISCARD_RD_ADDR_LO 0x11
#define RADEON_PCIE_TX_DISCARD_RD_ADDR_HI 0x12
#define RADEON_PCIE_TX_GART_BASE 0x13
@@ -462,14 +464,9 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
#define RADEON_PCIE_TX_GART_END_LO 0x16
#define RADEON_PCIE_TX_GART_END_HI 0x17
-#define RADEON_IGPGART_INDEX 0x168
-#define RADEON_IGPGART_DATA 0x16c
-#define RADEON_IGPGART_UNK_18 0x18
-#define RADEON_IGPGART_CTRL 0x2b
-#define RADEON_IGPGART_BASE_ADDR 0x2c
-#define RADEON_IGPGART_FLUSH 0x2e
-#define RADEON_IGPGART_ENABLE 0x38
-#define RADEON_IGPGART_UNK_39 0x39
+#define RS480_NB_MC_INDEX 0x168
+# define RS480_NB_MC_IND_WR_EN (1 << 8)
+#define RS480_NB_MC_DATA 0x16c
#define RS690_MC_INDEX 0x78
# define RS690_MC_INDEX_MASK 0x1ff
@@ -477,45 +474,91 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
# define RS690_MC_INDEX_WR_ACK 0x7f
#define RS690_MC_DATA 0x7c
-#define RS690_MC_MISC_CNTL 0x18
-#define RS690_MC_GART_FEATURE_ID 0x2b
-#define RS690_MC_GART_BASE 0x2c
-#define RS690_MC_GART_CACHE_CNTL 0x2e
-# define RS690_MC_GART_CC_NO_CHANGE 0x0
-# define RS690_MC_GART_CC_CLEAR 0x1
-# define RS690_MC_GART_CLEAR_STATUS (1 << 1)
-# define RS690_MC_GART_CLEAR_DONE (0 << 1)
-# define RS690_MC_GART_CLEAR_PENDING (1 << 1)
-#define RS690_MC_AGP_SIZE 0x38
-# define RS690_MC_GART_DIS 0x0
-# define RS690_MC_GART_EN 0x1
-# define RS690_MC_AGP_SIZE_32MB (0 << 1)
-# define RS690_MC_AGP_SIZE_64MB (1 << 1)
-# define RS690_MC_AGP_SIZE_128MB (2 << 1)
-# define RS690_MC_AGP_SIZE_256MB (3 << 1)
-# define RS690_MC_AGP_SIZE_512MB (4 << 1)
-# define RS690_MC_AGP_SIZE_1GB (5 << 1)
-# define RS690_MC_AGP_SIZE_2GB (6 << 1)
-#define RS690_MC_AGP_MODE_CONTROL 0x39
+/* MC indirect registers */
+#define RS480_MC_MISC_CNTL 0x18
+# define RS480_DISABLE_GTW (1 << 1)
+/* switch between MCIND GART and MM GART registers. 0 = mmgart, 1 = mcind gart */
+# define RS480_GART_INDEX_REG_EN (1 << 12)
+# define RS690_BLOCK_GFX_D3_EN (1 << 14)
+#define RS480_K8_FB_LOCATION 0x1e
+#define RS480_GART_FEATURE_ID 0x2b
+# define RS480_HANG_EN (1 << 11)
+# define RS480_TLB_ENABLE (1 << 18)
+# define RS480_P2P_ENABLE (1 << 19)
+# define RS480_GTW_LAC_EN (1 << 25)
+# define RS480_2LEVEL_GART (0 << 30)
+# define RS480_1LEVEL_GART (1 << 30)
+# define RS480_PDC_EN (1 << 31)
+#define RS480_GART_BASE 0x2c
+#define RS480_GART_CACHE_CNTRL 0x2e
+# define RS480_GART_CACHE_INVALIDATE (1 << 0) /* wait for it to clear */
+#define RS480_AGP_ADDRESS_SPACE_SIZE 0x38
+# define RS480_GART_EN (1 << 0)
+# define RS480_VA_SIZE_32MB (0 << 1)
+# define RS480_VA_SIZE_64MB (1 << 1)
+# define RS480_VA_SIZE_128MB (2 << 1)
+# define RS480_VA_SIZE_256MB (3 << 1)
+# define RS480_VA_SIZE_512MB (4 << 1)
+# define RS480_VA_SIZE_1GB (5 << 1)
+# define RS480_VA_SIZE_2GB (6 << 1)
+#define RS480_AGP_MODE_CNTL 0x39
+# define RS480_POST_GART_Q_SIZE (1 << 18)
+# define RS480_NONGART_SNOOP (1 << 19)
+# define RS480_AGP_RD_BUF_SIZE (1 << 20)
+# define RS480_REQ_TYPE_SNOOP_SHIFT 22
+# define RS480_REQ_TYPE_SNOOP_MASK 0x3
+# define RS480_REQ_TYPE_SNOOP_DIS (1 << 24)
+#define RS480_MC_MISC_UMA_CNTL 0x5f
+#define RS480_MC_MCLK_CNTL 0x7a
+#define RS480_MC_UMA_DUALCH_CNTL 0x86
+
#define RS690_MC_FB_LOCATION 0x100
#define RS690_MC_AGP_LOCATION 0x101
#define RS690_MC_AGP_BASE 0x102
+#define RS690_MC_AGP_BASE_2 0x103
#define R520_MC_IND_INDEX 0x70
-#define R520_MC_IND_WR_EN (1<<24)
+#define R520_MC_IND_WR_EN (1 << 24)
#define R520_MC_IND_DATA 0x74
#define RV515_MC_FB_LOCATION 0x01
#define RV515_MC_AGP_LOCATION 0x02
+#define RV515_MC_AGP_BASE 0x03
+#define RV515_MC_AGP_BASE_2 0x04
#define R520_MC_FB_LOCATION 0x04
#define R520_MC_AGP_LOCATION 0x05
+#define R520_MC_AGP_BASE 0x06
+#define R520_MC_AGP_BASE_2 0x07
#define RADEON_MPP_TB_CONFIG 0x01c0
#define RADEON_MEM_CNTL 0x0140
#define RADEON_MEM_SDRAM_MODE_REG 0x0158
+#define RADEON_AGP_BASE_2 0x015c /* r200+ only */
+#define RS480_AGP_BASE_2 0x0164
#define RADEON_AGP_BASE 0x0170
+/* pipe config regs */
+#define R400_GB_PIPE_SELECT 0x402c
+#define R500_DYN_SCLK_PWMEM_PIPE 0x000d /* PLL */
+#define R500_SU_REG_DEST 0x42c8
+#define R300_GB_TILE_CONFIG 0x4018
+# define R300_ENABLE_TILING (1 << 0)
+# define R300_PIPE_COUNT_RV350 (0 << 1)
+# define R300_PIPE_COUNT_R300 (3 << 1)
+# define R300_PIPE_COUNT_R420_3P (6 << 1)
+# define R300_PIPE_COUNT_R420 (7 << 1)
+# define R300_TILE_SIZE_8 (0 << 4)
+# define R300_TILE_SIZE_16 (1 << 4)
+# define R300_TILE_SIZE_32 (2 << 4)
+# define R300_SUBPIXEL_1_12 (0 << 16)
+# define R300_SUBPIXEL_1_16 (1 << 16)
+#define R300_DST_PIPE_CONFIG 0x170c
+# define R300_PIPE_AUTO_CONFIG (1 << 31)
+#define R300_RB2D_DSTCACHE_MODE 0x3428
+# define R300_DC_AUTOFLUSH_ENABLE (1 << 8)
+# define R300_DC_DC_DISABLE_IGNORE_PE (1 << 17)
+
#define RADEON_RB3D_COLOROFFSET 0x1c40
#define RADEON_RB3D_COLORPITCH 0x1c48
@@ -561,12 +604,6 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
? DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(x) ) \
: RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) )
-#define RADEON_CRTC_CRNT_FRAME 0x0214
-#define RADEON_CRTC2_CRNT_FRAME 0x0314
-
-#define RADEON_CRTC_STATUS 0x005c
-#define RADEON_CRTC2_STATUS 0x03fc
-
#define RADEON_GEN_INT_CNTL 0x0040
# define RADEON_CRTC_VBLANK_MASK (1 << 0)
# define RADEON_CRTC2_VBLANK_MASK (1 << 9)
@@ -625,11 +662,12 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
#define RADEON_PP_TXFILTER_1 0x1c6c
#define RADEON_PP_TXFILTER_2 0x1c84
-#define RADEON_RB2D_DSTCACHE_CTLSTAT 0x342c
-# define RADEON_RB2D_DC_FLUSH (3 << 0)
-# define RADEON_RB2D_DC_FREE (3 << 2)
-# define RADEON_RB2D_DC_FLUSH_ALL 0xf
-# define RADEON_RB2D_DC_BUSY (1 << 31)
+#define R300_RB2D_DSTCACHE_CTLSTAT 0x342c /* use R300_DSTCACHE_CTLSTAT */
+#define R300_DSTCACHE_CTLSTAT 0x1714
+# define R300_RB2D_DC_FLUSH (3 << 0)
+# define R300_RB2D_DC_FREE (3 << 2)
+# define R300_RB2D_DC_FLUSH_ALL 0xf
+# define R300_RB2D_DC_BUSY (1 << 31)
#define RADEON_RB3D_CNTL 0x1c3c
# define RADEON_ALPHA_BLEND_ENABLE (1 << 0)
# define RADEON_PLANE_MASK_ENABLE (1 << 1)
@@ -652,11 +690,18 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
# define RADEON_RB3D_ZC_FREE (1 << 2)
# define RADEON_RB3D_ZC_FLUSH_ALL 0x5
# define RADEON_RB3D_ZC_BUSY (1 << 31)
+#define R300_ZB_ZCACHE_CTLSTAT 0x4f18
+# define R300_ZC_FLUSH (1 << 0)
+# define R300_ZC_FREE (1 << 1)
+# define R300_ZC_FLUSH_ALL 0x3
+# define R300_ZC_BUSY (1 << 31)
#define RADEON_RB3D_DSTCACHE_CTLSTAT 0x325c
# define RADEON_RB3D_DC_FLUSH (3 << 0)
# define RADEON_RB3D_DC_FREE (3 << 2)
# define RADEON_RB3D_DC_FLUSH_ALL 0xf
# define RADEON_RB3D_DC_BUSY (1 << 31)
+#define R300_RB3D_DSTCACHE_CTLSTAT 0x4e4c
+# define R300_RB3D_DC_FINISH (1 << 4)
#define RADEON_RB3D_ZSTENCILCNTL 0x1c2c
# define RADEON_Z_TEST_MASK (7 << 4)
# define RADEON_Z_TEST_ALWAYS (7 << 4)
@@ -1066,6 +1111,31 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
#define R200_VAP_PVS_CNTL_1 0x22D0
+#define R500_D1CRTC_STATUS 0x609c
+#define R500_D2CRTC_STATUS 0x689c
+#define R500_CRTC_V_BLANK (1<<0)
+
+#define R500_D1CRTC_FRAME_COUNT 0x60a4
+#define R500_D2CRTC_FRAME_COUNT 0x68a4
+
+#define R500_D1MODE_V_COUNTER 0x6530
+#define R500_D2MODE_V_COUNTER 0x6d30
+
+#define R500_D1MODE_VBLANK_STATUS 0x6534
+#define R500_D2MODE_VBLANK_STATUS 0x6d34
+#define R500_VBLANK_OCCURED (1<<0)
+#define R500_VBLANK_ACK (1<<4)
+#define R500_VBLANK_STAT (1<<12)
+#define R500_VBLANK_INT (1<<16)
+
+#define R500_DxMODE_INT_MASK 0x6540
+#define R500_D1MODE_INT_MASK (1<<0)
+#define R500_D2MODE_INT_MASK (1<<8)
+
+#define R500_DISP_INTERRUPT_STATUS 0x7edc
+#define R500_D1_VBLANK_INTERRUPT (1 << 4)
+#define R500_D2_VBLANK_INTERRUPT (1 << 5)
+
/* Constants */
#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */
@@ -1087,42 +1157,50 @@ extern int r300_do_cp_cmdbuf(struct drm_device * dev,
#define RADEON_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) )
#define RADEON_WRITE8(reg,val) DRM_WRITE8( dev_priv->mmio, (reg), (val) )
-#define RADEON_WRITE_PLL( addr, val ) \
+#define RADEON_WRITE_PLL(addr, val) \
do { \
- RADEON_WRITE8( RADEON_CLOCK_CNTL_INDEX, \
+ RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, \
((addr) & 0x1f) | RADEON_PLL_WR_EN ); \
- RADEON_WRITE( RADEON_CLOCK_CNTL_DATA, (val) ); \
+ RADEON_WRITE(RADEON_CLOCK_CNTL_DATA, (val)); \
} while (0)
-#define RADEON_WRITE_IGPGART( addr, val ) \
+#define RADEON_WRITE_PCIE(addr, val) \
do { \
- RADEON_WRITE( RADEON_IGPGART_INDEX, \
- ((addr) & 0x7f) | (1 << 8)); \
- RADEON_WRITE( RADEON_IGPGART_DATA, (val) ); \
- RADEON_WRITE( RADEON_IGPGART_INDEX, 0x7f ); \
+ RADEON_WRITE8(RADEON_PCIE_INDEX, \
+ ((addr) & 0xff)); \
+ RADEON_WRITE(RADEON_PCIE_DATA, (val)); \
} while (0)
-#define RADEON_WRITE_PCIE( addr, val ) \
-do { \
- RADEON_WRITE8( RADEON_PCIE_INDEX, \
- ((addr) & 0xff)); \
- RADEON_WRITE( RADEON_PCIE_DATA, (val) ); \
+#define R500_WRITE_MCIND(addr, val) \
+do { \
+ RADEON_WRITE(R520_MC_IND_INDEX, 0xff0000 | ((addr) & 0xff)); \
+ RADEON_WRITE(R520_MC_IND_DATA, (val)); \
+ RADEON_WRITE(R520_MC_IND_INDEX, 0); \
} while (0)
-#define RADEON_WRITE_MCIND( addr, val ) \
- do { \
- RADEON_WRITE(R520_MC_IND_INDEX, 0xff0000 | ((addr) & 0xff)); \
- RADEON_WRITE(R520_MC_IND_DATA, (val)); \
- RADEON_WRITE(R520_MC_IND_INDEX, 0); \
- } while (0)
+#define RS480_WRITE_MCIND(addr, val) \
+do { \
+ RADEON_WRITE(RS480_NB_MC_INDEX, \
+ ((addr) & 0xff) | RS480_NB_MC_IND_WR_EN); \
+ RADEON_WRITE(RS480_NB_MC_DATA, (val)); \
+ RADEON_WRITE(RS480_NB_MC_INDEX, 0xff); \
+} while (0)
-#define RS690_WRITE_MCIND( addr, val ) \
+#define RS690_WRITE_MCIND(addr, val) \
do { \
RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_WR_EN | ((addr) & RS690_MC_INDEX_MASK)); \
RADEON_WRITE(RS690_MC_DATA, val); \
RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK); \
} while (0)
+#define IGP_WRITE_MCIND(addr, val) \
+do { \
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) \
+ RS690_WRITE_MCIND(addr, val); \
+ else \
+ RS480_WRITE_MCIND(addr, val); \
+} while (0)
+
#define CP_PACKET0( reg, n ) \
(RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2))
#define CP_PACKET0_TABLE( reg, n ) \
@@ -1163,23 +1241,43 @@ do { \
} while (0)
#define RADEON_FLUSH_CACHE() do { \
- OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \
- OUT_RING( RADEON_RB3D_DC_FLUSH ); \
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) { \
+ OUT_RING(CP_PACKET0(RADEON_RB3D_DSTCACHE_CTLSTAT, 0)); \
+ OUT_RING(RADEON_RB3D_DC_FLUSH); \
+ } else { \
+ OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); \
+ OUT_RING(RADEON_RB3D_DC_FLUSH); \
+ } \
} while (0)
#define RADEON_PURGE_CACHE() do { \
- OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \
- OUT_RING( RADEON_RB3D_DC_FLUSH_ALL ); \
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) { \
+ OUT_RING(CP_PACKET0(RADEON_RB3D_DSTCACHE_CTLSTAT, 0)); \
+ OUT_RING(RADEON_RB3D_DC_FLUSH_ALL); \
+ } else { \
+ OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); \
+ OUT_RING(RADEON_RB3D_DC_FLUSH_ALL); \
+ } \
} while (0)
#define RADEON_FLUSH_ZCACHE() do { \
- OUT_RING( CP_PACKET0( RADEON_RB3D_ZCACHE_CTLSTAT, 0 ) ); \
- OUT_RING( RADEON_RB3D_ZC_FLUSH ); \
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) { \
+ OUT_RING(CP_PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0)); \
+ OUT_RING(RADEON_RB3D_ZC_FLUSH); \
+ } else { \
+ OUT_RING(CP_PACKET0(R300_ZB_ZCACHE_CTLSTAT, 0)); \
+ OUT_RING(R300_ZC_FLUSH); \
+ } \
} while (0)
#define RADEON_PURGE_ZCACHE() do { \
- OUT_RING( CP_PACKET0( RADEON_RB3D_ZCACHE_CTLSTAT, 0 ) ); \
- OUT_RING( RADEON_RB3D_ZC_FLUSH_ALL ); \
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) { \
+ OUT_RING(CP_PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0)); \
+ OUT_RING(RADEON_RB3D_ZC_FLUSH_ALL); \
+ } else { \
+ OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); \
+ OUT_RING(R300_ZC_FLUSH_ALL); \
+ } \
} while (0)
/* ================================================================
diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c
index 507d6b747a13..ee40d197deb7 100644
--- a/drivers/char/drm/radeon_irq.c
+++ b/drivers/char/drm/radeon_irq.c
@@ -35,61 +35,12 @@
#include "radeon_drm.h"
#include "radeon_drv.h"
-static void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state)
+static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv,
+ u32 mask)
{
- drm_radeon_private_t *dev_priv = dev->dev_private;
-
- if (state)
- dev_priv->irq_enable_reg |= mask;
- else
- dev_priv->irq_enable_reg &= ~mask;
-
- RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
-}
-
-int radeon_enable_vblank(struct drm_device *dev, int crtc)
-{
- switch (crtc) {
- case 0:
- radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 1);
- break;
- case 1:
- radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 1);
- break;
- default:
- DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
- crtc);
- return EINVAL;
- }
-
- return 0;
-}
-
-void radeon_disable_vblank(struct drm_device *dev, int crtc)
-{
- switch (crtc) {
- case 0:
- radeon_irq_set_state(dev, RADEON_CRTC_VBLANK_MASK, 0);
- break;
- case 1:
- radeon_irq_set_state(dev, RADEON_CRTC2_VBLANK_MASK, 0);
- break;
- default:
- DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
- crtc);
- break;
- }
-}
-
-static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv)
-{
- u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) &
- (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT |
- RADEON_CRTC2_VBLANK_STAT);
-
+ u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask;
if (irqs)
RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
-
return irqs;
}
@@ -121,21 +72,39 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
/* Only consider the bits we're interested in - others could be used
* outside the DRM
*/
- stat = radeon_acknowledge_irqs(dev_priv);
+ stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
+ RADEON_CRTC_VBLANK_STAT |
+ RADEON_CRTC2_VBLANK_STAT));
if (!stat)
return IRQ_NONE;
stat &= dev_priv->irq_enable_reg;
/* SW interrupt */
- if (stat & RADEON_SW_INT_TEST)
+ if (stat & RADEON_SW_INT_TEST) {
DRM_WAKEUP(&dev_priv->swi_queue);
+ }
/* VBLANK interrupt */
- if (stat & RADEON_CRTC_VBLANK_STAT)
- drm_handle_vblank(dev, 0);
- if (stat & RADEON_CRTC2_VBLANK_STAT)
- drm_handle_vblank(dev, 1);
+ if (stat & (RADEON_CRTC_VBLANK_STAT|RADEON_CRTC2_VBLANK_STAT)) {
+ int vblank_crtc = dev_priv->vblank_crtc;
+
+ if ((vblank_crtc &
+ (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) ==
+ (DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) {
+ if (stat & RADEON_CRTC_VBLANK_STAT)
+ atomic_inc(&dev->vbl_received);
+ if (stat & RADEON_CRTC2_VBLANK_STAT)
+ atomic_inc(&dev->vbl_received2);
+ } else if (((stat & RADEON_CRTC_VBLANK_STAT) &&
+ (vblank_crtc & DRM_RADEON_VBLANK_CRTC1)) ||
+ ((stat & RADEON_CRTC2_VBLANK_STAT) &&
+ (vblank_crtc & DRM_RADEON_VBLANK_CRTC2)))
+ atomic_inc(&dev->vbl_received);
+
+ DRM_WAKEUP(&dev->vbl_queue);
+ drm_vbl_send_signals(dev);
+ }
return IRQ_HANDLED;
}
@@ -175,27 +144,54 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr)
return ret;
}
-u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
+static int radeon_driver_vblank_do_wait(struct drm_device * dev,
+ unsigned int *sequence, int crtc)
{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- u32 crtc_cnt_reg, crtc_status_reg;
-
+ drm_radeon_private_t *dev_priv =
+ (drm_radeon_private_t *) dev->dev_private;
+ unsigned int cur_vblank;
+ int ret = 0;
+ int ack = 0;
+ atomic_t *counter;
if (!dev_priv) {
DRM_ERROR("called with no initialization\n");
return -EINVAL;
}
- if (crtc == 0) {
- crtc_cnt_reg = RADEON_CRTC_CRNT_FRAME;
- crtc_status_reg = RADEON_CRTC_STATUS;
- } else if (crtc == 1) {
- crtc_cnt_reg = RADEON_CRTC2_CRNT_FRAME;
- crtc_status_reg = RADEON_CRTC2_STATUS;
- } else {
+ if (crtc == DRM_RADEON_VBLANK_CRTC1) {
+ counter = &dev->vbl_received;
+ ack |= RADEON_CRTC_VBLANK_STAT;
+ } else if (crtc == DRM_RADEON_VBLANK_CRTC2) {
+ counter = &dev->vbl_received2;
+ ack |= RADEON_CRTC2_VBLANK_STAT;
+ } else
return -EINVAL;
- }
- return RADEON_READ(crtc_cnt_reg) + (RADEON_READ(crtc_status_reg) & 1);
+ radeon_acknowledge_irqs(dev_priv, ack);
+
+ dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
+
+ /* Assume that the user has missed the current sequence number
+ * by about a day rather than she wants to wait for years
+ * using vertical blanks...
+ */
+ DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
+ (((cur_vblank = atomic_read(counter))
+ - *sequence) <= (1 << 23)));
+
+ *sequence = cur_vblank;
+
+ return ret;
+}
+
+int radeon_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
+{
+ return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC1);
+}
+
+int radeon_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
+{
+ return radeon_driver_vblank_do_wait(dev, sequence, DRM_RADEON_VBLANK_CRTC2);
}
/* Needs the lock as it touches the ring.
@@ -238,6 +234,21 @@ int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_pr
return radeon_wait_irq(dev, irqwait->irq_seq);
}
+void radeon_enable_interrupt(struct drm_device *dev)
+{
+ drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
+
+ dev_priv->irq_enable_reg = RADEON_SW_INT_ENABLE;
+ if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC1)
+ dev_priv->irq_enable_reg |= RADEON_CRTC_VBLANK_MASK;
+
+ if (dev_priv->vblank_crtc & DRM_RADEON_VBLANK_CRTC2)
+ dev_priv->irq_enable_reg |= RADEON_CRTC2_VBLANK_MASK;
+
+ RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
+ dev_priv->irq_enabled = 1;
+}
+
/* drm_dma.h hooks
*/
void radeon_driver_irq_preinstall(struct drm_device * dev)
@@ -249,27 +260,20 @@ void radeon_driver_irq_preinstall(struct drm_device * dev)
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
/* Clear bits if they're already high */
- radeon_acknowledge_irqs(dev_priv);
+ radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
+ RADEON_CRTC_VBLANK_STAT |
+ RADEON_CRTC2_VBLANK_STAT));
}
-int radeon_driver_irq_postinstall(struct drm_device * dev)
+void radeon_driver_irq_postinstall(struct drm_device * dev)
{
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
- int ret;
atomic_set(&dev_priv->swi_emitted, 0);
DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
- ret = drm_vblank_init(dev, 2);
- if (ret)
- return ret;
-
- dev->max_vblank_count = 0x001fffff;
-
- radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
-
- return 0;
+ radeon_enable_interrupt(dev);
}
void radeon_driver_irq_uninstall(struct drm_device * dev)
@@ -311,5 +315,6 @@ int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value)
return -EINVAL;
}
dev_priv->vblank_crtc = (unsigned int)value;
+ radeon_enable_interrupt(dev);
return 0;
}
diff --git a/drivers/char/drm/radeon_microcode.h b/drivers/char/drm/radeon_microcode.h
new file mode 100644
index 000000000000..a348c9e7db1c
--- /dev/null
+++ b/drivers/char/drm/radeon_microcode.h
@@ -0,0 +1,1844 @@
+/*
+ * Copyright 2007 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef RADEON_MICROCODE_H
+#define RADEON_MICROCODE_H
+
+/* production radeon ucode r1xx-r6xx */
+static const u32 R100_cp_microcode[][2] = {
+ { 0x21007000, 0000000000 },
+ { 0x20007000, 0000000000 },
+ { 0x000000b4, 0x00000004 },
+ { 0x000000b8, 0x00000004 },
+ { 0x6f5b4d4c, 0000000000 },
+ { 0x4c4c427f, 0000000000 },
+ { 0x5b568a92, 0000000000 },
+ { 0x4ca09c6d, 0000000000 },
+ { 0xad4c4c4c, 0000000000 },
+ { 0x4ce1af3d, 0000000000 },
+ { 0xd8afafaf, 0000000000 },
+ { 0xd64c4cdc, 0000000000 },
+ { 0x4cd10d10, 0000000000 },
+ { 0x000f0000, 0x00000016 },
+ { 0x362f242d, 0000000000 },
+ { 0x00000012, 0x00000004 },
+ { 0x000f0000, 0x00000016 },
+ { 0x362f282d, 0000000000 },
+ { 0x000380e7, 0x00000002 },
+ { 0x04002c97, 0x00000002 },
+ { 0x000f0001, 0x00000016 },
+ { 0x333a3730, 0000000000 },
+ { 0x000077ef, 0x00000002 },
+ { 0x00061000, 0x00000002 },
+ { 0x00000021, 0x0000001a },
+ { 0x00004000, 0x0000001e },
+ { 0x00061000, 0x00000002 },
+ { 0x00000021, 0x0000001a },
+ { 0x00004000, 0x0000001e },
+ { 0x00061000, 0x00000002 },
+ { 0x00000021, 0x0000001a },
+ { 0x00004000, 0x0000001e },
+ { 0x00000017, 0x00000004 },
+ { 0x0003802b, 0x00000002 },
+ { 0x040067e0, 0x00000002 },
+ { 0x00000017, 0x00000004 },
+ { 0x000077e0, 0x00000002 },
+ { 0x00065000, 0x00000002 },
+ { 0x000037e1, 0x00000002 },
+ { 0x040067e1, 0x00000006 },
+ { 0x000077e0, 0x00000002 },
+ { 0x000077e1, 0x00000002 },
+ { 0x000077e1, 0x00000006 },
+ { 0xffffffff, 0000000000 },
+ { 0x10000000, 0000000000 },
+ { 0x0003802b, 0x00000002 },
+ { 0x040067e0, 0x00000006 },
+ { 0x00007675, 0x00000002 },
+ { 0x00007676, 0x00000002 },
+ { 0x00007677, 0x00000002 },
+ { 0x00007678, 0x00000006 },
+ { 0x0003802c, 0x00000002 },
+ { 0x04002676, 0x00000002 },
+ { 0x00007677, 0x00000002 },
+ { 0x00007678, 0x00000006 },
+ { 0x0000002f, 0x00000018 },
+ { 0x0000002f, 0x00000018 },
+ { 0000000000, 0x00000006 },
+ { 0x00000030, 0x00000018 },
+ { 0x00000030, 0x00000018 },
+ { 0000000000, 0x00000006 },
+ { 0x01605000, 0x00000002 },
+ { 0x00065000, 0x00000002 },
+ { 0x00098000, 0x00000002 },
+ { 0x00061000, 0x00000002 },
+ { 0x64c0603e, 0x00000004 },
+ { 0x000380e6, 0x00000002 },
+ { 0x040025c5, 0x00000002 },
+ { 0x00080000, 0x00000016 },
+ { 0000000000, 0000000000 },
+ { 0x0400251d, 0x00000002 },
+ { 0x00007580, 0x00000002 },
+ { 0x00067581, 0x00000002 },
+ { 0x04002580, 0x00000002 },
+ { 0x00067581, 0x00000002 },
+ { 0x00000049, 0x00000004 },
+ { 0x00005000, 0000000000 },
+ { 0x000380e6, 0x00000002 },
+ { 0x040025c5, 0x00000002 },
+ { 0x00061000, 0x00000002 },
+ { 0x0000750e, 0x00000002 },
+ { 0x00019000, 0x00000002 },
+ { 0x00011055, 0x00000014 },
+ { 0x00000055, 0x00000012 },
+ { 0x0400250f, 0x00000002 },
+ { 0x0000504f, 0x00000004 },
+ { 0x000380e6, 0x00000002 },
+ { 0x040025c5, 0x00000002 },
+ { 0x00007565, 0x00000002 },
+ { 0x00007566, 0x00000002 },
+ { 0x00000058, 0x00000004 },
+ { 0x000380e6, 0x00000002 },
+ { 0x040025c5, 0x00000002 },
+ { 0x01e655b4, 0x00000002 },
+ { 0x4401b0e4, 0x00000002 },
+ { 0x01c110e4, 0x00000002 },
+ { 0x26667066, 0x00000018 },
+ { 0x040c2565, 0x00000002 },
+ { 0x00000066, 0x00000018 },
+ { 0x04002564, 0x00000002 },
+ { 0x00007566, 0x00000002 },
+ { 0x0000005d, 0x00000004 },
+ { 0x00401069, 0x00000008 },
+ { 0x00101000, 0x00000002 },
+ { 0x000d80ff, 0x00000002 },
+ { 0x0080006c, 0x00000008 },
+ { 0x000f9000, 0x00000002 },
+ { 0x000e00ff, 0x00000002 },
+ { 0000000000, 0x00000006 },
+ { 0x0000008f, 0x00000018 },
+ { 0x0000005b, 0x00000004 },
+ { 0x000380e6, 0x00000002 },
+ { 0x040025c5, 0x00000002 },
+ { 0x00007576, 0x00000002 },
+ { 0x00065000, 0x00000002 },
+ { 0x00009000, 0x00000002 },
+ { 0x00041000, 0x00000002 },
+ { 0x0c00350e, 0x00000002 },
+ { 0x00049000, 0x00000002 },
+ { 0x00051000, 0x00000002 },
+ { 0x01e785f8, 0x00000002 },
+ { 0x00200000, 0x00000002 },
+ { 0x0060007e, 0x0000000c },
+ { 0x00007563, 0x00000002 },
+ { 0x006075f0, 0x00000021 },
+ { 0x20007073, 0x00000004 },
+ { 0x00005073, 0x00000004 },
+ { 0x000380e6, 0x00000002 },
+ { 0x040025c5, 0x00000002 },
+ { 0x00007576, 0x00000002 },
+ { 0x00007577, 0x00000002 },
+ { 0x0000750e, 0x00000002 },
+ { 0x0000750f, 0x00000002 },
+ { 0x00a05000, 0x00000002 },
+ { 0x00600083, 0x0000000c },
+ { 0x006075f0, 0x00000021 },
+ { 0x000075f8, 0x00000002 },
+ { 0x00000083, 0x00000004 },
+ { 0x000a750e, 0x00000002 },
+ { 0x000380e6, 0x00000002 },
+ { 0x040025c5, 0x00000002 },
+ { 0x0020750f, 0x00000002 },
+ { 0x00600086, 0x00000004 },
+ { 0x00007570, 0x00000002 },
+ { 0x00007571, 0x00000002 },
+ { 0x00007572, 0x00000006 },
+ { 0x000380e6, 0x00000002 },
+ { 0x040025c5, 0x00000002 },
+ { 0x00005000, 0x00000002 },
+ { 0x00a05000, 0x00000002 },
+ { 0x00007568, 0x00000002 },
+ { 0x00061000, 0x00000002 },
+ { 0x00000095, 0x0000000c },
+ { 0x00058000, 0x00000002 },
+ { 0x0c607562, 0x00000002 },
+ { 0x00000097, 0x00000004 },
+ { 0x000380e6, 0x00000002 },
+ { 0x040025c5, 0x00000002 },
+ { 0x00600096, 0x00000004 },
+ { 0x400070e5, 0000000000 },
+ { 0x000380e6, 0x00000002 },
+ { 0x040025c5, 0x00000002 },
+ { 0x000380e5, 0x00000002 },
+ { 0x000000a8, 0x0000001c },
+ { 0x000650aa, 0x00000018 },
+ { 0x040025bb, 0x00000002 },
+ { 0x000610ab, 0x00000018 },
+ { 0x040075bc, 0000000000 },
+ { 0x000075bb, 0x00000002 },
+ { 0x000075bc, 0000000000 },
+ { 0x00090000, 0x00000006 },
+ { 0x00090000, 0x00000002 },
+ { 0x000d8002, 0x00000006 },
+ { 0x00007832, 0x00000002 },
+ { 0x00005000, 0x00000002 },
+ { 0x000380e7, 0x00000002 },
+ { 0x04002c97, 0x00000002 },
+ { 0x00007820, 0x00000002 },
+ { 0x00007821, 0x00000002 },
+ { 0x00007800, 0000000000 },
+ { 0x01200000, 0x00000002 },
+ { 0x20077000, 0x00000002 },
+ { 0x01200000, 0x00000002 },
+ { 0x20007000, 0x00000002 },
+ { 0x00061000, 0x00000002 },
+ { 0x0120751b, 0x00000002 },
+ { 0x8040750a, 0x00000002 },
+ { 0x8040750b, 0x00000002 },
+ { 0x00110000, 0x00000002 },
+ { 0x000380e5, 0x00000002 },
+ { 0x000000c6, 0x0000001c },
+ { 0x000610ab, 0x00000018 },
+ { 0x844075bd, 0x00000002 },
+ { 0x000610aa, 0x00000018 },
+ { 0x840075bb, 0x00000002 },
+ { 0x000610ab, 0x00000018 },
+ { 0x844075bc, 0x00000002 },
+ { 0x000000c9, 0x00000004 },
+ { 0x804075bd, 0x00000002 },
+ { 0x800075bb, 0x00000002 },
+ { 0x804075bc, 0x00000002 },
+ { 0x00108000, 0x00000002 },
+ { 0x01400000, 0x00000002 },
+ { 0x006000cd, 0x0000000c },
+ { 0x20c07000, 0x00000020 },
+ { 0x000000cf, 0x00000012 },
+ { 0x00800000, 0x00000006 },
+ { 0x0080751d, 0x00000006 },
+ { 0000000000, 0000000000 },
+ { 0x0000775c, 0x00000002 },
+ { 0x00a05000, 0x00000002 },
+ { 0x00661000, 0x00000002 },
+ { 0x0460275d, 0x00000020 },
+ { 0x00004000, 0000000000 },
+ { 0x01e00830, 0x00000002 },
+ { 0x21007000, 0000000000 },
+ { 0x6464614d, 0000000000 },
+ { 0x69687420, 0000000000 },
+ { 0x00000073, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0x00005000, 0x00000002 },
+ { 0x000380d0, 0x00000002 },
+ { 0x040025e0, 0x00000002 },
+ { 0x000075e1, 0000000000 },
+ { 0x00000001, 0000000000 },
+ { 0x000380e0, 0x00000002 },
+ { 0x04002394, 0x00000002 },
+ { 0x00005000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0x00000008, 0000000000 },
+ { 0x00000004, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+};
+
+static const u32 R200_cp_microcode[][2] = {
+ { 0x21007000, 0000000000 },
+ { 0x20007000, 0000000000 },
+ { 0x000000bf, 0x00000004 },
+ { 0x000000c3, 0x00000004 },
+ { 0x7a685e5d, 0000000000 },
+ { 0x5d5d5588, 0000000000 },
+ { 0x68659197, 0000000000 },
+ { 0x5da19f78, 0000000000 },
+ { 0x5d5d5d5d, 0000000000 },
+ { 0x5dee5d50, 0000000000 },
+ { 0xf2acacac, 0000000000 },
+ { 0xe75df9e9, 0000000000 },
+ { 0xb1dd0e11, 0000000000 },
+ { 0xe2afafaf, 0000000000 },
+ { 0x000f0000, 0x00000016 },
+ { 0x452f232d, 0000000000 },
+ { 0x00000013, 0x00000004 },
+ { 0x000f0000, 0x00000016 },
+ { 0x452f272d, 0000000000 },
+ { 0x000f0001, 0x00000016 },
+ { 0x3e4d4a37, 0000000000 },
+ { 0x000077ef, 0x00000002 },
+ { 0x00061000, 0x00000002 },
+ { 0x00000020, 0x0000001a },
+ { 0x00004000, 0x0000001e },
+ { 0x00061000, 0x00000002 },
+ { 0x00000020, 0x0000001a },
+ { 0x00004000, 0x0000001e },
+ { 0x00061000, 0x00000002 },
+ { 0x00000020, 0x0000001a },
+ { 0x00004000, 0x0000001e },
+ { 0x00000016, 0x00000004 },
+ { 0x0003802a, 0x00000002 },
+ { 0x040067e0, 0x00000002 },
+ { 0x00000016, 0x00000004 },
+ { 0x000077e0, 0x00000002 },
+ { 0x00065000, 0x00000002 },
+ { 0x000037e1, 0x00000002 },
+ { 0x040067e1, 0x00000006 },
+ { 0x000077e0, 0x00000002 },
+ { 0x000077e1, 0x00000002 },
+ { 0x000077e1, 0x00000006 },
+ { 0xffffffff, 0000000000 },
+ { 0x10000000, 0000000000 },
+ { 0x07f007f0, 0000000000 },
+ { 0x0003802a, 0x00000002 },
+ { 0x040067e0, 0x00000006 },
+ { 0x0003802c, 0x00000002 },
+ { 0x04002741, 0x00000002 },
+ { 0x04002741, 0x00000002 },
+ { 0x04002743, 0x00000002 },
+ { 0x00007675, 0x00000002 },
+ { 0x00007676, 0x00000002 },
+ { 0x00007677, 0x00000002 },
+ { 0x00007678, 0x00000006 },
+ { 0x0003802c, 0x00000002 },
+ { 0x04002741, 0x00000002 },
+ { 0x04002741, 0x00000002 },
+ { 0x04002743, 0x00000002 },
+ { 0x00007676, 0x00000002 },
+ { 0x00007677, 0x00000002 },
+ { 0x00007678, 0x00000006 },
+ { 0x0003802b, 0x00000002 },
+ { 0x04002676, 0x00000002 },
+ { 0x00007677, 0x00000002 },
+ { 0x0003802c, 0x00000002 },
+ { 0x04002741, 0x00000002 },
+ { 0x04002743, 0x00000002 },
+ { 0x00007678, 0x00000006 },
+ { 0x0003802c, 0x00000002 },
+ { 0x04002741, 0x00000002 },
+ { 0x04002741, 0x00000002 },
+ { 0x04002743, 0x00000002 },
+ { 0x00007678, 0x00000006 },
+ { 0x0000002f, 0x00000018 },
+ { 0x0000002f, 0x00000018 },
+ { 0000000000, 0x00000006 },
+ { 0x00000037, 0x00000018 },
+ { 0x00000037, 0x00000018 },
+ { 0000000000, 0x00000006 },
+ { 0x01605000, 0x00000002 },
+ { 0x00065000, 0x00000002 },
+ { 0x00098000, 0x00000002 },
+ { 0x00061000, 0x00000002 },
+ { 0x64c06051, 0x00000004 },
+ { 0x00080000, 0x00000016 },
+ { 0000000000, 0000000000 },
+ { 0x0400251d, 0x00000002 },
+ { 0x00007580, 0x00000002 },
+ { 0x00067581, 0x00000002 },
+ { 0x04002580, 0x00000002 },
+ { 0x00067581, 0x00000002 },
+ { 0x0000005a, 0x00000004 },
+ { 0x00005000, 0000000000 },
+ { 0x00061000, 0x00000002 },
+ { 0x0000750e, 0x00000002 },
+ { 0x00019000, 0x00000002 },
+ { 0x00011064, 0x00000014 },
+ { 0x00000064, 0x00000012 },
+ { 0x0400250f, 0x00000002 },
+ { 0x0000505e, 0x00000004 },
+ { 0x00007565, 0x00000002 },
+ { 0x00007566, 0x00000002 },
+ { 0x00000065, 0x00000004 },
+ { 0x01e655b4, 0x00000002 },
+ { 0x4401b0f0, 0x00000002 },
+ { 0x01c110f0, 0x00000002 },
+ { 0x26667071, 0x00000018 },
+ { 0x040c2565, 0x00000002 },
+ { 0x00000071, 0x00000018 },
+ { 0x04002564, 0x00000002 },
+ { 0x00007566, 0x00000002 },
+ { 0x00000068, 0x00000004 },
+ { 0x00401074, 0x00000008 },
+ { 0x00101000, 0x00000002 },
+ { 0x000d80ff, 0x00000002 },
+ { 0x00800077, 0x00000008 },
+ { 0x000f9000, 0x00000002 },
+ { 0x000e00ff, 0x00000002 },
+ { 0000000000, 0x00000006 },
+ { 0x00000094, 0x00000018 },
+ { 0x00000068, 0x00000004 },
+ { 0x00007576, 0x00000002 },
+ { 0x00065000, 0x00000002 },
+ { 0x00009000, 0x00000002 },
+ { 0x00041000, 0x00000002 },
+ { 0x0c00350e, 0x00000002 },
+ { 0x00049000, 0x00000002 },
+ { 0x00051000, 0x00000002 },
+ { 0x01e785f8, 0x00000002 },
+ { 0x00200000, 0x00000002 },
+ { 0x00600087, 0x0000000c },
+ { 0x00007563, 0x00000002 },
+ { 0x006075f0, 0x00000021 },
+ { 0x2000707c, 0x00000004 },
+ { 0x0000507c, 0x00000004 },
+ { 0x00007576, 0x00000002 },
+ { 0x00007577, 0x00000002 },
+ { 0x0000750e, 0x00000002 },
+ { 0x0000750f, 0x00000002 },
+ { 0x00a05000, 0x00000002 },
+ { 0x0060008a, 0x0000000c },
+ { 0x006075f0, 0x00000021 },
+ { 0x000075f8, 0x00000002 },
+ { 0x0000008a, 0x00000004 },
+ { 0x000a750e, 0x00000002 },
+ { 0x0020750f, 0x00000002 },
+ { 0x0060008d, 0x00000004 },
+ { 0x00007570, 0x00000002 },
+ { 0x00007571, 0x00000002 },
+ { 0x00007572, 0x00000006 },
+ { 0x00005000, 0x00000002 },
+ { 0x00a05000, 0x00000002 },
+ { 0x00007568, 0x00000002 },
+ { 0x00061000, 0x00000002 },
+ { 0x00000098, 0x0000000c },
+ { 0x00058000, 0x00000002 },
+ { 0x0c607562, 0x00000002 },
+ { 0x0000009a, 0x00000004 },
+ { 0x00600099, 0x00000004 },
+ { 0x400070f1, 0000000000 },
+ { 0x000380f1, 0x00000002 },
+ { 0x000000a7, 0x0000001c },
+ { 0x000650a9, 0x00000018 },
+ { 0x040025bb, 0x00000002 },
+ { 0x000610aa, 0x00000018 },
+ { 0x040075bc, 0000000000 },
+ { 0x000075bb, 0x00000002 },
+ { 0x000075bc, 0000000000 },
+ { 0x00090000, 0x00000006 },
+ { 0x00090000, 0x00000002 },
+ { 0x000d8002, 0x00000006 },
+ { 0x00005000, 0x00000002 },
+ { 0x00007821, 0x00000002 },
+ { 0x00007800, 0000000000 },
+ { 0x00007821, 0x00000002 },
+ { 0x00007800, 0000000000 },
+ { 0x01665000, 0x00000002 },
+ { 0x000a0000, 0x00000002 },
+ { 0x000671cc, 0x00000002 },
+ { 0x0286f1cd, 0x00000002 },
+ { 0x000000b7, 0x00000010 },
+ { 0x21007000, 0000000000 },
+ { 0x000000be, 0x0000001c },
+ { 0x00065000, 0x00000002 },
+ { 0x000a0000, 0x00000002 },
+ { 0x00061000, 0x00000002 },
+ { 0x000b0000, 0x00000002 },
+ { 0x38067000, 0x00000002 },
+ { 0x000a00ba, 0x00000004 },
+ { 0x20007000, 0000000000 },
+ { 0x01200000, 0x00000002 },
+ { 0x20077000, 0x00000002 },
+ { 0x01200000, 0x00000002 },
+ { 0x20007000, 0000000000 },
+ { 0x00061000, 0x00000002 },
+ { 0x0120751b, 0x00000002 },
+ { 0x8040750a, 0x00000002 },
+ { 0x8040750b, 0x00000002 },
+ { 0x00110000, 0x00000002 },
+ { 0x000380f1, 0x00000002 },
+ { 0x000000d1, 0x0000001c },
+ { 0x000610aa, 0x00000018 },
+ { 0x844075bd, 0x00000002 },
+ { 0x000610a9, 0x00000018 },
+ { 0x840075bb, 0x00000002 },
+ { 0x000610aa, 0x00000018 },
+ { 0x844075bc, 0x00000002 },
+ { 0x000000d4, 0x00000004 },
+ { 0x804075bd, 0x00000002 },
+ { 0x800075bb, 0x00000002 },
+ { 0x804075bc, 0x00000002 },
+ { 0x00108000, 0x00000002 },
+ { 0x01400000, 0x00000002 },
+ { 0x006000d8, 0x0000000c },
+ { 0x20c07000, 0x00000020 },
+ { 0x000000da, 0x00000012 },
+ { 0x00800000, 0x00000006 },
+ { 0x0080751d, 0x00000006 },
+ { 0x000025bb, 0x00000002 },
+ { 0x000040d4, 0x00000004 },
+ { 0x0000775c, 0x00000002 },
+ { 0x00a05000, 0x00000002 },
+ { 0x00661000, 0x00000002 },
+ { 0x0460275d, 0x00000020 },
+ { 0x00004000, 0000000000 },
+ { 0x00007999, 0x00000002 },
+ { 0x00a05000, 0x00000002 },
+ { 0x00661000, 0x00000002 },
+ { 0x0460299b, 0x00000020 },
+ { 0x00004000, 0000000000 },
+ { 0x01e00830, 0x00000002 },
+ { 0x21007000, 0000000000 },
+ { 0x00005000, 0x00000002 },
+ { 0x00038056, 0x00000002 },
+ { 0x040025e0, 0x00000002 },
+ { 0x000075e1, 0000000000 },
+ { 0x00000001, 0000000000 },
+ { 0x000380ed, 0x00000002 },
+ { 0x04007394, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0x000078c4, 0x00000002 },
+ { 0x000078c5, 0x00000002 },
+ { 0x000078c6, 0x00000002 },
+ { 0x00007924, 0x00000002 },
+ { 0x00007925, 0x00000002 },
+ { 0x00007926, 0x00000002 },
+ { 0x000000f2, 0x00000004 },
+ { 0x00007924, 0x00000002 },
+ { 0x00007925, 0x00000002 },
+ { 0x00007926, 0x00000002 },
+ { 0x000000f9, 0x00000004 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+};
+
+static const u32 R300_cp_microcode[][2] = {
+ { 0x4200e000, 0000000000 },
+ { 0x4000e000, 0000000000 },
+ { 0x000000ae, 0x00000008 },
+ { 0x000000b2, 0x00000008 },
+ { 0x67554b4a, 0000000000 },
+ { 0x4a4a4475, 0000000000 },
+ { 0x55527d83, 0000000000 },
+ { 0x4a8c8b65, 0000000000 },
+ { 0x4aef4af6, 0000000000 },
+ { 0x4ae14a4a, 0000000000 },
+ { 0xe4979797, 0000000000 },
+ { 0xdb4aebdd, 0000000000 },
+ { 0x9ccc4a4a, 0000000000 },
+ { 0xd1989898, 0000000000 },
+ { 0x4a0f9ad6, 0000000000 },
+ { 0x000ca000, 0x00000004 },
+ { 0x000d0012, 0x00000038 },
+ { 0x0000e8b4, 0x00000004 },
+ { 0x000d0014, 0x00000038 },
+ { 0x0000e8b6, 0x00000004 },
+ { 0x000d0016, 0x00000038 },
+ { 0x0000e854, 0x00000004 },
+ { 0x000d0018, 0x00000038 },
+ { 0x0000e855, 0x00000004 },
+ { 0x000d001a, 0x00000038 },
+ { 0x0000e856, 0x00000004 },
+ { 0x000d001c, 0x00000038 },
+ { 0x0000e857, 0x00000004 },
+ { 0x000d001e, 0x00000038 },
+ { 0x0000e824, 0x00000004 },
+ { 0x000d0020, 0x00000038 },
+ { 0x0000e825, 0x00000004 },
+ { 0x000d0022, 0x00000038 },
+ { 0x0000e830, 0x00000004 },
+ { 0x000d0024, 0x00000038 },
+ { 0x0000f0c0, 0x00000004 },
+ { 0x000d0026, 0x00000038 },
+ { 0x0000f0c1, 0x00000004 },
+ { 0x000d0028, 0x00000038 },
+ { 0x0000f041, 0x00000004 },
+ { 0x000d002a, 0x00000038 },
+ { 0x0000f184, 0x00000004 },
+ { 0x000d002c, 0x00000038 },
+ { 0x0000f185, 0x00000004 },
+ { 0x000d002e, 0x00000038 },
+ { 0x0000f186, 0x00000004 },
+ { 0x000d0030, 0x00000038 },
+ { 0x0000f187, 0x00000004 },
+ { 0x000d0032, 0x00000038 },
+ { 0x0000f180, 0x00000004 },
+ { 0x000d0034, 0x00000038 },
+ { 0x0000f393, 0x00000004 },
+ { 0x000d0036, 0x00000038 },
+ { 0x0000f38a, 0x00000004 },
+ { 0x000d0038, 0x00000038 },
+ { 0x0000f38e, 0x00000004 },
+ { 0x0000e821, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00000043, 0x00000018 },
+ { 0x00cce800, 0x00000004 },
+ { 0x001b0001, 0x00000004 },
+ { 0x08004800, 0x00000004 },
+ { 0x001b0001, 0x00000004 },
+ { 0x08004800, 0x00000004 },
+ { 0x001b0001, 0x00000004 },
+ { 0x08004800, 0x00000004 },
+ { 0x0000003a, 0x00000008 },
+ { 0x0000a000, 0000000000 },
+ { 0x2000451d, 0x00000004 },
+ { 0x0000e580, 0x00000004 },
+ { 0x000ce581, 0x00000004 },
+ { 0x08004580, 0x00000004 },
+ { 0x000ce581, 0x00000004 },
+ { 0x00000047, 0x00000008 },
+ { 0x0000a000, 0000000000 },
+ { 0x000c2000, 0x00000004 },
+ { 0x0000e50e, 0x00000004 },
+ { 0x00032000, 0x00000004 },
+ { 0x00022051, 0x00000028 },
+ { 0x00000051, 0x00000024 },
+ { 0x0800450f, 0x00000004 },
+ { 0x0000a04b, 0x00000008 },
+ { 0x0000e565, 0x00000004 },
+ { 0x0000e566, 0x00000004 },
+ { 0x00000052, 0x00000008 },
+ { 0x03cca5b4, 0x00000004 },
+ { 0x05432000, 0x00000004 },
+ { 0x00022000, 0x00000004 },
+ { 0x4ccce05e, 0x00000030 },
+ { 0x08274565, 0x00000004 },
+ { 0x0000005e, 0x00000030 },
+ { 0x08004564, 0x00000004 },
+ { 0x0000e566, 0x00000004 },
+ { 0x00000055, 0x00000008 },
+ { 0x00802061, 0x00000010 },
+ { 0x00202000, 0x00000004 },
+ { 0x001b00ff, 0x00000004 },
+ { 0x01000064, 0x00000010 },
+ { 0x001f2000, 0x00000004 },
+ { 0x001c00ff, 0x00000004 },
+ { 0000000000, 0x0000000c },
+ { 0x00000080, 0x00000030 },
+ { 0x00000055, 0x00000008 },
+ { 0x0000e576, 0x00000004 },
+ { 0x000ca000, 0x00000004 },
+ { 0x00012000, 0x00000004 },
+ { 0x00082000, 0x00000004 },
+ { 0x1800650e, 0x00000004 },
+ { 0x00092000, 0x00000004 },
+ { 0x000a2000, 0x00000004 },
+ { 0x000f0000, 0x00000004 },
+ { 0x00400000, 0x00000004 },
+ { 0x00000074, 0x00000018 },
+ { 0x0000e563, 0x00000004 },
+ { 0x00c0e5f9, 0x000000c2 },
+ { 0x00000069, 0x00000008 },
+ { 0x0000a069, 0x00000008 },
+ { 0x0000e576, 0x00000004 },
+ { 0x0000e577, 0x00000004 },
+ { 0x0000e50e, 0x00000004 },
+ { 0x0000e50f, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00000077, 0x00000018 },
+ { 0x00c0e5f9, 0x000000c2 },
+ { 0x00000077, 0x00000008 },
+ { 0x0014e50e, 0x00000004 },
+ { 0x0040e50f, 0x00000004 },
+ { 0x00c0007a, 0x00000008 },
+ { 0x0000e570, 0x00000004 },
+ { 0x0000e571, 0x00000004 },
+ { 0x0000e572, 0x0000000c },
+ { 0x0000a000, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x0000e568, 0x00000004 },
+ { 0x000c2000, 0x00000004 },
+ { 0x00000084, 0x00000018 },
+ { 0x000b0000, 0x00000004 },
+ { 0x18c0e562, 0x00000004 },
+ { 0x00000086, 0x00000008 },
+ { 0x00c00085, 0x00000008 },
+ { 0x000700e3, 0x00000004 },
+ { 0x00000092, 0x00000038 },
+ { 0x000ca094, 0x00000030 },
+ { 0x080045bb, 0x00000004 },
+ { 0x000c2095, 0x00000030 },
+ { 0x0800e5bc, 0000000000 },
+ { 0x0000e5bb, 0x00000004 },
+ { 0x0000e5bc, 0000000000 },
+ { 0x00120000, 0x0000000c },
+ { 0x00120000, 0x00000004 },
+ { 0x001b0002, 0x0000000c },
+ { 0x0000a000, 0x00000004 },
+ { 0x0000e821, 0x00000004 },
+ { 0x0000e800, 0000000000 },
+ { 0x0000e821, 0x00000004 },
+ { 0x0000e82e, 0000000000 },
+ { 0x02cca000, 0x00000004 },
+ { 0x00140000, 0x00000004 },
+ { 0x000ce1cc, 0x00000004 },
+ { 0x050de1cd, 0x00000004 },
+ { 0x00400000, 0x00000004 },
+ { 0x000000a4, 0x00000018 },
+ { 0x00c0a000, 0x00000004 },
+ { 0x000000a1, 0x00000008 },
+ { 0x000000a6, 0x00000020 },
+ { 0x4200e000, 0000000000 },
+ { 0x000000ad, 0x00000038 },
+ { 0x000ca000, 0x00000004 },
+ { 0x00140000, 0x00000004 },
+ { 0x000c2000, 0x00000004 },
+ { 0x00160000, 0x00000004 },
+ { 0x700ce000, 0x00000004 },
+ { 0x001400a9, 0x00000008 },
+ { 0x4000e000, 0000000000 },
+ { 0x02400000, 0x00000004 },
+ { 0x400ee000, 0x00000004 },
+ { 0x02400000, 0x00000004 },
+ { 0x4000e000, 0000000000 },
+ { 0x000c2000, 0x00000004 },
+ { 0x0240e51b, 0x00000004 },
+ { 0x0080e50a, 0x00000005 },
+ { 0x0080e50b, 0x00000005 },
+ { 0x00220000, 0x00000004 },
+ { 0x000700e3, 0x00000004 },
+ { 0x000000c0, 0x00000038 },
+ { 0x000c2095, 0x00000030 },
+ { 0x0880e5bd, 0x00000005 },
+ { 0x000c2094, 0x00000030 },
+ { 0x0800e5bb, 0x00000005 },
+ { 0x000c2095, 0x00000030 },
+ { 0x0880e5bc, 0x00000005 },
+ { 0x000000c3, 0x00000008 },
+ { 0x0080e5bd, 0x00000005 },
+ { 0x0000e5bb, 0x00000005 },
+ { 0x0080e5bc, 0x00000005 },
+ { 0x00210000, 0x00000004 },
+ { 0x02800000, 0x00000004 },
+ { 0x00c000c7, 0x00000018 },
+ { 0x4180e000, 0x00000040 },
+ { 0x000000c9, 0x00000024 },
+ { 0x01000000, 0x0000000c },
+ { 0x0100e51d, 0x0000000c },
+ { 0x000045bb, 0x00000004 },
+ { 0x000080c3, 0x00000008 },
+ { 0x0000f3ce, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00cc2000, 0x00000004 },
+ { 0x08c053cf, 0x00000040 },
+ { 0x00008000, 0000000000 },
+ { 0x0000f3d2, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00cc2000, 0x00000004 },
+ { 0x08c053d3, 0x00000040 },
+ { 0x00008000, 0000000000 },
+ { 0x0000f39d, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00cc2000, 0x00000004 },
+ { 0x08c0539e, 0x00000040 },
+ { 0x00008000, 0000000000 },
+ { 0x03c00830, 0x00000004 },
+ { 0x4200e000, 0000000000 },
+ { 0x0000a000, 0x00000004 },
+ { 0x200045e0, 0x00000004 },
+ { 0x0000e5e1, 0000000000 },
+ { 0x00000001, 0000000000 },
+ { 0x000700e0, 0x00000004 },
+ { 0x0800e394, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0x0000e8c4, 0x00000004 },
+ { 0x0000e8c5, 0x00000004 },
+ { 0x0000e8c6, 0x00000004 },
+ { 0x0000e928, 0x00000004 },
+ { 0x0000e929, 0x00000004 },
+ { 0x0000e92a, 0x00000004 },
+ { 0x000000e4, 0x00000008 },
+ { 0x0000e928, 0x00000004 },
+ { 0x0000e929, 0x00000004 },
+ { 0x0000e92a, 0x00000004 },
+ { 0x000000eb, 0x00000008 },
+ { 0x02c02000, 0x00000004 },
+ { 0x00060000, 0x00000004 },
+ { 0x000000f3, 0x00000034 },
+ { 0x000000f0, 0x00000008 },
+ { 0x00008000, 0x00000004 },
+ { 0xc000e000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0x000c2000, 0x00000004 },
+ { 0x001d0018, 0x00000004 },
+ { 0x001a0001, 0x00000004 },
+ { 0x000000fb, 0x00000034 },
+ { 0x0000004a, 0x00000008 },
+ { 0x0500a04a, 0x00000008 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+};
+
+static const u32 R420_cp_microcode[][2] = {
+ { 0x4200e000, 0000000000 },
+ { 0x4000e000, 0000000000 },
+ { 0x00000099, 0x00000008 },
+ { 0x0000009d, 0x00000008 },
+ { 0x4a554b4a, 0000000000 },
+ { 0x4a4a4467, 0000000000 },
+ { 0x55526f75, 0000000000 },
+ { 0x4a7e7d65, 0000000000 },
+ { 0xd9d3dff6, 0000000000 },
+ { 0x4ac54a4a, 0000000000 },
+ { 0xc8828282, 0000000000 },
+ { 0xbf4acfc1, 0000000000 },
+ { 0x87b04a4a, 0000000000 },
+ { 0xb5838383, 0000000000 },
+ { 0x4a0f85ba, 0000000000 },
+ { 0x000ca000, 0x00000004 },
+ { 0x000d0012, 0x00000038 },
+ { 0x0000e8b4, 0x00000004 },
+ { 0x000d0014, 0x00000038 },
+ { 0x0000e8b6, 0x00000004 },
+ { 0x000d0016, 0x00000038 },
+ { 0x0000e854, 0x00000004 },
+ { 0x000d0018, 0x00000038 },
+ { 0x0000e855, 0x00000004 },
+ { 0x000d001a, 0x00000038 },
+ { 0x0000e856, 0x00000004 },
+ { 0x000d001c, 0x00000038 },
+ { 0x0000e857, 0x00000004 },
+ { 0x000d001e, 0x00000038 },
+ { 0x0000e824, 0x00000004 },
+ { 0x000d0020, 0x00000038 },
+ { 0x0000e825, 0x00000004 },
+ { 0x000d0022, 0x00000038 },
+ { 0x0000e830, 0x00000004 },
+ { 0x000d0024, 0x00000038 },
+ { 0x0000f0c0, 0x00000004 },
+ { 0x000d0026, 0x00000038 },
+ { 0x0000f0c1, 0x00000004 },
+ { 0x000d0028, 0x00000038 },
+ { 0x0000f041, 0x00000004 },
+ { 0x000d002a, 0x00000038 },
+ { 0x0000f184, 0x00000004 },
+ { 0x000d002c, 0x00000038 },
+ { 0x0000f185, 0x00000004 },
+ { 0x000d002e, 0x00000038 },
+ { 0x0000f186, 0x00000004 },
+ { 0x000d0030, 0x00000038 },
+ { 0x0000f187, 0x00000004 },
+ { 0x000d0032, 0x00000038 },
+ { 0x0000f180, 0x00000004 },
+ { 0x000d0034, 0x00000038 },
+ { 0x0000f393, 0x00000004 },
+ { 0x000d0036, 0x00000038 },
+ { 0x0000f38a, 0x00000004 },
+ { 0x000d0038, 0x00000038 },
+ { 0x0000f38e, 0x00000004 },
+ { 0x0000e821, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00000043, 0x00000018 },
+ { 0x00cce800, 0x00000004 },
+ { 0x001b0001, 0x00000004 },
+ { 0x08004800, 0x00000004 },
+ { 0x001b0001, 0x00000004 },
+ { 0x08004800, 0x00000004 },
+ { 0x001b0001, 0x00000004 },
+ { 0x08004800, 0x00000004 },
+ { 0x0000003a, 0x00000008 },
+ { 0x0000a000, 0000000000 },
+ { 0x2000451d, 0x00000004 },
+ { 0x0000e580, 0x00000004 },
+ { 0x000ce581, 0x00000004 },
+ { 0x08004580, 0x00000004 },
+ { 0x000ce581, 0x00000004 },
+ { 0x00000047, 0x00000008 },
+ { 0x0000a000, 0000000000 },
+ { 0x000c2000, 0x00000004 },
+ { 0x0000e50e, 0x00000004 },
+ { 0x00032000, 0x00000004 },
+ { 0x00022051, 0x00000028 },
+ { 0x00000051, 0x00000024 },
+ { 0x0800450f, 0x00000004 },
+ { 0x0000a04b, 0x00000008 },
+ { 0x0000e565, 0x00000004 },
+ { 0x0000e566, 0x00000004 },
+ { 0x00000052, 0x00000008 },
+ { 0x03cca5b4, 0x00000004 },
+ { 0x05432000, 0x00000004 },
+ { 0x00022000, 0x00000004 },
+ { 0x4ccce05e, 0x00000030 },
+ { 0x08274565, 0x00000004 },
+ { 0x0000005e, 0x00000030 },
+ { 0x08004564, 0x00000004 },
+ { 0x0000e566, 0x00000004 },
+ { 0x00000055, 0x00000008 },
+ { 0x00802061, 0x00000010 },
+ { 0x00202000, 0x00000004 },
+ { 0x001b00ff, 0x00000004 },
+ { 0x01000064, 0x00000010 },
+ { 0x001f2000, 0x00000004 },
+ { 0x001c00ff, 0x00000004 },
+ { 0000000000, 0x0000000c },
+ { 0x00000072, 0x00000030 },
+ { 0x00000055, 0x00000008 },
+ { 0x0000e576, 0x00000004 },
+ { 0x0000e577, 0x00000004 },
+ { 0x0000e50e, 0x00000004 },
+ { 0x0000e50f, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00000069, 0x00000018 },
+ { 0x00c0e5f9, 0x000000c2 },
+ { 0x00000069, 0x00000008 },
+ { 0x0014e50e, 0x00000004 },
+ { 0x0040e50f, 0x00000004 },
+ { 0x00c0006c, 0x00000008 },
+ { 0x0000e570, 0x00000004 },
+ { 0x0000e571, 0x00000004 },
+ { 0x0000e572, 0x0000000c },
+ { 0x0000a000, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x0000e568, 0x00000004 },
+ { 0x000c2000, 0x00000004 },
+ { 0x00000076, 0x00000018 },
+ { 0x000b0000, 0x00000004 },
+ { 0x18c0e562, 0x00000004 },
+ { 0x00000078, 0x00000008 },
+ { 0x00c00077, 0x00000008 },
+ { 0x000700c7, 0x00000004 },
+ { 0x00000080, 0x00000038 },
+ { 0x0000e5bb, 0x00000004 },
+ { 0x0000e5bc, 0000000000 },
+ { 0x0000a000, 0x00000004 },
+ { 0x0000e821, 0x00000004 },
+ { 0x0000e800, 0000000000 },
+ { 0x0000e821, 0x00000004 },
+ { 0x0000e82e, 0000000000 },
+ { 0x02cca000, 0x00000004 },
+ { 0x00140000, 0x00000004 },
+ { 0x000ce1cc, 0x00000004 },
+ { 0x050de1cd, 0x00000004 },
+ { 0x00400000, 0x00000004 },
+ { 0x0000008f, 0x00000018 },
+ { 0x00c0a000, 0x00000004 },
+ { 0x0000008c, 0x00000008 },
+ { 0x00000091, 0x00000020 },
+ { 0x4200e000, 0000000000 },
+ { 0x00000098, 0x00000038 },
+ { 0x000ca000, 0x00000004 },
+ { 0x00140000, 0x00000004 },
+ { 0x000c2000, 0x00000004 },
+ { 0x00160000, 0x00000004 },
+ { 0x700ce000, 0x00000004 },
+ { 0x00140094, 0x00000008 },
+ { 0x4000e000, 0000000000 },
+ { 0x02400000, 0x00000004 },
+ { 0x400ee000, 0x00000004 },
+ { 0x02400000, 0x00000004 },
+ { 0x4000e000, 0000000000 },
+ { 0x000c2000, 0x00000004 },
+ { 0x0240e51b, 0x00000004 },
+ { 0x0080e50a, 0x00000005 },
+ { 0x0080e50b, 0x00000005 },
+ { 0x00220000, 0x00000004 },
+ { 0x000700c7, 0x00000004 },
+ { 0x000000a4, 0x00000038 },
+ { 0x0080e5bd, 0x00000005 },
+ { 0x0000e5bb, 0x00000005 },
+ { 0x0080e5bc, 0x00000005 },
+ { 0x00210000, 0x00000004 },
+ { 0x02800000, 0x00000004 },
+ { 0x00c000ab, 0x00000018 },
+ { 0x4180e000, 0x00000040 },
+ { 0x000000ad, 0x00000024 },
+ { 0x01000000, 0x0000000c },
+ { 0x0100e51d, 0x0000000c },
+ { 0x000045bb, 0x00000004 },
+ { 0x000080a7, 0x00000008 },
+ { 0x0000f3ce, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00cc2000, 0x00000004 },
+ { 0x08c053cf, 0x00000040 },
+ { 0x00008000, 0000000000 },
+ { 0x0000f3d2, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00cc2000, 0x00000004 },
+ { 0x08c053d3, 0x00000040 },
+ { 0x00008000, 0000000000 },
+ { 0x0000f39d, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00cc2000, 0x00000004 },
+ { 0x08c0539e, 0x00000040 },
+ { 0x00008000, 0000000000 },
+ { 0x03c00830, 0x00000004 },
+ { 0x4200e000, 0000000000 },
+ { 0x0000a000, 0x00000004 },
+ { 0x200045e0, 0x00000004 },
+ { 0x0000e5e1, 0000000000 },
+ { 0x00000001, 0000000000 },
+ { 0x000700c4, 0x00000004 },
+ { 0x0800e394, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0x0000e8c4, 0x00000004 },
+ { 0x0000e8c5, 0x00000004 },
+ { 0x0000e8c6, 0x00000004 },
+ { 0x0000e928, 0x00000004 },
+ { 0x0000e929, 0x00000004 },
+ { 0x0000e92a, 0x00000004 },
+ { 0x000000c8, 0x00000008 },
+ { 0x0000e928, 0x00000004 },
+ { 0x0000e929, 0x00000004 },
+ { 0x0000e92a, 0x00000004 },
+ { 0x000000cf, 0x00000008 },
+ { 0x02c02000, 0x00000004 },
+ { 0x00060000, 0x00000004 },
+ { 0x000000d7, 0x00000034 },
+ { 0x000000d4, 0x00000008 },
+ { 0x00008000, 0x00000004 },
+ { 0xc000e000, 0000000000 },
+ { 0x0000e1cc, 0x00000004 },
+ { 0x0500e1cd, 0x00000004 },
+ { 0x000ca000, 0x00000004 },
+ { 0x000000de, 0x00000034 },
+ { 0x000000da, 0x00000008 },
+ { 0x0000a000, 0000000000 },
+ { 0x0019e1cc, 0x00000004 },
+ { 0x001b0001, 0x00000004 },
+ { 0x0500a000, 0x00000004 },
+ { 0x080041cd, 0x00000004 },
+ { 0x000ca000, 0x00000004 },
+ { 0x000000fb, 0x00000034 },
+ { 0x0000004a, 0x00000008 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0x000c2000, 0x00000004 },
+ { 0x001d0018, 0x00000004 },
+ { 0x001a0001, 0x00000004 },
+ { 0x000000fb, 0x00000034 },
+ { 0x0000004a, 0x00000008 },
+ { 0x0500a04a, 0x00000008 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+};
+
+static const u32 RS600_cp_microcode[][2] = {
+ { 0x4200e000, 0000000000 },
+ { 0x4000e000, 0000000000 },
+ { 0x000000a0, 0x00000008 },
+ { 0x000000a4, 0x00000008 },
+ { 0x4a554b4a, 0000000000 },
+ { 0x4a4a4467, 0000000000 },
+ { 0x55526f75, 0000000000 },
+ { 0x4a7e7d65, 0000000000 },
+ { 0x4ae74af6, 0000000000 },
+ { 0x4ad34a4a, 0000000000 },
+ { 0xd6898989, 0000000000 },
+ { 0xcd4addcf, 0000000000 },
+ { 0x8ebe4ae2, 0000000000 },
+ { 0xc38a8a8a, 0000000000 },
+ { 0x4a0f8cc8, 0000000000 },
+ { 0x000ca000, 0x00000004 },
+ { 0x000d0012, 0x00000038 },
+ { 0x0000e8b4, 0x00000004 },
+ { 0x000d0014, 0x00000038 },
+ { 0x0000e8b6, 0x00000004 },
+ { 0x000d0016, 0x00000038 },
+ { 0x0000e854, 0x00000004 },
+ { 0x000d0018, 0x00000038 },
+ { 0x0000e855, 0x00000004 },
+ { 0x000d001a, 0x00000038 },
+ { 0x0000e856, 0x00000004 },
+ { 0x000d001c, 0x00000038 },
+ { 0x0000e857, 0x00000004 },
+ { 0x000d001e, 0x00000038 },
+ { 0x0000e824, 0x00000004 },
+ { 0x000d0020, 0x00000038 },
+ { 0x0000e825, 0x00000004 },
+ { 0x000d0022, 0x00000038 },
+ { 0x0000e830, 0x00000004 },
+ { 0x000d0024, 0x00000038 },
+ { 0x0000f0c0, 0x00000004 },
+ { 0x000d0026, 0x00000038 },
+ { 0x0000f0c1, 0x00000004 },
+ { 0x000d0028, 0x00000038 },
+ { 0x0000f041, 0x00000004 },
+ { 0x000d002a, 0x00000038 },
+ { 0x0000f184, 0x00000004 },
+ { 0x000d002c, 0x00000038 },
+ { 0x0000f185, 0x00000004 },
+ { 0x000d002e, 0x00000038 },
+ { 0x0000f186, 0x00000004 },
+ { 0x000d0030, 0x00000038 },
+ { 0x0000f187, 0x00000004 },
+ { 0x000d0032, 0x00000038 },
+ { 0x0000f180, 0x00000004 },
+ { 0x000d0034, 0x00000038 },
+ { 0x0000f393, 0x00000004 },
+ { 0x000d0036, 0x00000038 },
+ { 0x0000f38a, 0x00000004 },
+ { 0x000d0038, 0x00000038 },
+ { 0x0000f38e, 0x00000004 },
+ { 0x0000e821, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00000043, 0x00000018 },
+ { 0x00cce800, 0x00000004 },
+ { 0x001b0001, 0x00000004 },
+ { 0x08004800, 0x00000004 },
+ { 0x001b0001, 0x00000004 },
+ { 0x08004800, 0x00000004 },
+ { 0x001b0001, 0x00000004 },
+ { 0x08004800, 0x00000004 },
+ { 0x0000003a, 0x00000008 },
+ { 0x0000a000, 0000000000 },
+ { 0x2000451d, 0x00000004 },
+ { 0x0000e580, 0x00000004 },
+ { 0x000ce581, 0x00000004 },
+ { 0x08004580, 0x00000004 },
+ { 0x000ce581, 0x00000004 },
+ { 0x00000047, 0x00000008 },
+ { 0x0000a000, 0000000000 },
+ { 0x000c2000, 0x00000004 },
+ { 0x0000e50e, 0x00000004 },
+ { 0x00032000, 0x00000004 },
+ { 0x00022051, 0x00000028 },
+ { 0x00000051, 0x00000024 },
+ { 0x0800450f, 0x00000004 },
+ { 0x0000a04b, 0x00000008 },
+ { 0x0000e565, 0x00000004 },
+ { 0x0000e566, 0x00000004 },
+ { 0x00000052, 0x00000008 },
+ { 0x03cca5b4, 0x00000004 },
+ { 0x05432000, 0x00000004 },
+ { 0x00022000, 0x00000004 },
+ { 0x4ccce05e, 0x00000030 },
+ { 0x08274565, 0x00000004 },
+ { 0x0000005e, 0x00000030 },
+ { 0x08004564, 0x00000004 },
+ { 0x0000e566, 0x00000004 },
+ { 0x00000055, 0x00000008 },
+ { 0x00802061, 0x00000010 },
+ { 0x00202000, 0x00000004 },
+ { 0x001b00ff, 0x00000004 },
+ { 0x01000064, 0x00000010 },
+ { 0x001f2000, 0x00000004 },
+ { 0x001c00ff, 0x00000004 },
+ { 0000000000, 0x0000000c },
+ { 0x00000072, 0x00000030 },
+ { 0x00000055, 0x00000008 },
+ { 0x0000e576, 0x00000004 },
+ { 0x0000e577, 0x00000004 },
+ { 0x0000e50e, 0x00000004 },
+ { 0x0000e50f, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00000069, 0x00000018 },
+ { 0x00c0e5f9, 0x000000c2 },
+ { 0x00000069, 0x00000008 },
+ { 0x0014e50e, 0x00000004 },
+ { 0x0040e50f, 0x00000004 },
+ { 0x00c0006c, 0x00000008 },
+ { 0x0000e570, 0x00000004 },
+ { 0x0000e571, 0x00000004 },
+ { 0x0000e572, 0x0000000c },
+ { 0x0000a000, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x0000e568, 0x00000004 },
+ { 0x000c2000, 0x00000004 },
+ { 0x00000076, 0x00000018 },
+ { 0x000b0000, 0x00000004 },
+ { 0x18c0e562, 0x00000004 },
+ { 0x00000078, 0x00000008 },
+ { 0x00c00077, 0x00000008 },
+ { 0x000700d5, 0x00000004 },
+ { 0x00000084, 0x00000038 },
+ { 0x000ca086, 0x00000030 },
+ { 0x080045bb, 0x00000004 },
+ { 0x000c2087, 0x00000030 },
+ { 0x0800e5bc, 0000000000 },
+ { 0x0000e5bb, 0x00000004 },
+ { 0x0000e5bc, 0000000000 },
+ { 0x00120000, 0x0000000c },
+ { 0x00120000, 0x00000004 },
+ { 0x001b0002, 0x0000000c },
+ { 0x0000a000, 0x00000004 },
+ { 0x0000e821, 0x00000004 },
+ { 0x0000e800, 0000000000 },
+ { 0x0000e821, 0x00000004 },
+ { 0x0000e82e, 0000000000 },
+ { 0x02cca000, 0x00000004 },
+ { 0x00140000, 0x00000004 },
+ { 0x000ce1cc, 0x00000004 },
+ { 0x050de1cd, 0x00000004 },
+ { 0x00400000, 0x00000004 },
+ { 0x00000096, 0x00000018 },
+ { 0x00c0a000, 0x00000004 },
+ { 0x00000093, 0x00000008 },
+ { 0x00000098, 0x00000020 },
+ { 0x4200e000, 0000000000 },
+ { 0x0000009f, 0x00000038 },
+ { 0x000ca000, 0x00000004 },
+ { 0x00140000, 0x00000004 },
+ { 0x000c2000, 0x00000004 },
+ { 0x00160000, 0x00000004 },
+ { 0x700ce000, 0x00000004 },
+ { 0x0014009b, 0x00000008 },
+ { 0x4000e000, 0000000000 },
+ { 0x02400000, 0x00000004 },
+ { 0x400ee000, 0x00000004 },
+ { 0x02400000, 0x00000004 },
+ { 0x4000e000, 0000000000 },
+ { 0x000c2000, 0x00000004 },
+ { 0x0240e51b, 0x00000004 },
+ { 0x0080e50a, 0x00000005 },
+ { 0x0080e50b, 0x00000005 },
+ { 0x00220000, 0x00000004 },
+ { 0x000700d5, 0x00000004 },
+ { 0x000000b2, 0x00000038 },
+ { 0x000c2087, 0x00000030 },
+ { 0x0880e5bd, 0x00000005 },
+ { 0x000c2086, 0x00000030 },
+ { 0x0800e5bb, 0x00000005 },
+ { 0x000c2087, 0x00000030 },
+ { 0x0880e5bc, 0x00000005 },
+ { 0x000000b5, 0x00000008 },
+ { 0x0080e5bd, 0x00000005 },
+ { 0x0000e5bb, 0x00000005 },
+ { 0x0080e5bc, 0x00000005 },
+ { 0x00210000, 0x00000004 },
+ { 0x02800000, 0x00000004 },
+ { 0x00c000b9, 0x00000018 },
+ { 0x4180e000, 0x00000040 },
+ { 0x000000bb, 0x00000024 },
+ { 0x01000000, 0x0000000c },
+ { 0x0100e51d, 0x0000000c },
+ { 0x000045bb, 0x00000004 },
+ { 0x000080b5, 0x00000008 },
+ { 0x0000f3ce, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00cc2000, 0x00000004 },
+ { 0x08c053cf, 0x00000040 },
+ { 0x00008000, 0000000000 },
+ { 0x0000f3d2, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00cc2000, 0x00000004 },
+ { 0x08c053d3, 0x00000040 },
+ { 0x00008000, 0000000000 },
+ { 0x0000f39d, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00cc2000, 0x00000004 },
+ { 0x08c0539e, 0x00000040 },
+ { 0x00008000, 0000000000 },
+ { 0x03c00830, 0x00000004 },
+ { 0x4200e000, 0000000000 },
+ { 0x0000a000, 0x00000004 },
+ { 0x200045e0, 0x00000004 },
+ { 0x0000e5e1, 0000000000 },
+ { 0x00000001, 0000000000 },
+ { 0x000700d2, 0x00000004 },
+ { 0x0800e394, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0x0000e8c4, 0x00000004 },
+ { 0x0000e8c5, 0x00000004 },
+ { 0x0000e8c6, 0x00000004 },
+ { 0x0000e928, 0x00000004 },
+ { 0x0000e929, 0x00000004 },
+ { 0x0000e92a, 0x00000004 },
+ { 0x000000d6, 0x00000008 },
+ { 0x0000e928, 0x00000004 },
+ { 0x0000e929, 0x00000004 },
+ { 0x0000e92a, 0x00000004 },
+ { 0x000000dd, 0x00000008 },
+ { 0x00e00116, 0000000000 },
+ { 0x000700e1, 0x00000004 },
+ { 0x0800401c, 0x00000004 },
+ { 0x200050e7, 0x00000004 },
+ { 0x0000e01d, 0x00000004 },
+ { 0x000000e4, 0x00000008 },
+ { 0x02c02000, 0x00000004 },
+ { 0x00060000, 0x00000004 },
+ { 0x000000eb, 0x00000034 },
+ { 0x000000e8, 0x00000008 },
+ { 0x00008000, 0x00000004 },
+ { 0xc000e000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0x000c2000, 0x00000004 },
+ { 0x001d0018, 0x00000004 },
+ { 0x001a0001, 0x00000004 },
+ { 0x000000fb, 0x00000034 },
+ { 0x0000004a, 0x00000008 },
+ { 0x0500a04a, 0x00000008 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+};
+
+static const u32 RS690_cp_microcode[][2] = {
+ { 0x000000dd, 0x00000008 },
+ { 0x000000df, 0x00000008 },
+ { 0x000000a0, 0x00000008 },
+ { 0x000000a4, 0x00000008 },
+ { 0x4a554b4a, 0000000000 },
+ { 0x4a4a4467, 0000000000 },
+ { 0x55526f75, 0000000000 },
+ { 0x4a7e7d65, 0000000000 },
+ { 0x4ad74af6, 0000000000 },
+ { 0x4ac94a4a, 0000000000 },
+ { 0xcc898989, 0000000000 },
+ { 0xc34ad3c5, 0000000000 },
+ { 0x8e4a4a4a, 0000000000 },
+ { 0x4a8a8a8a, 0000000000 },
+ { 0x4a0f8c4a, 0000000000 },
+ { 0x000ca000, 0x00000004 },
+ { 0x000d0012, 0x00000038 },
+ { 0x0000e8b4, 0x00000004 },
+ { 0x000d0014, 0x00000038 },
+ { 0x0000e8b6, 0x00000004 },
+ { 0x000d0016, 0x00000038 },
+ { 0x0000e854, 0x00000004 },
+ { 0x000d0018, 0x00000038 },
+ { 0x0000e855, 0x00000004 },
+ { 0x000d001a, 0x00000038 },
+ { 0x0000e856, 0x00000004 },
+ { 0x000d001c, 0x00000038 },
+ { 0x0000e857, 0x00000004 },
+ { 0x000d001e, 0x00000038 },
+ { 0x0000e824, 0x00000004 },
+ { 0x000d0020, 0x00000038 },
+ { 0x0000e825, 0x00000004 },
+ { 0x000d0022, 0x00000038 },
+ { 0x0000e830, 0x00000004 },
+ { 0x000d0024, 0x00000038 },
+ { 0x0000f0c0, 0x00000004 },
+ { 0x000d0026, 0x00000038 },
+ { 0x0000f0c1, 0x00000004 },
+ { 0x000d0028, 0x00000038 },
+ { 0x0000f041, 0x00000004 },
+ { 0x000d002a, 0x00000038 },
+ { 0x0000f184, 0x00000004 },
+ { 0x000d002c, 0x00000038 },
+ { 0x0000f185, 0x00000004 },
+ { 0x000d002e, 0x00000038 },
+ { 0x0000f186, 0x00000004 },
+ { 0x000d0030, 0x00000038 },
+ { 0x0000f187, 0x00000004 },
+ { 0x000d0032, 0x00000038 },
+ { 0x0000f180, 0x00000004 },
+ { 0x000d0034, 0x00000038 },
+ { 0x0000f393, 0x00000004 },
+ { 0x000d0036, 0x00000038 },
+ { 0x0000f38a, 0x00000004 },
+ { 0x000d0038, 0x00000038 },
+ { 0x0000f38e, 0x00000004 },
+ { 0x0000e821, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00000043, 0x00000018 },
+ { 0x00cce800, 0x00000004 },
+ { 0x001b0001, 0x00000004 },
+ { 0x08004800, 0x00000004 },
+ { 0x001b0001, 0x00000004 },
+ { 0x08004800, 0x00000004 },
+ { 0x001b0001, 0x00000004 },
+ { 0x08004800, 0x00000004 },
+ { 0x0000003a, 0x00000008 },
+ { 0x0000a000, 0000000000 },
+ { 0x2000451d, 0x00000004 },
+ { 0x0000e580, 0x00000004 },
+ { 0x000ce581, 0x00000004 },
+ { 0x08004580, 0x00000004 },
+ { 0x000ce581, 0x00000004 },
+ { 0x00000047, 0x00000008 },
+ { 0x0000a000, 0000000000 },
+ { 0x000c2000, 0x00000004 },
+ { 0x0000e50e, 0x00000004 },
+ { 0x00032000, 0x00000004 },
+ { 0x00022051, 0x00000028 },
+ { 0x00000051, 0x00000024 },
+ { 0x0800450f, 0x00000004 },
+ { 0x0000a04b, 0x00000008 },
+ { 0x0000e565, 0x00000004 },
+ { 0x0000e566, 0x00000004 },
+ { 0x00000052, 0x00000008 },
+ { 0x03cca5b4, 0x00000004 },
+ { 0x05432000, 0x00000004 },
+ { 0x00022000, 0x00000004 },
+ { 0x4ccce05e, 0x00000030 },
+ { 0x08274565, 0x00000004 },
+ { 0x0000005e, 0x00000030 },
+ { 0x08004564, 0x00000004 },
+ { 0x0000e566, 0x00000004 },
+ { 0x00000055, 0x00000008 },
+ { 0x00802061, 0x00000010 },
+ { 0x00202000, 0x00000004 },
+ { 0x001b00ff, 0x00000004 },
+ { 0x01000064, 0x00000010 },
+ { 0x001f2000, 0x00000004 },
+ { 0x001c00ff, 0x00000004 },
+ { 0000000000, 0x0000000c },
+ { 0x00000072, 0x00000030 },
+ { 0x00000055, 0x00000008 },
+ { 0x0000e576, 0x00000004 },
+ { 0x0000e577, 0x00000004 },
+ { 0x0000e50e, 0x00000004 },
+ { 0x0000e50f, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00000069, 0x00000018 },
+ { 0x00c0e5f9, 0x000000c2 },
+ { 0x00000069, 0x00000008 },
+ { 0x0014e50e, 0x00000004 },
+ { 0x0040e50f, 0x00000004 },
+ { 0x00c0006c, 0x00000008 },
+ { 0x0000e570, 0x00000004 },
+ { 0x0000e571, 0x00000004 },
+ { 0x0000e572, 0x0000000c },
+ { 0x0000a000, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x0000e568, 0x00000004 },
+ { 0x000c2000, 0x00000004 },
+ { 0x00000076, 0x00000018 },
+ { 0x000b0000, 0x00000004 },
+ { 0x18c0e562, 0x00000004 },
+ { 0x00000078, 0x00000008 },
+ { 0x00c00077, 0x00000008 },
+ { 0x000700cb, 0x00000004 },
+ { 0x00000084, 0x00000038 },
+ { 0x000ca086, 0x00000030 },
+ { 0x080045bb, 0x00000004 },
+ { 0x000c2087, 0x00000030 },
+ { 0x0800e5bc, 0000000000 },
+ { 0x0000e5bb, 0x00000004 },
+ { 0x0000e5bc, 0000000000 },
+ { 0x00120000, 0x0000000c },
+ { 0x00120000, 0x00000004 },
+ { 0x001b0002, 0x0000000c },
+ { 0x0000a000, 0x00000004 },
+ { 0x0000e821, 0x00000004 },
+ { 0x0000e800, 0000000000 },
+ { 0x0000e821, 0x00000004 },
+ { 0x0000e82e, 0000000000 },
+ { 0x02cca000, 0x00000004 },
+ { 0x00140000, 0x00000004 },
+ { 0x000ce1cc, 0x00000004 },
+ { 0x050de1cd, 0x00000004 },
+ { 0x00400000, 0x00000004 },
+ { 0x00000096, 0x00000018 },
+ { 0x00c0a000, 0x00000004 },
+ { 0x00000093, 0x00000008 },
+ { 0x00000098, 0x00000020 },
+ { 0x4200e000, 0000000000 },
+ { 0x0000009f, 0x00000038 },
+ { 0x000ca000, 0x00000004 },
+ { 0x00140000, 0x00000004 },
+ { 0x000c2000, 0x00000004 },
+ { 0x00160000, 0x00000004 },
+ { 0x700ce000, 0x00000004 },
+ { 0x0014009b, 0x00000008 },
+ { 0x4000e000, 0000000000 },
+ { 0x02400000, 0x00000004 },
+ { 0x400ee000, 0x00000004 },
+ { 0x02400000, 0x00000004 },
+ { 0x4000e000, 0000000000 },
+ { 0x00100000, 0x0000002c },
+ { 0x00004000, 0000000000 },
+ { 0x080045c8, 0x00000004 },
+ { 0x00240005, 0x00000004 },
+ { 0x08004d0b, 0x00000004 },
+ { 0x000c2000, 0x00000004 },
+ { 0x0240e51b, 0x00000004 },
+ { 0x0080e50a, 0x00000005 },
+ { 0x0080e50b, 0x00000005 },
+ { 0x00220000, 0x00000004 },
+ { 0x000700cb, 0x00000004 },
+ { 0x000000b7, 0x00000038 },
+ { 0x000c2087, 0x00000030 },
+ { 0x0880e5bd, 0x00000005 },
+ { 0x000c2086, 0x00000030 },
+ { 0x0800e5bb, 0x00000005 },
+ { 0x000c2087, 0x00000030 },
+ { 0x0880e5bc, 0x00000005 },
+ { 0x000000ba, 0x00000008 },
+ { 0x0080e5bd, 0x00000005 },
+ { 0x0000e5bb, 0x00000005 },
+ { 0x0080e5bc, 0x00000005 },
+ { 0x00210000, 0x00000004 },
+ { 0x02800000, 0x00000004 },
+ { 0x00c000be, 0x00000018 },
+ { 0x4180e000, 0x00000040 },
+ { 0x000000c0, 0x00000024 },
+ { 0x01000000, 0x0000000c },
+ { 0x0100e51d, 0x0000000c },
+ { 0x000045bb, 0x00000004 },
+ { 0x000080ba, 0x00000008 },
+ { 0x03c00830, 0x00000004 },
+ { 0x4200e000, 0000000000 },
+ { 0x0000a000, 0x00000004 },
+ { 0x200045e0, 0x00000004 },
+ { 0x0000e5e1, 0000000000 },
+ { 0x00000001, 0000000000 },
+ { 0x000700c8, 0x00000004 },
+ { 0x0800e394, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0x0000e8c4, 0x00000004 },
+ { 0x0000e8c5, 0x00000004 },
+ { 0x0000e8c6, 0x00000004 },
+ { 0x0000e928, 0x00000004 },
+ { 0x0000e929, 0x00000004 },
+ { 0x0000e92a, 0x00000004 },
+ { 0x000000cc, 0x00000008 },
+ { 0x0000e928, 0x00000004 },
+ { 0x0000e929, 0x00000004 },
+ { 0x0000e92a, 0x00000004 },
+ { 0x000000d3, 0x00000008 },
+ { 0x02c02000, 0x00000004 },
+ { 0x00060000, 0x00000004 },
+ { 0x000000db, 0x00000034 },
+ { 0x000000d8, 0x00000008 },
+ { 0x00008000, 0x00000004 },
+ { 0xc000e000, 0000000000 },
+ { 0x000000e1, 0x00000030 },
+ { 0x4200e000, 0000000000 },
+ { 0x000000e1, 0x00000030 },
+ { 0x4000e000, 0000000000 },
+ { 0x0025001b, 0x00000004 },
+ { 0x00230000, 0x00000004 },
+ { 0x00250005, 0x00000004 },
+ { 0x000000e6, 0x00000034 },
+ { 0000000000, 0x0000000c },
+ { 0x00244000, 0x00000004 },
+ { 0x080045c8, 0x00000004 },
+ { 0x00240005, 0x00000004 },
+ { 0x08004d0b, 0x0000000c },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0x000c2000, 0x00000004 },
+ { 0x001d0018, 0x00000004 },
+ { 0x001a0001, 0x00000004 },
+ { 0x000000fb, 0x00000034 },
+ { 0x0000004a, 0x00000008 },
+ { 0x0500a04a, 0x00000008 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+};
+
+static const u32 R520_cp_microcode[][2] = {
+ { 0x4200e000, 0000000000 },
+ { 0x4000e000, 0000000000 },
+ { 0x00000099, 0x00000008 },
+ { 0x0000009d, 0x00000008 },
+ { 0x4a554b4a, 0000000000 },
+ { 0x4a4a4467, 0000000000 },
+ { 0x55526f75, 0000000000 },
+ { 0x4a7e7d65, 0000000000 },
+ { 0xe0dae6f6, 0000000000 },
+ { 0x4ac54a4a, 0000000000 },
+ { 0xc8828282, 0000000000 },
+ { 0xbf4acfc1, 0000000000 },
+ { 0x87b04ad5, 0000000000 },
+ { 0xb5838383, 0000000000 },
+ { 0x4a0f85ba, 0000000000 },
+ { 0x000ca000, 0x00000004 },
+ { 0x000d0012, 0x00000038 },
+ { 0x0000e8b4, 0x00000004 },
+ { 0x000d0014, 0x00000038 },
+ { 0x0000e8b6, 0x00000004 },
+ { 0x000d0016, 0x00000038 },
+ { 0x0000e854, 0x00000004 },
+ { 0x000d0018, 0x00000038 },
+ { 0x0000e855, 0x00000004 },
+ { 0x000d001a, 0x00000038 },
+ { 0x0000e856, 0x00000004 },
+ { 0x000d001c, 0x00000038 },
+ { 0x0000e857, 0x00000004 },
+ { 0x000d001e, 0x00000038 },
+ { 0x0000e824, 0x00000004 },
+ { 0x000d0020, 0x00000038 },
+ { 0x0000e825, 0x00000004 },
+ { 0x000d0022, 0x00000038 },
+ { 0x0000e830, 0x00000004 },
+ { 0x000d0024, 0x00000038 },
+ { 0x0000f0c0, 0x00000004 },
+ { 0x000d0026, 0x00000038 },
+ { 0x0000f0c1, 0x00000004 },
+ { 0x000d0028, 0x00000038 },
+ { 0x0000e000, 0x00000004 },
+ { 0x000d002a, 0x00000038 },
+ { 0x0000e000, 0x00000004 },
+ { 0x000d002c, 0x00000038 },
+ { 0x0000e000, 0x00000004 },
+ { 0x000d002e, 0x00000038 },
+ { 0x0000e000, 0x00000004 },
+ { 0x000d0030, 0x00000038 },
+ { 0x0000e000, 0x00000004 },
+ { 0x000d0032, 0x00000038 },
+ { 0x0000f180, 0x00000004 },
+ { 0x000d0034, 0x00000038 },
+ { 0x0000f393, 0x00000004 },
+ { 0x000d0036, 0x00000038 },
+ { 0x0000f38a, 0x00000004 },
+ { 0x000d0038, 0x00000038 },
+ { 0x0000f38e, 0x00000004 },
+ { 0x0000e821, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00000043, 0x00000018 },
+ { 0x00cce800, 0x00000004 },
+ { 0x001b0001, 0x00000004 },
+ { 0x08004800, 0x00000004 },
+ { 0x001b0001, 0x00000004 },
+ { 0x08004800, 0x00000004 },
+ { 0x001b0001, 0x00000004 },
+ { 0x08004800, 0x00000004 },
+ { 0x0000003a, 0x00000008 },
+ { 0x0000a000, 0000000000 },
+ { 0x2000451d, 0x00000004 },
+ { 0x0000e580, 0x00000004 },
+ { 0x000ce581, 0x00000004 },
+ { 0x08004580, 0x00000004 },
+ { 0x000ce581, 0x00000004 },
+ { 0x00000047, 0x00000008 },
+ { 0x0000a000, 0000000000 },
+ { 0x000c2000, 0x00000004 },
+ { 0x0000e50e, 0x00000004 },
+ { 0x00032000, 0x00000004 },
+ { 0x00022051, 0x00000028 },
+ { 0x00000051, 0x00000024 },
+ { 0x0800450f, 0x00000004 },
+ { 0x0000a04b, 0x00000008 },
+ { 0x0000e565, 0x00000004 },
+ { 0x0000e566, 0x00000004 },
+ { 0x00000052, 0x00000008 },
+ { 0x03cca5b4, 0x00000004 },
+ { 0x05432000, 0x00000004 },
+ { 0x00022000, 0x00000004 },
+ { 0x4ccce05e, 0x00000030 },
+ { 0x08274565, 0x00000004 },
+ { 0x0000005e, 0x00000030 },
+ { 0x08004564, 0x00000004 },
+ { 0x0000e566, 0x00000004 },
+ { 0x00000055, 0x00000008 },
+ { 0x00802061, 0x00000010 },
+ { 0x00202000, 0x00000004 },
+ { 0x001b00ff, 0x00000004 },
+ { 0x01000064, 0x00000010 },
+ { 0x001f2000, 0x00000004 },
+ { 0x001c00ff, 0x00000004 },
+ { 0000000000, 0x0000000c },
+ { 0x00000072, 0x00000030 },
+ { 0x00000055, 0x00000008 },
+ { 0x0000e576, 0x00000004 },
+ { 0x0000e577, 0x00000004 },
+ { 0x0000e50e, 0x00000004 },
+ { 0x0000e50f, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00000069, 0x00000018 },
+ { 0x00c0e5f9, 0x000000c2 },
+ { 0x00000069, 0x00000008 },
+ { 0x0014e50e, 0x00000004 },
+ { 0x0040e50f, 0x00000004 },
+ { 0x00c0006c, 0x00000008 },
+ { 0x0000e570, 0x00000004 },
+ { 0x0000e571, 0x00000004 },
+ { 0x0000e572, 0x0000000c },
+ { 0x0000a000, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x0000e568, 0x00000004 },
+ { 0x000c2000, 0x00000004 },
+ { 0x00000076, 0x00000018 },
+ { 0x000b0000, 0x00000004 },
+ { 0x18c0e562, 0x00000004 },
+ { 0x00000078, 0x00000008 },
+ { 0x00c00077, 0x00000008 },
+ { 0x000700c7, 0x00000004 },
+ { 0x00000080, 0x00000038 },
+ { 0x0000e5bb, 0x00000004 },
+ { 0x0000e5bc, 0000000000 },
+ { 0x0000a000, 0x00000004 },
+ { 0x0000e821, 0x00000004 },
+ { 0x0000e800, 0000000000 },
+ { 0x0000e821, 0x00000004 },
+ { 0x0000e82e, 0000000000 },
+ { 0x02cca000, 0x00000004 },
+ { 0x00140000, 0x00000004 },
+ { 0x000ce1cc, 0x00000004 },
+ { 0x050de1cd, 0x00000004 },
+ { 0x00400000, 0x00000004 },
+ { 0x0000008f, 0x00000018 },
+ { 0x00c0a000, 0x00000004 },
+ { 0x0000008c, 0x00000008 },
+ { 0x00000091, 0x00000020 },
+ { 0x4200e000, 0000000000 },
+ { 0x00000098, 0x00000038 },
+ { 0x000ca000, 0x00000004 },
+ { 0x00140000, 0x00000004 },
+ { 0x000c2000, 0x00000004 },
+ { 0x00160000, 0x00000004 },
+ { 0x700ce000, 0x00000004 },
+ { 0x00140094, 0x00000008 },
+ { 0x4000e000, 0000000000 },
+ { 0x02400000, 0x00000004 },
+ { 0x400ee000, 0x00000004 },
+ { 0x02400000, 0x00000004 },
+ { 0x4000e000, 0000000000 },
+ { 0x000c2000, 0x00000004 },
+ { 0x0240e51b, 0x00000004 },
+ { 0x0080e50a, 0x00000005 },
+ { 0x0080e50b, 0x00000005 },
+ { 0x00220000, 0x00000004 },
+ { 0x000700c7, 0x00000004 },
+ { 0x000000a4, 0x00000038 },
+ { 0x0080e5bd, 0x00000005 },
+ { 0x0000e5bb, 0x00000005 },
+ { 0x0080e5bc, 0x00000005 },
+ { 0x00210000, 0x00000004 },
+ { 0x02800000, 0x00000004 },
+ { 0x00c000ab, 0x00000018 },
+ { 0x4180e000, 0x00000040 },
+ { 0x000000ad, 0x00000024 },
+ { 0x01000000, 0x0000000c },
+ { 0x0100e51d, 0x0000000c },
+ { 0x000045bb, 0x00000004 },
+ { 0x000080a7, 0x00000008 },
+ { 0x0000f3ce, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00cc2000, 0x00000004 },
+ { 0x08c053cf, 0x00000040 },
+ { 0x00008000, 0000000000 },
+ { 0x0000f3d2, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00cc2000, 0x00000004 },
+ { 0x08c053d3, 0x00000040 },
+ { 0x00008000, 0000000000 },
+ { 0x0000f39d, 0x00000004 },
+ { 0x0140a000, 0x00000004 },
+ { 0x00cc2000, 0x00000004 },
+ { 0x08c0539e, 0x00000040 },
+ { 0x00008000, 0000000000 },
+ { 0x03c00830, 0x00000004 },
+ { 0x4200e000, 0000000000 },
+ { 0x0000a000, 0x00000004 },
+ { 0x200045e0, 0x00000004 },
+ { 0x0000e5e1, 0000000000 },
+ { 0x00000001, 0000000000 },
+ { 0x000700c4, 0x00000004 },
+ { 0x0800e394, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0x0000e8c4, 0x00000004 },
+ { 0x0000e8c5, 0x00000004 },
+ { 0x0000e8c6, 0x00000004 },
+ { 0x0000e928, 0x00000004 },
+ { 0x0000e929, 0x00000004 },
+ { 0x0000e92a, 0x00000004 },
+ { 0x000000c8, 0x00000008 },
+ { 0x0000e928, 0x00000004 },
+ { 0x0000e929, 0x00000004 },
+ { 0x0000e92a, 0x00000004 },
+ { 0x000000cf, 0x00000008 },
+ { 0xdeadbeef, 0000000000 },
+ { 0x00000116, 0000000000 },
+ { 0x000700d3, 0x00000004 },
+ { 0x080050e7, 0x00000004 },
+ { 0x000700d4, 0x00000004 },
+ { 0x0800401c, 0x00000004 },
+ { 0x0000e01d, 0000000000 },
+ { 0x02c02000, 0x00000004 },
+ { 0x00060000, 0x00000004 },
+ { 0x000000de, 0x00000034 },
+ { 0x000000db, 0x00000008 },
+ { 0x00008000, 0x00000004 },
+ { 0xc000e000, 0000000000 },
+ { 0x0000e1cc, 0x00000004 },
+ { 0x0500e1cd, 0x00000004 },
+ { 0x000ca000, 0x00000004 },
+ { 0x000000e5, 0x00000034 },
+ { 0x000000e1, 0x00000008 },
+ { 0x0000a000, 0000000000 },
+ { 0x0019e1cc, 0x00000004 },
+ { 0x001b0001, 0x00000004 },
+ { 0x0500a000, 0x00000004 },
+ { 0x080041cd, 0x00000004 },
+ { 0x000ca000, 0x00000004 },
+ { 0x000000fb, 0x00000034 },
+ { 0x0000004a, 0x00000008 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0x000c2000, 0x00000004 },
+ { 0x001d0018, 0x00000004 },
+ { 0x001a0001, 0x00000004 },
+ { 0x000000fb, 0x00000034 },
+ { 0x0000004a, 0x00000008 },
+ { 0x0500a04a, 0x00000008 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+ { 0000000000, 0000000000 },
+};
+
+
+#endif
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
index 6f75512f591e..11c146b49211 100644
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -1662,7 +1662,7 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev,
u32 height;
int i;
u32 texpitch, microtile;
- u32 offset;
+ u32 offset, byte_offset;
RING_LOCALS;
if (radeon_check_and_fixup_offset(dev_priv, file_priv, &tex->offset)) {
@@ -1727,6 +1727,13 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev,
} else
microtile = 0;
+ /* this might fail for zero-sized uploads - are those illegal? */
+ if (!radeon_check_offset(dev_priv, tex->offset + image->height *
+ blit_width - 1)) {
+ DRM_ERROR("Invalid final destination offset\n");
+ return -EINVAL;
+ }
+
DRM_DEBUG("tex=%dx%d blit=%d\n", tex_width, tex->height, blit_width);
do {
@@ -1840,6 +1847,7 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev,
}
#undef RADEON_COPY_MT
+ byte_offset = (image->y & ~2047) * blit_width;
buf->file_priv = file_priv;
buf->used = size;
offset = dev_priv->gart_buffers_offset + buf->offset;
@@ -1854,9 +1862,9 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev,
RADEON_DP_SRC_SOURCE_MEMORY |
RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
OUT_RING((spitch << 22) | (offset >> 10));
- OUT_RING((texpitch << 22) | (tex->offset >> 10));
+ OUT_RING((texpitch << 22) | ((tex->offset >> 10) + (byte_offset >> 10)));
OUT_RING(0);
- OUT_RING((image->x << 16) | image->y);
+ OUT_RING((image->x << 16) | (image->y % 2048));
OUT_RING((image->width << 16) | height);
RADEON_WAIT_UNTIL_2D_IDLE();
ADVANCE_RING();
@@ -3037,6 +3045,9 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
case RADEON_PARAM_FB_LOCATION:
value = radeon_read_fb_location(dev_priv);
break;
+ case RADEON_PARAM_NUM_GB_PIPES:
+ value = dev_priv->num_gb_pipes;
+ break;
default:
DRM_DEBUG("Invalid parameter %d\n", param->param);
return -EINVAL;
diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c
index 37870a4a3dc7..80c01cdfa37d 100644
--- a/drivers/char/drm/via_drv.c
+++ b/drivers/char/drm/via_drv.c
@@ -40,13 +40,11 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ |
- DRIVER_IRQ_SHARED,
+ DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
.load = via_driver_load,
.unload = via_driver_unload,
.context_dtor = via_final_context,
- .get_vblank_counter = via_get_vblank_counter,
- .enable_vblank = via_enable_vblank,
- .disable_vblank = via_disable_vblank,
+ .vblank_wait = via_driver_vblank_wait,
.irq_preinstall = via_driver_irq_preinstall,
.irq_postinstall = via_driver_irq_postinstall,
.irq_uninstall = via_driver_irq_uninstall,
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
index fe67030e39ac..2daae81874cd 100644
--- a/drivers/char/drm/via_drv.h
+++ b/drivers/char/drm/via_drv.h
@@ -75,7 +75,6 @@ typedef struct drm_via_private {
struct timeval last_vblank;
int last_vblank_valid;
unsigned usec_per_vblank;
- atomic_t vbl_received;
drm_via_state_t hc_state;
char pci_buf[VIA_PCI_BUF_SIZE];
const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
@@ -131,13 +130,11 @@ extern int via_init_context(struct drm_device * dev, int context);
extern int via_final_context(struct drm_device * dev, int context);
extern int via_do_cleanup_map(struct drm_device * dev);
-extern u32 via_get_vblank_counter(struct drm_device *dev, int crtc);
-extern int via_enable_vblank(struct drm_device *dev, int crtc);
-extern void via_disable_vblank(struct drm_device *dev, int crtc);
+extern int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS);
extern void via_driver_irq_preinstall(struct drm_device * dev);
-extern int via_driver_irq_postinstall(struct drm_device * dev);
+extern void via_driver_irq_postinstall(struct drm_device * dev);
extern void via_driver_irq_uninstall(struct drm_device * dev);
extern int via_dma_cleanup(struct drm_device * dev);
diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c
index f1ab6fc7c07e..c6bb978a1106 100644
--- a/drivers/char/drm/via_irq.c
+++ b/drivers/char/drm/via_irq.c
@@ -92,17 +92,8 @@ static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1};
static unsigned time_diff(struct timeval *now, struct timeval *then)
{
return (now->tv_usec >= then->tv_usec) ?
- now->tv_usec - then->tv_usec :
- 1000000 - (then->tv_usec - now->tv_usec);
-}
-
-u32 via_get_vblank_counter(struct drm_device *dev, int crtc)
-{
- drm_via_private_t *dev_priv = dev->dev_private;
- if (crtc != 0)
- return 0;
-
- return atomic_read(&dev_priv->vbl_received);
+ now->tv_usec - then->tv_usec :
+ 1000000 - (then->tv_usec - now->tv_usec);
}
irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
@@ -117,8 +108,8 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
status = VIA_READ(VIA_REG_INTERRUPT);
if (status & VIA_IRQ_VBLANK_PENDING) {
- atomic_inc(&dev_priv->vbl_received);
- if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) {
+ atomic_inc(&dev->vbl_received);
+ if (!(atomic_read(&dev->vbl_received) & 0x0F)) {
do_gettimeofday(&cur_vblank);
if (dev_priv->last_vblank_valid) {
dev_priv->usec_per_vblank =
@@ -128,11 +119,12 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
dev_priv->last_vblank = cur_vblank;
dev_priv->last_vblank_valid = 1;
}
- if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) {
+ if (!(atomic_read(&dev->vbl_received) & 0xFF)) {
DRM_DEBUG("US per vblank is: %u\n",
dev_priv->usec_per_vblank);
}
- drm_handle_vblank(dev, 0);
+ DRM_WAKEUP(&dev->vbl_queue);
+ drm_vbl_send_signals(dev);
handled = 1;
}
@@ -171,34 +163,31 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
}
}
-int via_enable_vblank(struct drm_device *dev, int crtc)
+int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
{
- drm_via_private_t *dev_priv = dev->dev_private;
- u32 status;
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ unsigned int cur_vblank;
+ int ret = 0;
- if (crtc != 0) {
- DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc);
+ DRM_DEBUG("\n");
+ if (!dev_priv) {
+ DRM_ERROR("called with no initialization\n");
return -EINVAL;
}
- status = VIA_READ(VIA_REG_INTERRUPT);
- VIA_WRITE(VIA_REG_INTERRUPT, status & VIA_IRQ_VBLANK_ENABLE);
+ viadrv_acknowledge_irqs(dev_priv);
- VIA_WRITE8(0x83d4, 0x11);
- VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
+ /* Assume that the user has missed the current sequence number
+ * by about a day rather than she wants to wait for years
+ * using vertical blanks...
+ */
- return 0;
-}
+ DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
+ (((cur_vblank = atomic_read(&dev->vbl_received)) -
+ *sequence) <= (1 << 23)));
-void via_disable_vblank(struct drm_device *dev, int crtc)
-{
- drm_via_private_t *dev_priv = dev->dev_private;
-
- VIA_WRITE8(0x83d4, 0x11);
- VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);
-
- if (crtc != 0)
- DRM_ERROR("%s: bad crtc %d\n", __FUNCTION__, crtc);
+ *sequence = cur_vblank;
+ return ret;
}
static int
@@ -303,25 +292,23 @@ void via_driver_irq_preinstall(struct drm_device * dev)
}
}
-int via_driver_irq_postinstall(struct drm_device * dev)
+void via_driver_irq_postinstall(struct drm_device * dev)
{
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
u32 status;
- DRM_DEBUG("via_driver_irq_postinstall\n");
- if (!dev_priv)
- return -EINVAL;
+ DRM_DEBUG("\n");
+ if (dev_priv) {
+ status = VIA_READ(VIA_REG_INTERRUPT);
+ VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
+ | dev_priv->irq_enable_mask);
- drm_vblank_init(dev, 1);
- status = VIA_READ(VIA_REG_INTERRUPT);
- VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
- | dev_priv->irq_enable_mask);
+ /* Some magic, oh for some data sheets ! */
- /* Some magic, oh for some data sheets ! */
- VIA_WRITE8(0x83d4, 0x11);
- VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
+ VIA_WRITE8(0x83d4, 0x11);
+ VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
- return 0;
+ }
}
void via_driver_irq_uninstall(struct drm_device * dev)
diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c
index 2398e864c28d..a00869c650d5 100644
--- a/drivers/char/generic_nvram.c
+++ b/drivers/char/generic_nvram.c
@@ -133,7 +133,7 @@ static struct miscdevice nvram_dev = {
int __init nvram_init(void)
{
- printk(KERN_INFO "Macintosh non-volatile memory driver v%s\n",
+ printk(KERN_INFO "Generic non-volatile memory driver v%s\n",
NVRAM_VERSION);
return misc_register(&nvram_dev);
}
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 8d6c2089d2a8..efd0b4db7c8e 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -112,3 +112,12 @@ config HW_RANDOM_PASEMI
If unsure, say Y.
+config HW_RANDOM_VIRTIO
+ tristate "VirtIO Random Number Generator support"
+ depends on HW_RANDOM && VIRTIO
+ ---help---
+ This driver provides kernel-side support for the virtual Random Number
+ Generator hardware.
+
+ To compile this driver as a module, choose M here: the
+ module will be called virtio-rng. If unsure, say N.
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index c8b7300e2fb1..b4940ddbb35f 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o
obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
+obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c
index 5cc651ef75eb..27fdc0866496 100644
--- a/drivers/char/hw_random/intel-rng.c
+++ b/drivers/char/hw_random/intel-rng.c
@@ -273,7 +273,7 @@ static int __init intel_rng_hw_init(void *_intel_rng_hw)
if (mfc != INTEL_FWH_MANUFACTURER_CODE ||
(dvc != INTEL_FWH_DEVICE_CODE_8M &&
dvc != INTEL_FWH_DEVICE_CODE_4M)) {
- printk(KERN_ERR PFX "FWH not detected\n");
+ printk(KERN_NOTICE PFX "FWH not detected\n");
return -ENODEV;
}
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
new file mode 100644
index 000000000000..d0e563e4fc39
--- /dev/null
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -0,0 +1,155 @@
+/*
+ * Randomness driver for virtio
+ * Copyright (C) 2007, 2008 Rusty Russell IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/err.h>
+#include <linux/hw_random.h>
+#include <linux/scatterlist.h>
+#include <linux/spinlock.h>
+#include <linux/virtio.h>
+#include <linux/virtio_rng.h>
+
+/* The host will fill any buffer we give it with sweet, sweet randomness. We
+ * give it 64 bytes at a time, and the hwrng framework takes it 4 bytes at a
+ * time. */
+#define RANDOM_DATA_SIZE 64
+
+static struct virtqueue *vq;
+static u32 *random_data;
+static unsigned int data_left;
+static DECLARE_COMPLETION(have_data);
+
+static void random_recv_done(struct virtqueue *vq)
+{
+ int len;
+
+ /* We never get spurious callbacks. */
+ if (!vq->vq_ops->get_buf(vq, &len))
+ BUG();
+
+ data_left = len / sizeof(random_data[0]);
+ complete(&have_data);
+}
+
+static void register_buffer(void)
+{
+ struct scatterlist sg;
+
+ sg_init_one(&sg, random_data, RANDOM_DATA_SIZE);
+ /* There should always be room for one buffer. */
+ if (vq->vq_ops->add_buf(vq, &sg, 0, 1, random_data) != 0)
+ BUG();
+ vq->vq_ops->kick(vq);
+}
+
+/* At least we don't udelay() in a loop like some other drivers. */
+static int virtio_data_present(struct hwrng *rng, int wait)
+{
+ if (data_left)
+ return 1;
+
+ if (!wait)
+ return 0;
+
+ wait_for_completion(&have_data);
+ return 1;
+}
+
+/* virtio_data_present() must have succeeded before this is called. */
+static int virtio_data_read(struct hwrng *rng, u32 *data)
+{
+ BUG_ON(!data_left);
+
+ *data = random_data[--data_left];
+
+ if (!data_left) {
+ init_completion(&have_data);
+ register_buffer();
+ }
+ return sizeof(*data);
+}
+
+static struct hwrng virtio_hwrng = {
+ .name = "virtio",
+ .data_present = virtio_data_present,
+ .data_read = virtio_data_read,
+};
+
+static int virtrng_probe(struct virtio_device *vdev)
+{
+ int err;
+
+ /* We expect a single virtqueue. */
+ vq = vdev->config->find_vq(vdev, 0, random_recv_done);
+ if (IS_ERR(vq))
+ return PTR_ERR(vq);
+
+ err = hwrng_register(&virtio_hwrng);
+ if (err) {
+ vdev->config->del_vq(vq);
+ return err;
+ }
+
+ register_buffer();
+ return 0;
+}
+
+static void virtrng_remove(struct virtio_device *vdev)
+{
+ vdev->config->reset(vdev);
+ hwrng_unregister(&virtio_hwrng);
+ vdev->config->del_vq(vq);
+}
+
+static struct virtio_device_id id_table[] = {
+ { VIRTIO_ID_RNG, VIRTIO_DEV_ANY_ID },
+ { 0 },
+};
+
+static struct virtio_driver virtio_rng = {
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .id_table = id_table,
+ .probe = virtrng_probe,
+ .remove = __devexit_p(virtrng_remove),
+};
+
+static int __init init(void)
+{
+ int err;
+
+ random_data = kmalloc(RANDOM_DATA_SIZE, GFP_KERNEL);
+ if (!random_data)
+ return -ENOMEM;
+
+ err = register_virtio_driver(&virtio_rng);
+ if (err)
+ kfree(random_data);
+ return err;
+}
+
+static void __exit fini(void)
+{
+ kfree(random_data);
+ unregister_virtio_driver(&virtio_rng);
+}
+module_init(init);
+module_exit(fini);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio random number driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/ip2/Makefile b/drivers/char/ip2/Makefile
index 6bfe2543ddc2..939618f62fe1 100644
--- a/drivers/char/ip2/Makefile
+++ b/drivers/char/ip2/Makefile
@@ -2,7 +2,7 @@
# Makefile for the Computone IntelliPort Plus Driver
#
-obj-$(CONFIG_COMPUTONE) += ip2.o ip2main.o
+obj-$(CONFIG_COMPUTONE) += ip2.o
-ip2-objs := ip2base.o
+ip2-objs := ip2base.o ip2main.o
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index a978c57b6b2b..61b6fe4156bb 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -347,27 +347,6 @@ have_requested_irq( char irq )
}
/******************************************************************************/
-/* Function: init_module() */
-/* Parameters: None */
-/* Returns: Success (0) */
-/* */
-/* Description: */
-/* This is a required entry point for an installable module. It simply calls */
-/* the driver initialisation function and returns what it returns. */
-/******************************************************************************/
-#ifdef MODULE
-static int __init
-ip2_init_module(void)
-{
-#ifdef IP2DEBUG_INIT
- printk (KERN_DEBUG "Loading module ...\n" );
-#endif
- return 0;
-}
-module_init(ip2_init_module);
-#endif /* MODULE */
-
-/******************************************************************************/
/* Function: cleanup_module() */
/* Parameters: None */
/* Returns: Nothing */
@@ -780,8 +759,6 @@ out:
return err;
}
-EXPORT_SYMBOL(ip2_loadmain);
-
/******************************************************************************/
/* Function: ip2_init_board() */
/* Parameters: Index of board in configuration structure */
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 357d99b9d0e5..235fab0bdf79 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -756,9 +756,8 @@ static ssize_t ipmi_write(struct file *file,
rv = ipmi_heartbeat();
if (rv)
return rv;
- return 1;
}
- return 0;
+ return len;
}
static ssize_t ipmi_read(struct file *file,
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 7f7e798c1384..d9a0a53c842d 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -677,12 +677,7 @@ static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag)
static void k_self(struct vc_data *vc, unsigned char value, char up_flag)
{
- unsigned int uni;
- if (kbd->kbdmode == VC_UNICODE)
- uni = value;
- else
- uni = conv_8bit_to_uni(value);
- k_unicode(vc, uni, up_flag);
+ k_unicode(vc, conv_8bit_to_uni(value), up_flag);
}
static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag)
diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c
index fa9d3c945f31..929101ecbae2 100644
--- a/drivers/char/pcmcia/ipwireless/hardware.c
+++ b/drivers/char/pcmcia/ipwireless/hardware.c
@@ -251,10 +251,11 @@ struct ipw_hardware {
int init_loops;
struct timer_list setup_timer;
+ /* Flag if hw is ready to send next packet */
int tx_ready;
- struct list_head tx_queue[NL_NUM_OF_PRIORITIES];
- /* True if any packets are queued for transmission */
+ /* Count of pending packets to be sent */
int tx_queued;
+ struct list_head tx_queue[NL_NUM_OF_PRIORITIES];
int rx_bytes_queued;
struct list_head rx_queue;
@@ -404,6 +405,8 @@ static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data,
spin_lock_irqsave(&hw->spinlock, flags);
+ hw->tx_ready = 0;
+
if (hw->hw_version == HW_VERSION_1) {
outw((unsigned short) length, hw->base_port + IODWR);
@@ -492,6 +495,7 @@ static int do_send_packet(struct ipw_hardware *hw, struct ipw_tx_packet *packet)
spin_lock_irqsave(&hw->spinlock, flags);
list_add(&packet->queue, &hw->tx_queue[0]);
+ hw->tx_queued++;
spin_unlock_irqrestore(&hw->spinlock, flags);
} else {
if (packet->packet_callback)
@@ -586,8 +590,10 @@ static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw,
packet = kmalloc(sizeof(struct ipw_rx_packet) +
old_packet->length + minimum_free_space,
GFP_ATOMIC);
- if (!packet)
+ if (!packet) {
+ kfree(old_packet);
return NULL;
+ }
memcpy(packet, old_packet,
sizeof(struct ipw_rx_packet)
+ old_packet->length);
@@ -949,12 +955,10 @@ static int send_pending_packet(struct ipw_hardware *hw, int priority_limit)
unsigned long flags;
spin_lock_irqsave(&hw->spinlock, flags);
- if (hw->tx_queued && hw->tx_ready != 0) {
+ if (hw->tx_queued && hw->tx_ready) {
int priority;
struct ipw_tx_packet *packet = NULL;
- hw->tx_ready--;
-
/* Pick a packet */
for (priority = 0; priority < priority_limit; priority++) {
if (!list_empty(&hw->tx_queue[priority])) {
@@ -963,6 +967,7 @@ static int send_pending_packet(struct ipw_hardware *hw, int priority_limit)
struct ipw_tx_packet,
queue);
+ hw->tx_queued--;
list_del(&packet->queue);
break;
@@ -973,6 +978,7 @@ static int send_pending_packet(struct ipw_hardware *hw, int priority_limit)
spin_unlock_irqrestore(&hw->spinlock, flags);
return 0;
}
+
spin_unlock_irqrestore(&hw->spinlock, flags);
/* Send */
@@ -1063,7 +1069,7 @@ static irqreturn_t ipwireless_handle_v1_interrupt(int irq,
if (irqn & IR_TXINTR) {
ack |= IR_TXINTR;
spin_lock_irqsave(&hw->spinlock, flags);
- hw->tx_ready++;
+ hw->tx_ready = 1;
spin_unlock_irqrestore(&hw->spinlock, flags);
}
/* Received data */
@@ -1170,7 +1176,7 @@ static irqreturn_t ipwireless_handle_v2_v3_interrupt(int irq,
if (memrxdone & MEMRX_RX_DONE) {
writew(0, &hw->memory_info_regs->memreg_rx_done);
spin_lock_irqsave(&hw->spinlock, flags);
- hw->tx_ready++;
+ hw->tx_ready = 1;
spin_unlock_irqrestore(&hw->spinlock, flags);
tx = 1;
}
@@ -1234,7 +1240,7 @@ static void send_packet(struct ipw_hardware *hw, int priority,
spin_lock_irqsave(&hw->spinlock, flags);
list_add_tail(&packet->queue, &hw->tx_queue[priority]);
- hw->tx_queued = 1;
+ hw->tx_queued++;
spin_unlock_irqrestore(&hw->spinlock, flags);
flush_packets_to_hw(hw);
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 10f06a6bfeb5..fa92a8af5a5a 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -679,12 +679,13 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
if (arg != (1<<tmp))
return -EINVAL;
+ rtc_freq = arg;
+
spin_lock_irqsave(&rtc_lock, flags);
if (hpet_set_periodic_freq(arg)) {
spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
}
- rtc_freq = arg;
val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
val |= (16 - tmp);
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 9e9bad8bdcf4..dbce1263bdff 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -402,6 +402,7 @@ static struct sysrq_key_op *sysrq_key_table[36] = {
&sysrq_showstate_blocked_op, /* w */
/* x: May be registered on ppc/powerpc for xmon */
NULL, /* x */
+ /* y: May be registered on sparc64 for global register dump */
NULL, /* y */
NULL /* z */
};
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 13a4bdd4e4d6..c7a977bc03e8 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -623,6 +623,7 @@ static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = {
{"IFX0102", 0}, /* Infineon */
{"BCM0101", 0}, /* Broadcom */
{"NSC1200", 0}, /* National */
+ {"ICO0102", 0}, /* Intel */
/* Add new here */
{"", 0}, /* User Specified */
{"", 0} /* Terminator */
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index eda27899372c..047a17339f83 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -3349,7 +3349,7 @@ static int send_break(struct tty_struct *tty, unsigned int duration)
msleep_interruptible(duration);
tty->ops->break_ctl(tty, 0);
tty_write_unlock(tty);
- if (!signal_pending(current))
+ if (signal_pending(current))
return -EINTR;
return 0;
}
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index b1a757a5ee27..8f81139d6194 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -981,16 +981,9 @@ EXPORT_SYMBOL_GPL(tty_perform_flush);
int n_tty_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
- struct tty_struct *real_tty;
unsigned long flags;
int retval;
- if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
- tty->driver->subtype == PTY_TYPE_MASTER)
- real_tty = tty->link;
- else
- real_tty = tty;
-
switch (cmd) {
case TCXONC:
retval = tty_check_change(tty);
diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c
index 3d3e1c2b310f..65fb848e1cce 100644
--- a/drivers/char/viocons.c
+++ b/drivers/char/viocons.c
@@ -7,7 +7,7 @@
* Authors: Dave Boutcher <boutcher@us.ibm.com>
* Ryan Arnold <ryanarn@us.ibm.com>
* Colin Devilbiss <devilbis@us.ibm.com>
- * Stephen Rothwell <sfr@au1.ibm.com>
+ * Stephen Rothwell
*
* (C) Copyright 2000, 2001, 2002, 2003, 2004 IBM Corporation
*
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index a171d894b7e7..977f7d35e769 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -6,7 +6,7 @@
* Authors: Dave Boutcher <boutcher@us.ibm.com>
* Ryan Arnold <ryanarn@us.ibm.com>
* Colin Devilbiss <devilbis@us.ibm.com>
- * Stephen Rothwell <sfr@au1.ibm.com>
+ * Stephen Rothwell
*
* (C) Copyright 2000-2004 IBM Corporation
*
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index fa1ffbf2c621..935f1c207a1f 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -434,7 +434,7 @@ static void update_attr(struct vc_data *vc)
vc->vc_blink, vc->vc_underline,
vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
- vc->vc_scrl_erase_char = (build_attr(vc, vc->vc_def_color, 1, false, false, false, false) << 8) | ' ';
+ vc->vc_scrl_erase_char = (build_attr(vc, vc->vc_def_color, 1, false, false, vc->vc_decscnm, false) << 8) | ' ';
}
/* Note: inverting the screen twice should revert to the original state */
@@ -909,7 +909,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
if (vc->vc_tty) {
struct winsize ws, *cws = &vc->vc_tty->winsize;
- unsigned long flags;
+ struct pid *pgrp = NULL;
memset(&ws, 0, sizeof(ws));
ws.ws_row = vc->vc_rows;
@@ -917,11 +917,14 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
ws.ws_ypixel = vc->vc_scan_lines;
mutex_lock(&vc->vc_tty->termios_mutex);
- spin_lock_irqsave(&vc->vc_tty->ctrl_lock, flags);
- if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&
- vc->vc_tty->pgrp)
+ spin_lock_irq(&vc->vc_tty->ctrl_lock);
+ if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col))
+ pgrp = get_pid(vc->vc_tty->pgrp);
+ spin_unlock_irq(&vc->vc_tty->ctrl_lock);
+ if (pgrp) {
kill_pgrp(vc->vc_tty->pgrp, SIGWINCH, 1);
- spin_unlock_irqrestore(&vc->vc_tty->ctrl_lock, flags);
+ put_pid(pgrp);
+ }
*cws = ws;
mutex_unlock(&vc->vc_tty->termios_mutex);
}
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index 85e2ba7fcfba..bf4830082a13 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -27,6 +27,8 @@
#include <linux/moduleparam.h>
#include <linux/connector.h>
#include <linux/mutex.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
#include <net/sock.h>
@@ -403,6 +405,40 @@ static void cn_callback(void *data)
mutex_unlock(&notify_lock);
}
+static int cn_proc_show(struct seq_file *m, void *v)
+{
+ struct cn_queue_dev *dev = cdev.cbdev;
+ struct cn_callback_entry *cbq;
+
+ seq_printf(m, "Name ID\n");
+
+ spin_lock_bh(&dev->queue_lock);
+
+ list_for_each_entry(cbq, &dev->queue_list, callback_entry) {
+ seq_printf(m, "%-15s %u:%u\n",
+ cbq->id.name,
+ cbq->id.id.idx,
+ cbq->id.id.val);
+ }
+
+ spin_unlock_bh(&dev->queue_lock);
+
+ return 0;
+}
+
+static int cn_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cn_proc_show, NULL);
+}
+
+static const struct file_operations cn_file_ops = {
+ .owner = THIS_MODULE,
+ .open = cn_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release
+};
+
static int __devinit cn_init(void)
{
struct cn_dev *dev = &cdev;
@@ -434,6 +470,8 @@ static int __devinit cn_init(void)
return -EINVAL;
}
+ proc_net_fops_create(&init_net, "connector", S_IRUGO, &cn_file_ops);
+
return 0;
}
@@ -443,6 +481,8 @@ static void __devexit cn_fini(void)
cn_already_initialized = 0;
+ proc_net_remove(&init_net, "connector");
+
cn_del_callback(&dev->id);
cn_queue_free_dev(dev->cbdev);
netlink_kernel_release(dev->nls);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 7fce038fa57e..1d41496ed2f8 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -412,7 +412,7 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
int ret;
mutex_unlock(&cpufreq_governor_mutex);
- ret = request_module(name);
+ ret = request_module("%s", name);
mutex_lock(&cpufreq_governor_mutex);
if (ret == 0)
@@ -625,7 +625,7 @@ static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy,
unsigned int freq = 0;
unsigned int ret;
- if (!policy->governor->store_setspeed)
+ if (!policy->governor || !policy->governor->store_setspeed)
return -EINVAL;
ret = sscanf(buf, "%u", &freq);
@@ -639,7 +639,7 @@ static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy,
static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf)
{
- if (!policy->governor->show_setspeed)
+ if (!policy->governor || !policy->governor->show_setspeed)
return sprintf(buf, "<unsupported>\n");
return policy->governor->show_setspeed(policy, buf);
@@ -928,13 +928,13 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
policy->user_policy.policy = policy->policy;
policy->user_policy.governor = policy->governor;
- unlock_policy_rwsem_write(cpu);
-
if (ret) {
dprintk("setting policy failed\n");
goto err_out_unregister;
}
+ unlock_policy_rwsem_write(cpu);
+
kobject_uevent(&policy->kobj, KOBJ_ADD);
module_put(cpufreq_driver->owner);
dprintk("initialization complete\n");
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index ae6cd60d5c14..b64c6bc445e3 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -2,6 +2,11 @@
* linux/drivers/cpufreq/freq_table.c
*
* Copyright (C) 2002 - 2003 Dominik Brodowski
+ *
+ * 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/kernel.h>
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index fc555a90bb21..23554b676d6e 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -38,6 +38,8 @@ static void cpuidle_kick_cpus(void)
static void cpuidle_kick_cpus(void) {}
#endif
+static int __cpuidle_register_device(struct cpuidle_device *dev);
+
/**
* cpuidle_idle_call - the main idle loop
*
@@ -138,6 +140,12 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
if (!dev->state_count)
return -EINVAL;
+ if (dev->registered == 0) {
+ ret = __cpuidle_register_device(dev);
+ if (ret)
+ return ret;
+ }
+
if ((ret = cpuidle_add_state_sysfs(dev)))
return ret;
@@ -232,10 +240,13 @@ static void poll_idle_init(struct cpuidle_device *dev) {}
#endif /* CONFIG_ARCH_HAS_CPU_RELAX */
/**
- * cpuidle_register_device - registers a CPU's idle PM feature
+ * __cpuidle_register_device - internal register function called before register
+ * and enable routines
* @dev: the cpu
+ *
+ * cpuidle_lock mutex must be held before this is called
*/
-int cpuidle_register_device(struct cpuidle_device *dev)
+static int __cpuidle_register_device(struct cpuidle_device *dev)
{
int ret;
struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu);
@@ -247,18 +258,34 @@ int cpuidle_register_device(struct cpuidle_device *dev)
init_completion(&dev->kobj_unregister);
- mutex_lock(&cpuidle_lock);
-
poll_idle_init(dev);
per_cpu(cpuidle_devices, dev->cpu) = dev;
list_add(&dev->device_list, &cpuidle_detected_devices);
if ((ret = cpuidle_add_sysfs(sys_dev))) {
- mutex_unlock(&cpuidle_lock);
module_put(cpuidle_curr_driver->owner);
return ret;
}
+ dev->registered = 1;
+ return 0;
+}
+
+/**
+ * cpuidle_register_device - registers a CPU's idle PM feature
+ * @dev: the cpu
+ */
+int cpuidle_register_device(struct cpuidle_device *dev)
+{
+ int ret;
+
+ mutex_lock(&cpuidle_lock);
+
+ if ((ret = __cpuidle_register_device(dev))) {
+ mutex_unlock(&cpuidle_lock);
+ return ret;
+ }
+
cpuidle_enable_device(dev);
cpuidle_install_idle_handler();
@@ -278,6 +305,9 @@ void cpuidle_unregister_device(struct cpuidle_device *dev)
{
struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu);
+ if (dev->registered == 0)
+ return;
+
cpuidle_pause_and_lock();
cpuidle_disable_device(dev);
diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c
index 762b729672e0..0ec0f431e6a1 100644
--- a/drivers/dma/iop-adma.c
+++ b/drivers/dma/iop-adma.c
@@ -821,10 +821,10 @@ static int __devinit iop_adma_memcpy_self_test(struct iop_adma_device *device)
dev_dbg(device->common.dev, "%s\n", __func__);
- src = kzalloc(sizeof(u8) * IOP_ADMA_TEST_SIZE, GFP_KERNEL);
+ src = kmalloc(IOP_ADMA_TEST_SIZE, GFP_KERNEL);
if (!src)
return -ENOMEM;
- dest = kzalloc(sizeof(u8) * IOP_ADMA_TEST_SIZE, GFP_KERNEL);
+ dest = kzalloc(IOP_ADMA_TEST_SIZE, GFP_KERNEL);
if (!dest) {
kfree(src);
return -ENOMEM;
@@ -834,8 +834,6 @@ static int __devinit iop_adma_memcpy_self_test(struct iop_adma_device *device)
for (i = 0; i < IOP_ADMA_TEST_SIZE; i++)
((u8 *) src)[i] = (u8)i;
- memset(dest, 0, IOP_ADMA_TEST_SIZE);
-
/* Start copy, using first DMA channel */
dma_chan = container_of(device->common.channels.next,
struct dma_chan,
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 065732ddf40c..d49361bfe670 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -20,7 +20,6 @@
#include <linux/of_platform.h>
#include <linux/of_device.h>
-#include <asm/mpc85xx.h>
#include "edac_module.h"
#include "edac_core.h"
#include "mpc85xx_edac.h"
@@ -43,8 +42,6 @@ static u32 orig_pci_err_en;
static u32 orig_l2_err_disable;
static u32 orig_hid1;
-static const char *mpc85xx_ctl_name = "MPC85xx";
-
/************************ MC SYSFS parts ***********************************/
static ssize_t mpc85xx_mc_inject_data_hi_show(struct mem_ctl_info *mci,
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index fb4d391810b6..76f26710fc16 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -1,28 +1,26 @@
-comment "An alternative FireWire stack is available with EXPERIMENTAL=y"
+comment "A new alternative FireWire stack is available with EXPERIMENTAL=y"
depends on EXPERIMENTAL=n
+comment "Enable only one of the two stacks, unless you know what you are doing"
+ depends on EXPERIMENTAL
+
config FIREWIRE
- tristate "IEEE 1394 (FireWire) support - alternative stack, EXPERIMENTAL"
+ tristate "New FireWire stack, EXPERIMENTAL"
depends on EXPERIMENTAL
select CRC_ITU_T
help
This is the "Juju" FireWire stack, a new alternative implementation
designed for robustness and simplicity. You can build either this
- stack, or the classic stack (the ieee1394 driver, ohci1394 etc.)
- or both. Please read http://wiki.linux1394.org/JujuMigration before
- you enable the new stack.
+ stack, or the old stack (the ieee1394 driver, ohci1394 etc.) or both.
+ Please read http://wiki.linux1394.org/JujuMigration before you
+ enable the new stack.
To compile this driver as a module, say M here: the module will be
called firewire-core. It functionally replaces ieee1394, raw1394,
and video1394.
- NOTE:
-
- You should only build ONE of the stacks, unless you REALLY know what
- you are doing.
-
config FIREWIRE_OHCI
- tristate "Support for OHCI FireWire host controllers"
+ tristate "OHCI-1394 controllers"
depends on PCI && FIREWIRE
help
Enable this driver if you have a FireWire controller based
@@ -33,12 +31,12 @@ config FIREWIRE_OHCI
called firewire-ohci. It replaces ohci1394 of the classic IEEE 1394
stack.
- NOTE:
+ NOTE:
- You should only build ohci1394 or firewire-ohci, but not both.
- If you nevertheless want to install both, you should configure them
- only as modules and blacklist the driver(s) which you don't want to
- have auto-loaded. Add either
+ You should only build either firewire-ohci or the old ohci1394 driver,
+ but not both. If you nevertheless want to install both, you should
+ configure them only as modules and blacklist the driver(s) which you
+ don't want to have auto-loaded. Add either
blacklist firewire-ohci
or
@@ -60,7 +58,7 @@ config FIREWIRE_OHCI_DEBUG
default y
config FIREWIRE_SBP2
- tristate "Support for storage devices (SBP-2 protocol driver)"
+ tristate "Storage devices (SBP-2 protocol)"
depends on FIREWIRE && SCSI
help
This option enables you to use SBP-2 devices connected to a
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c
index 4a541921a14a..c639915fc3cb 100644
--- a/drivers/firewire/fw-cdev.c
+++ b/drivers/firewire/fw-cdev.c
@@ -113,6 +113,11 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
if (device == NULL)
return -ENODEV;
+ if (fw_device_is_shutdown(device)) {
+ fw_device_put(device);
+ return -ENODEV;
+ }
+
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (client == NULL) {
fw_device_put(device);
@@ -200,6 +205,7 @@ fw_device_op_read(struct file *file,
return dequeue_event(client, buffer, count);
}
+/* caller must hold card->lock so that node pointers can be dereferenced here */
static void
fill_bus_reset_event(struct fw_cdev_event_bus_reset *event,
struct client *client)
@@ -209,7 +215,6 @@ fill_bus_reset_event(struct fw_cdev_event_bus_reset *event,
event->closure = client->bus_reset_closure;
event->type = FW_CDEV_EVENT_BUS_RESET;
event->generation = client->device->generation;
- smp_rmb(); /* node_id must not be older than generation */
event->node_id = client->device->node_id;
event->local_node_id = card->local_node->node_id;
event->bm_node_id = 0; /* FIXME: We don't track the BM. */
@@ -269,6 +274,7 @@ static int ioctl_get_info(struct client *client, void *buffer)
{
struct fw_cdev_get_info *get_info = buffer;
struct fw_cdev_event_bus_reset bus_reset;
+ struct fw_card *card = client->device->card;
unsigned long ret = 0;
client->version = get_info->version;
@@ -294,13 +300,17 @@ static int ioctl_get_info(struct client *client, void *buffer)
client->bus_reset_closure = get_info->bus_reset_closure;
if (get_info->bus_reset != 0) {
void __user *uptr = u64_to_uptr(get_info->bus_reset);
+ unsigned long flags;
+ spin_lock_irqsave(&card->lock, flags);
fill_bus_reset_event(&bus_reset, client);
+ spin_unlock_irqrestore(&card->lock, flags);
+
if (copy_to_user(uptr, &bus_reset, sizeof(bus_reset)))
return -EFAULT;
}
- get_info->card = client->device->card->index;
+ get_info->card = card->index;
return 0;
}
@@ -901,6 +911,9 @@ fw_device_op_ioctl(struct file *file,
{
struct client *client = file->private_data;
+ if (fw_device_is_shutdown(client->device))
+ return -ENODEV;
+
return dispatch_ioctl(client, cmd, (void __user *) arg);
}
@@ -911,6 +924,9 @@ fw_device_op_compat_ioctl(struct file *file,
{
struct client *client = file->private_data;
+ if (fw_device_is_shutdown(client->device))
+ return -ENODEV;
+
return dispatch_ioctl(client, cmd, compat_ptr(arg));
}
#endif
@@ -922,6 +938,9 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
unsigned long size;
int page_count, retval;
+ if (fw_device_is_shutdown(client->device))
+ return -ENODEV;
+
/* FIXME: We could support multiple buffers, but we don't. */
if (client->buffer.pages != NULL)
return -EBUSY;
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c
index 4f02c55f13e1..0b66306af479 100644
--- a/drivers/firewire/fw-ohci.c
+++ b/drivers/firewire/fw-ohci.c
@@ -265,27 +265,25 @@ static void log_irqs(u32 evt)
!(evt & OHCI1394_busReset))
return;
- printk(KERN_DEBUG KBUILD_MODNAME ": IRQ "
- "%08x%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
- evt,
- evt & OHCI1394_selfIDComplete ? " selfID" : "",
- evt & OHCI1394_RQPkt ? " AR_req" : "",
- evt & OHCI1394_RSPkt ? " AR_resp" : "",
- evt & OHCI1394_reqTxComplete ? " AT_req" : "",
- evt & OHCI1394_respTxComplete ? " AT_resp" : "",
- evt & OHCI1394_isochRx ? " IR" : "",
- evt & OHCI1394_isochTx ? " IT" : "",
- evt & OHCI1394_postedWriteErr ? " postedWriteErr" : "",
- evt & OHCI1394_cycleTooLong ? " cycleTooLong" : "",
- evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "",
- evt & OHCI1394_regAccessFail ? " regAccessFail" : "",
- evt & OHCI1394_busReset ? " busReset" : "",
- evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt |
- OHCI1394_RSPkt | OHCI1394_reqTxComplete |
- OHCI1394_respTxComplete | OHCI1394_isochRx |
- OHCI1394_isochTx | OHCI1394_postedWriteErr |
- OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds |
- OHCI1394_regAccessFail | OHCI1394_busReset)
+ fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,
+ evt & OHCI1394_selfIDComplete ? " selfID" : "",
+ evt & OHCI1394_RQPkt ? " AR_req" : "",
+ evt & OHCI1394_RSPkt ? " AR_resp" : "",
+ evt & OHCI1394_reqTxComplete ? " AT_req" : "",
+ evt & OHCI1394_respTxComplete ? " AT_resp" : "",
+ evt & OHCI1394_isochRx ? " IR" : "",
+ evt & OHCI1394_isochTx ? " IT" : "",
+ evt & OHCI1394_postedWriteErr ? " postedWriteErr" : "",
+ evt & OHCI1394_cycleTooLong ? " cycleTooLong" : "",
+ evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "",
+ evt & OHCI1394_regAccessFail ? " regAccessFail" : "",
+ evt & OHCI1394_busReset ? " busReset" : "",
+ evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt |
+ OHCI1394_RSPkt | OHCI1394_reqTxComplete |
+ OHCI1394_respTxComplete | OHCI1394_isochRx |
+ OHCI1394_isochTx | OHCI1394_postedWriteErr |
+ OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds |
+ OHCI1394_regAccessFail | OHCI1394_busReset)
? " ?" : "");
}
@@ -308,23 +306,22 @@ static void log_selfids(int node_id, int generation, int self_id_count, u32 *s)
if (likely(!(param_debug & OHCI_PARAM_DEBUG_SELFIDS)))
return;
- printk(KERN_DEBUG KBUILD_MODNAME ": %d selfIDs, generation %d, "
- "local node ID %04x\n", self_id_count, generation, node_id);
+ fw_notify("%d selfIDs, generation %d, local node ID %04x\n",
+ self_id_count, generation, node_id);
for (; self_id_count--; ++s)
if ((*s & 1 << 23) == 0)
- printk(KERN_DEBUG "selfID 0: %08x, phy %d [%c%c%c] "
- "%s gc=%d %s %s%s%s\n",
- *s, *s >> 24 & 63, _p(s, 6), _p(s, 4), _p(s, 2),
- speed[*s >> 14 & 3], *s >> 16 & 63,
- power[*s >> 8 & 7], *s >> 22 & 1 ? "L" : "",
- *s >> 11 & 1 ? "c" : "", *s & 2 ? "i" : "");
+ fw_notify("selfID 0: %08x, phy %d [%c%c%c] "
+ "%s gc=%d %s %s%s%s\n",
+ *s, *s >> 24 & 63, _p(s, 6), _p(s, 4), _p(s, 2),
+ speed[*s >> 14 & 3], *s >> 16 & 63,
+ power[*s >> 8 & 7], *s >> 22 & 1 ? "L" : "",
+ *s >> 11 & 1 ? "c" : "", *s & 2 ? "i" : "");
else
- printk(KERN_DEBUG "selfID n: %08x, phy %d "
- "[%c%c%c%c%c%c%c%c]\n",
- *s, *s >> 24 & 63,
- _p(s, 16), _p(s, 14), _p(s, 12), _p(s, 10),
- _p(s, 8), _p(s, 6), _p(s, 4), _p(s, 2));
+ fw_notify("selfID n: %08x, phy %d [%c%c%c%c%c%c%c%c]\n",
+ *s, *s >> 24 & 63,
+ _p(s, 16), _p(s, 14), _p(s, 12), _p(s, 10),
+ _p(s, 8), _p(s, 6), _p(s, 4), _p(s, 2));
}
static const char *evts[] = {
@@ -373,15 +370,14 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt)
evt = 0x1f;
if (evt == OHCI1394_evt_bus_reset) {
- printk(KERN_DEBUG "A%c evt_bus_reset, generation %d\n",
- dir, (header[2] >> 16) & 0xff);
+ fw_notify("A%c evt_bus_reset, generation %d\n",
+ dir, (header[2] >> 16) & 0xff);
return;
}
if (header[0] == ~header[1]) {
- printk(KERN_DEBUG "A%c %s, %s, %08x\n",
- dir, evts[evt], phys[header[0] >> 30 & 0x3],
- header[0]);
+ fw_notify("A%c %s, %s, %08x\n",
+ dir, evts[evt], phys[header[0] >> 30 & 0x3], header[0]);
return;
}
@@ -400,24 +396,23 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt)
switch (tcode) {
case 0xe: case 0xa:
- printk(KERN_DEBUG "A%c %s, %s\n",
- dir, evts[evt], tcodes[tcode]);
+ fw_notify("A%c %s, %s\n", dir, evts[evt], tcodes[tcode]);
break;
case 0x0: case 0x1: case 0x4: case 0x5: case 0x9:
- printk(KERN_DEBUG "A%c spd %x tl %02x, "
- "%04x -> %04x, %s, "
- "%s, %04x%08x%s\n",
- dir, speed, header[0] >> 10 & 0x3f,
- header[1] >> 16, header[0] >> 16, evts[evt],
- tcodes[tcode], header[1] & 0xffff, header[2], specific);
+ fw_notify("A%c spd %x tl %02x, "
+ "%04x -> %04x, %s, "
+ "%s, %04x%08x%s\n",
+ dir, speed, header[0] >> 10 & 0x3f,
+ header[1] >> 16, header[0] >> 16, evts[evt],
+ tcodes[tcode], header[1] & 0xffff, header[2], specific);
break;
default:
- printk(KERN_DEBUG "A%c spd %x tl %02x, "
- "%04x -> %04x, %s, "
- "%s%s\n",
- dir, speed, header[0] >> 10 & 0x3f,
- header[1] >> 16, header[0] >> 16, evts[evt],
- tcodes[tcode], specific);
+ fw_notify("A%c spd %x tl %02x, "
+ "%04x -> %04x, %s, "
+ "%s%s\n",
+ dir, speed, header[0] >> 10 & 0x3f,
+ header[1] >> 16, header[0] >> 16, evts[evt],
+ tcodes[tcode], specific);
}
}
@@ -548,6 +543,11 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
p.header_length = 12;
p.payload_length = 0;
break;
+
+ default:
+ /* FIXME: Stop context, discard everything, and restart? */
+ p.header_length = 0;
+ p.payload_length = 0;
}
p.payload = (void *) buffer + p.header_length;
@@ -1468,6 +1468,9 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
reg_write(ohci, OHCI1394_HCControlClear,
OHCI1394_HCControl_noByteSwapData);
+ reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus);
+ reg_write(ohci, OHCI1394_LinkControlClear,
+ OHCI1394_LinkControl_rcvPhyPkt);
reg_write(ohci, OHCI1394_LinkControlSet,
OHCI1394_LinkControl_rcvSelfID |
OHCI1394_LinkControl_cycleTimerEnable |
@@ -1481,7 +1484,6 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
ar_context_run(&ohci->ar_request_ctx);
ar_context_run(&ohci->ar_response_ctx);
- reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus);
reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000);
reg_write(ohci, OHCI1394_IntEventClear, ~0);
reg_write(ohci, OHCI1394_IntMaskClear, ~0);
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index b2458bb8e9ca..227d2e036cd8 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -1051,7 +1051,8 @@ static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory,
break;
case SBP2_CSR_LOGICAL_UNIT_DIRECTORY:
- if (sbp2_scan_logical_unit_dir(tgt, ci.p + value) < 0)
+ /* Adjust for the increment in the iterator */
+ if (sbp2_scan_logical_unit_dir(tgt, ci.p - 1 + value) < 0)
return -ENOMEM;
break;
}
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c
index ccf0e4cf108f..03ae8a77c479 100644
--- a/drivers/firewire/fw-transaction.c
+++ b/drivers/firewire/fw-transaction.c
@@ -20,6 +20,7 @@
#include <linux/completion.h>
#include <linux/kernel.h>
+#include <linux/kref.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -297,37 +298,55 @@ EXPORT_SYMBOL(fw_send_request);
struct fw_phy_packet {
struct fw_packet packet;
struct completion done;
+ struct kref kref;
};
-static void
-transmit_phy_packet_callback(struct fw_packet *packet,
- struct fw_card *card, int status)
+static void phy_packet_release(struct kref *kref)
+{
+ struct fw_phy_packet *p =
+ container_of(kref, struct fw_phy_packet, kref);
+ kfree(p);
+}
+
+static void transmit_phy_packet_callback(struct fw_packet *packet,
+ struct fw_card *card, int status)
{
struct fw_phy_packet *p =
container_of(packet, struct fw_phy_packet, packet);
complete(&p->done);
+ kref_put(&p->kref, phy_packet_release);
}
void fw_send_phy_config(struct fw_card *card,
int node_id, int generation, int gap_count)
{
- struct fw_phy_packet p;
+ struct fw_phy_packet *p;
+ long timeout = DIV_ROUND_UP(HZ, 10);
u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) |
PHY_CONFIG_ROOT_ID(node_id) |
PHY_CONFIG_GAP_COUNT(gap_count);
- p.packet.header[0] = data;
- p.packet.header[1] = ~data;
- p.packet.header_length = 8;
- p.packet.payload_length = 0;
- p.packet.speed = SCODE_100;
- p.packet.generation = generation;
- p.packet.callback = transmit_phy_packet_callback;
- init_completion(&p.done);
-
- card->driver->send_request(card, &p.packet);
- wait_for_completion(&p.done);
+ p = kmalloc(sizeof(*p), GFP_KERNEL);
+ if (p == NULL)
+ return;
+
+ p->packet.header[0] = data;
+ p->packet.header[1] = ~data;
+ p->packet.header_length = 8;
+ p->packet.payload_length = 0;
+ p->packet.speed = SCODE_100;
+ p->packet.generation = generation;
+ p->packet.callback = transmit_phy_packet_callback;
+ init_completion(&p->done);
+ kref_set(&p->kref, 2);
+
+ card->driver->send_request(card, &p->packet);
+ timeout = wait_for_completion_timeout(&p->done, timeout);
+ kref_put(&p->kref, phy_packet_release);
+
+ /* will leak p if the callback is never executed */
+ WARN_ON(timeout == 0);
}
void fw_flush_transactions(struct fw_card *card)
@@ -572,7 +591,8 @@ allocate_request(struct fw_packet *p)
break;
default:
- BUG();
+ fw_error("ERROR - corrupt request received - %08x %08x %08x\n",
+ p->header[0], p->header[1], p->header[2]);
return NULL;
}
diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
index 744011989044..9e4f59dc7f1e 100644
--- a/drivers/firmware/edd.c
+++ b/drivers/firmware/edd.c
@@ -753,7 +753,7 @@ edd_init(void)
if (!edd_num_devices()) {
printk(KERN_INFO "EDD information not available.\n");
- return 1;
+ return -ENODEV;
}
edd_kset = kset_create_and_add("edd", NULL, firmware_kobj);
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index bbd28342e771..008c38ba774f 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -28,12 +28,18 @@ config DEBUG_GPIO
comment "I2C GPIO expanders:"
config GPIO_PCA953X
- tristate "PCA953x I/O ports"
+ tristate "PCA953x, PCA955x, and MAX7310 I/O ports"
depends on I2C
help
- Say yes here to support the PCA9534 (8-bit), PCA9535 (16-bit),
- PCA9536 (4-bit), PCA9537 (4-bit), PCA9538 (8-bit), and PCA9539
- (16-bit) I/O ports. These parts are made by NXP and TI.
+ Say yes here to provide access to several register-oriented
+ SMBus I/O expanders, made mostly by NXP or TI. Compatible
+ models include:
+
+ 4 bits: pca9536, pca9537
+
+ 8 bits: max7310, pca9534, pca9538, pca9554, pca9557
+
+ 16 bits: pca9535, pca9539, pca9555
This driver can also be built as a module. If so, the module
will be called pca953x.
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 7f138c6195ff..beaf6b3a37dc 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -127,7 +127,7 @@ int __init gpiochip_reserve(int start, int ngpio)
unsigned long flags;
int i;
- if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio))
+ if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio - 1))
return -EINVAL;
spin_lock_irqsave(&gpio_lock, flags);
@@ -170,7 +170,7 @@ int gpiochip_add(struct gpio_chip *chip)
unsigned id;
int base = chip->base;
- if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio))
+ if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))
&& base >= 0) {
status = -EINVAL;
goto fail;
@@ -207,7 +207,7 @@ fail:
/* failures here can mean systems won't boot... */
if (status)
pr_err("gpiochip_add: gpios %d..%d (%s) not registered\n",
- chip->base, chip->base + chip->ngpio,
+ chip->base, chip->base + chip->ngpio - 1,
chip->label ? : "generic");
return status;
}
diff --git a/drivers/gpio/mcp23s08.c b/drivers/gpio/mcp23s08.c
index 7fb5b9d009d4..7f92fdd5f0e2 100644
--- a/drivers/gpio/mcp23s08.c
+++ b/drivers/gpio/mcp23s08.c
@@ -168,7 +168,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
struct mcp23s08 *mcp;
char bank;
- unsigned t;
+ int t;
unsigned mask;
mcp = container_of(chip, struct mcp23s08, chip);
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index 93f916720b13..a380730b61ab 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -30,9 +30,10 @@ static const struct i2c_device_id pca953x_id[] = {
{ "pca9537", 4, },
{ "pca9538", 8, },
{ "pca9539", 16, },
+ { "pca9554", 8, },
{ "pca9555", 16, },
{ "pca9557", 8, },
- /* REVISIT several pca955x parts should work here too */
+ { "max7310", 8, },
{ }
};
MODULE_DEVICE_TABLE(i2c, pca953x_id);
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index f88714b06000..47ac1a7d66e1 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -1,6 +1,4 @@
/*
- * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $
- *
* (c) 1999 Andreas Gal <gal@cs.uni-magdeburg.de>
* (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
* (c) 2007 Jiri Kosina
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index c3eb3f13e2ca..5c52a20ad344 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -1,6 +1,4 @@
/*
- * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $
- *
* Copyright (c) 2000-2001 Vojtech Pavlik
* Copyright (c) 2006-2007 Jiri Kosina
*
@@ -218,8 +216,9 @@ int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
}
}
- if (test_bit(usage->code, hid->pb_pressed_numlock) ||
- test_bit(LED_NUML, input->led)) {
+ if (hid->quirks & HID_QUIRK_APPLE_NUMLOCK_EMULATION && (
+ test_bit(usage->code, hid->pb_pressed_numlock) ||
+ test_bit(LED_NUML, input->led))) {
trans = find_translation(powerbook_numlock_keys, usage->code);
if (trans) {
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index d3f8d9194f30..1df832a8fcbc 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -325,6 +325,10 @@
#define USB_DEVICE_ID_MGE_UPS 0xffff
#define USB_DEVICE_ID_MGE_UPS1 0x0001
+#define USB_VENDOR_ID_MICROCHIP 0x04d8
+#define USB_DEVICE_ID_PICKIT1 0x0032
+#define USB_DEVICE_ID_PICKIT2 0x0033
+
#define USB_VENDOR_ID_MICROSOFT 0x045e
#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
@@ -371,6 +375,9 @@
#define USB_VENDOR_ID_SONY 0x054c
#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
+#define USB_VENDOR_ID_SOUNDGRAPH 0x15c2
+#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD 0x0038
+
#define USB_VENDOR_ID_SUN 0x0430
#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
@@ -567,6 +574,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE },
@@ -580,6 +588,9 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2, HID_QUIRK_IGNORE },
+
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP },
@@ -611,28 +622,28 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI, HID_QUIRK_APPLE_HAS_FN },
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD },
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS, HID_QUIRK_APPLE_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI, HID_QUIRK_APPLE_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS, HID_QUIRK_APPLE_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
{ USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD, HID_QUIRK_RESET_LEDS },
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
index 5d9dbb47e4a8..3cd46d2e53c1 100644
--- a/drivers/hid/usbhid/usbkbd.c
+++ b/drivers/hid/usbhid/usbkbd.c
@@ -1,6 +1,4 @@
/*
- * $Id: usbkbd.c,v 1.27 2001/12/27 10:37:41 vojtech Exp $
- *
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* USB HIDBP Keyboard support
diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
index df0d96d989de..703e9d0e8714 100644
--- a/drivers/hid/usbhid/usbmouse.c
+++ b/drivers/hid/usbhid/usbmouse.c
@@ -1,6 +1,4 @@
/*
- * $Id: usbmouse.c,v 1.15 2001/12/27 10:37:41 vojtech Exp $
- *
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* USB HIDBP Mouse support
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 4dc76bc45c9d..00ff53348491 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -330,6 +330,20 @@ config SENSORS_CORETEMP
sensor inside your CPU. Supported all are all known variants
of Intel Core family.
+config SENSORS_IBMAEM
+ tristate "IBM Active Energy Manager temperature/power sensors and control"
+ select IPMI_SI
+ depends on IPMI_HANDLER
+ help
+ If you say yes here you get support for the temperature and
+ power sensors and capping hardware in various IBM System X
+ servers that support Active Energy Manager. This includes
+ the x3350, x3550, x3650, x3655, x3755, x3850 M2, x3950 M2,
+ and certain HS2x/LS2x/QS2x blades.
+
+ This driver can also be built as a module. If so, the module
+ will be called ibmaem.
+
config SENSORS_IBMPEX
tristate "IBM PowerExecutive temperature/power sensors"
select IPMI_SI
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 3bdb05a5cbd7..d098677e08de 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
+obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
obj-$(CONFIG_SENSORS_IT87) += it87.o
obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
index ed33fddc4dee..f00f497b9ca9 100644
--- a/drivers/hwmon/abituguru3.c
+++ b/drivers/hwmon/abituguru3.c
@@ -30,6 +30,7 @@
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/dmi.h>
#include <asm/io.h>
/* uGuru3 bank addresses */
@@ -323,7 +324,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
{ "AUX1 Fan", 36, 2, 60, 1, 0 },
{ NULL, 0, 0, 0, 0, 0 } }
},
- { 0x0013, "unknown", {
+ { 0x0013, "Abit AW8D", {
{ "CPU Core", 0, 0, 10, 1, 0 },
{ "DDR", 1, 0, 10, 1, 0 },
{ "DDR VTT", 2, 0, 10, 1, 0 },
@@ -349,6 +350,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
{ "AUX2 Fan", 36, 2, 60, 1, 0 },
{ "AUX3 Fan", 37, 2, 60, 1, 0 },
{ "AUX4 Fan", 38, 2, 60, 1, 0 },
+ { "AUX5 Fan", 39, 2, 60, 1, 0 },
{ NULL, 0, 0, 0, 0, 0 } }
},
{ 0x0014, "Abit AB9 Pro", {
@@ -1111,11 +1113,12 @@ static int __init abituguru3_detect(void)
{
/* See if there is an uguru3 there. An idle uGuru3 will hold 0x00 or
0x08 at DATA and 0xAC at CMD. Sometimes the uGuru3 will hold 0x05
- at CMD instead, why is unknown. So we test for 0x05 too. */
+ or 0x55 at CMD instead, why is unknown. */
u8 data_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_DATA);
u8 cmd_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_CMD);
if (((data_val == 0x00) || (data_val == 0x08)) &&
- ((cmd_val == 0xAC) || (cmd_val == 0x05)))
+ ((cmd_val == 0xAC) || (cmd_val == 0x05) ||
+ (cmd_val == 0x55)))
return ABIT_UGURU3_BASE;
ABIT_UGURU3_DEBUG("no Abit uGuru3 found, data = 0x%02X, cmd = "
@@ -1138,6 +1141,15 @@ static int __init abituguru3_init(void)
int address, err;
struct resource res = { .flags = IORESOURCE_IO };
+#ifdef CONFIG_DMI
+ const char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+
+ /* safety check, refuse to load on non Abit motherboards */
+ if (!force && (!board_vendor ||
+ strcmp(board_vendor, "http://www.abit.com.tw/")))
+ return -ENODEV;
+#endif
+
address = abituguru3_detect();
if (address < 0)
return address;
diff --git a/drivers/hwmon/adt7473.c b/drivers/hwmon/adt7473.c
index c1009d6f9796..93dbf5e7ff8a 100644
--- a/drivers/hwmon/adt7473.c
+++ b/drivers/hwmon/adt7473.c
@@ -309,6 +309,9 @@ no_sensor_update:
ADT7473_REG_PWM_BHVR(i));
}
+ i = i2c_smbus_read_byte_data(client, ADT7473_REG_CFG4);
+ data->max_duty_at_overheat = !!(i & ADT7473_CFG4_MAX_DUTY_AT_OVT);
+
data->limits_last_updated = local_jiffies;
data->limits_valid = 1;
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index bab5fd2e4dfd..50f22690d611 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -515,16 +515,24 @@ static struct dmi_system_id __initdata hdaps_whitelist[] = {
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R50"),
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R51"),
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R52"),
+ HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i"),
+ HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61"),
HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p"),
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T41"),
HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p"),
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T42"),
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T43"),
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60"),
+ HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p"),
+ HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61"),
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X40"),
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X41"),
HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60"),
+ HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s"),
+ HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61"),
HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"),
+ HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m"),
+ HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p"),
{ .ident = NULL }
};
diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c
index 6ac5c6f53585..f9e2ed621f7b 100644
--- a/drivers/hwmon/i5k_amb.c
+++ b/drivers/hwmon/i5k_amb.c
@@ -111,6 +111,7 @@ struct i5k_amb_data {
void __iomem *amb_mmio;
struct i5k_device_attribute *attrs;
unsigned int num_attrs;
+ unsigned long chipset_id;
};
static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
@@ -382,7 +383,8 @@ err:
return res;
}
-static int __devinit i5k_find_amb_registers(struct i5k_amb_data *data)
+static int __devinit i5k_find_amb_registers(struct i5k_amb_data *data,
+ unsigned long devid)
{
struct pci_dev *pcidev;
u32 val32;
@@ -390,7 +392,7 @@ static int __devinit i5k_find_amb_registers(struct i5k_amb_data *data)
/* Find AMB register memory space */
pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_5000_ERR,
+ devid,
NULL);
if (!pcidev)
return -ENODEV;
@@ -409,6 +411,8 @@ static int __devinit i5k_find_amb_registers(struct i5k_amb_data *data)
goto out;
}
+ data->chipset_id = devid;
+
res = 0;
out:
pci_dev_put(pcidev);
@@ -441,10 +445,30 @@ out:
return res;
}
+static unsigned long i5k_channel_pci_id(struct i5k_amb_data *data,
+ unsigned long channel)
+{
+ switch (data->chipset_id) {
+ case PCI_DEVICE_ID_INTEL_5000_ERR:
+ return PCI_DEVICE_ID_INTEL_5000_FBD0 + channel;
+ case PCI_DEVICE_ID_INTEL_5400_ERR:
+ return PCI_DEVICE_ID_INTEL_5400_FBD0 + channel;
+ default:
+ BUG();
+ }
+}
+
+static unsigned long chipset_ids[] = {
+ PCI_DEVICE_ID_INTEL_5000_ERR,
+ PCI_DEVICE_ID_INTEL_5400_ERR,
+ 0
+};
+
static int __devinit i5k_amb_probe(struct platform_device *pdev)
{
struct i5k_amb_data *data;
struct resource *reso;
+ int i;
int res = -ENODEV;
data = kzalloc(sizeof(*data), GFP_KERNEL);
@@ -452,19 +476,24 @@ static int __devinit i5k_amb_probe(struct platform_device *pdev)
return -ENOMEM;
/* Figure out where the AMB registers live */
- res = i5k_find_amb_registers(data);
+ i = 0;
+ do {
+ res = i5k_find_amb_registers(data, chipset_ids[i]);
+ i++;
+ } while (res && chipset_ids[i]);
+
if (res)
goto err;
/* Copy the DIMM presence map for the first two channels */
res = i5k_channel_probe(&data->amb_present[0],
- PCI_DEVICE_ID_INTEL_5000_FBD0);
+ i5k_channel_pci_id(data, 0));
if (res)
goto err;
/* Copy the DIMM presence map for the optional second two channels */
i5k_channel_probe(&data->amb_present[2],
- PCI_DEVICE_ID_INTEL_5000_FBD1);
+ i5k_channel_pci_id(data, 1));
/* Set up resource regions */
reso = request_mem_region(data->amb_base, data->amb_len, DRVNAME);
diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c
new file mode 100644
index 000000000000..c9416e657487
--- /dev/null
+++ b/drivers/hwmon/ibmaem.c
@@ -0,0 +1,1111 @@
+/*
+ * A hwmon driver for the IBM Active Energy Manager temperature/power sensors
+ * and capping functionality.
+ * Copyright (C) 2008 IBM
+ *
+ * Author: Darrick J. Wong <djwong@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ */
+
+#include <linux/ipmi.h>
+#include <linux/module.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/kdev_t.h>
+#include <linux/spinlock.h>
+#include <linux/idr.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/math64.h>
+#include <linux/time.h>
+
+#define REFRESH_INTERVAL (HZ)
+#define IPMI_TIMEOUT (30 * HZ)
+#define DRVNAME "aem"
+
+#define AEM_NETFN 0x2E
+
+#define AEM_FIND_FW_CMD 0x80
+#define AEM_ELEMENT_CMD 0x81
+#define AEM_FW_INSTANCE_CMD 0x82
+
+#define AEM_READ_ELEMENT_CFG 0x80
+#define AEM_READ_BUFFER 0x81
+#define AEM_READ_REGISTER 0x82
+#define AEM_WRITE_REGISTER 0x83
+#define AEM_SET_REG_MASK 0x84
+#define AEM_CLEAR_REG_MASK 0x85
+#define AEM_READ_ELEMENT_CFG2 0x86
+
+#define AEM_CONTROL_ELEMENT 0
+#define AEM_ENERGY_ELEMENT 1
+#define AEM_CLOCK_ELEMENT 4
+#define AEM_POWER_CAP_ELEMENT 7
+#define AEM_EXHAUST_ELEMENT 9
+#define AEM_POWER_ELEMENT 10
+
+#define AEM_MODULE_TYPE_ID 0x0001
+
+#define AEM2_NUM_ENERGY_REGS 2
+#define AEM2_NUM_PCAP_REGS 6
+#define AEM2_NUM_TEMP_REGS 2
+#define AEM2_NUM_SENSORS 14
+
+#define AEM1_NUM_ENERGY_REGS 1
+#define AEM1_NUM_SENSORS 3
+
+/* AEM 2.x has more energy registers */
+#define AEM_NUM_ENERGY_REGS AEM2_NUM_ENERGY_REGS
+/* AEM 2.x needs more sensor files */
+#define AEM_NUM_SENSORS AEM2_NUM_SENSORS
+
+#define POWER_CAP 0
+#define POWER_CAP_MAX_HOTPLUG 1
+#define POWER_CAP_MAX 2
+#define POWER_CAP_MIN_WARNING 3
+#define POWER_CAP_MIN 4
+#define POWER_AUX 5
+
+#define AEM_DEFAULT_POWER_INTERVAL 1000
+#define AEM_MIN_POWER_INTERVAL 200
+#define UJ_PER_MJ 1000L
+
+static DEFINE_IDR(aem_idr);
+static DEFINE_SPINLOCK(aem_idr_lock);
+
+static struct device_driver aem_driver = {
+ .name = DRVNAME,
+ .bus = &platform_bus_type,
+};
+
+struct aem_ipmi_data {
+ struct completion read_complete;
+ struct ipmi_addr address;
+ ipmi_user_t user;
+ int interface;
+
+ struct kernel_ipmi_msg tx_message;
+ long tx_msgid;
+
+ void *rx_msg_data;
+ unsigned short rx_msg_len;
+ unsigned char rx_result;
+ int rx_recv_type;
+
+ struct device *bmc_device;
+};
+
+struct aem_ro_sensor_template {
+ char *label;
+ ssize_t (*show)(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf);
+ int index;
+};
+
+struct aem_rw_sensor_template {
+ char *label;
+ ssize_t (*show)(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf);
+ ssize_t (*set)(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count);
+ int index;
+};
+
+struct aem_data {
+ struct list_head list;
+
+ struct device *hwmon_dev;
+ struct platform_device *pdev;
+ struct mutex lock;
+ char valid;
+ unsigned long last_updated; /* In jiffies */
+ u8 ver_major;
+ u8 ver_minor;
+ u8 module_handle;
+ int id;
+ struct aem_ipmi_data ipmi;
+
+ /* Function to update sensors */
+ void (*update)(struct aem_data *data);
+
+ /*
+ * AEM 1.x sensors:
+ * Available sensors:
+ * Energy meter
+ * Power meter
+ *
+ * AEM 2.x sensors:
+ * Two energy meters
+ * Two power meters
+ * Two temperature sensors
+ * Six power cap registers
+ */
+
+ /* sysfs attrs */
+ struct sensor_device_attribute sensors[AEM_NUM_SENSORS];
+
+ /* energy use in mJ */
+ u64 energy[AEM_NUM_ENERGY_REGS];
+
+ /* power sampling interval in ms */
+ unsigned long power_period[AEM_NUM_ENERGY_REGS];
+
+ /* Everything past here is for AEM2 only */
+
+ /* power caps in dW */
+ u16 pcap[AEM2_NUM_PCAP_REGS];
+
+ /* exhaust temperature in C */
+ u8 temp[AEM2_NUM_TEMP_REGS];
+};
+
+/* Data structures returned by the AEM firmware */
+struct aem_iana_id {
+ u8 bytes[3];
+};
+static struct aem_iana_id system_x_id = {
+ .bytes = {0x4D, 0x4F, 0x00}
+};
+
+/* These are used to find AEM1 instances */
+struct aem_find_firmware_req {
+ struct aem_iana_id id;
+ u8 rsvd;
+ __be16 index;
+ __be16 module_type_id;
+} __packed;
+
+struct aem_find_firmware_resp {
+ struct aem_iana_id id;
+ u8 num_instances;
+} __packed;
+
+/* These are used to find AEM2 instances */
+struct aem_find_instance_req {
+ struct aem_iana_id id;
+ u8 instance_number;
+ __be16 module_type_id;
+} __packed;
+
+struct aem_find_instance_resp {
+ struct aem_iana_id id;
+ u8 num_instances;
+ u8 major;
+ u8 minor;
+ u8 module_handle;
+ u16 record_id;
+} __packed;
+
+/* These are used to query sensors */
+struct aem_read_sensor_req {
+ struct aem_iana_id id;
+ u8 module_handle;
+ u8 element;
+ u8 subcommand;
+ u8 reg;
+ u8 rx_buf_size;
+} __packed;
+
+struct aem_read_sensor_resp {
+ struct aem_iana_id id;
+ u8 bytes[0];
+} __packed;
+
+/* Data structures to talk to the IPMI layer */
+struct aem_driver_data {
+ struct list_head aem_devices;
+ struct ipmi_smi_watcher bmc_events;
+ struct ipmi_user_hndl ipmi_hndlrs;
+};
+
+static void aem_register_bmc(int iface, struct device *dev);
+static void aem_bmc_gone(int iface);
+static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data);
+
+static void aem_remove_sensors(struct aem_data *data);
+static int aem_init_aem1(struct aem_ipmi_data *probe);
+static int aem_init_aem2(struct aem_ipmi_data *probe);
+static int aem1_find_sensors(struct aem_data *data);
+static int aem2_find_sensors(struct aem_data *data);
+static void update_aem1_sensors(struct aem_data *data);
+static void update_aem2_sensors(struct aem_data *data);
+
+static struct aem_driver_data driver_data = {
+ .aem_devices = LIST_HEAD_INIT(driver_data.aem_devices),
+ .bmc_events = {
+ .owner = THIS_MODULE,
+ .new_smi = aem_register_bmc,
+ .smi_gone = aem_bmc_gone,
+ },
+ .ipmi_hndlrs = {
+ .ipmi_recv_hndl = aem_msg_handler,
+ },
+};
+
+/* Functions to talk to the IPMI layer */
+
+/* Initialize IPMI address, message buffers and user data */
+static int aem_init_ipmi_data(struct aem_ipmi_data *data, int iface,
+ struct device *bmc)
+{
+ int err;
+
+ init_completion(&data->read_complete);
+ data->bmc_device = bmc;
+
+ /* Initialize IPMI address */
+ data->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ data->address.channel = IPMI_BMC_CHANNEL;
+ data->address.data[0] = 0;
+ data->interface = iface;
+
+ /* Initialize message buffers */
+ data->tx_msgid = 0;
+ data->tx_message.netfn = AEM_NETFN;
+
+ /* Create IPMI messaging interface user */
+ err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
+ data, &data->user);
+ if (err < 0) {
+ dev_err(bmc, "Unable to register user with IPMI "
+ "interface %d\n", data->interface);
+ return -EACCES;
+ }
+
+ return 0;
+}
+
+/* Send an IPMI command */
+static int aem_send_message(struct aem_ipmi_data *data)
+{
+ int err;
+
+ err = ipmi_validate_addr(&data->address, sizeof(data->address));
+ if (err)
+ goto out;
+
+ data->tx_msgid++;
+ err = ipmi_request_settime(data->user, &data->address, data->tx_msgid,
+ &data->tx_message, data, 0, 0, 0);
+ if (err)
+ goto out1;
+
+ return 0;
+out1:
+ dev_err(data->bmc_device, "request_settime=%x\n", err);
+ return err;
+out:
+ dev_err(data->bmc_device, "validate_addr=%x\n", err);
+ return err;
+}
+
+/* Dispatch IPMI messages to callers */
+static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
+{
+ unsigned short rx_len;
+ struct aem_ipmi_data *data = user_msg_data;
+
+ if (msg->msgid != data->tx_msgid) {
+ dev_err(data->bmc_device, "Mismatch between received msgid "
+ "(%02x) and transmitted msgid (%02x)!\n",
+ (int)msg->msgid,
+ (int)data->tx_msgid);
+ ipmi_free_recv_msg(msg);
+ return;
+ }
+
+ data->rx_recv_type = msg->recv_type;
+ if (msg->msg.data_len > 0)
+ data->rx_result = msg->msg.data[0];
+ else
+ data->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE;
+
+ if (msg->msg.data_len > 1) {
+ rx_len = msg->msg.data_len - 1;
+ if (data->rx_msg_len < rx_len)
+ rx_len = data->rx_msg_len;
+ data->rx_msg_len = rx_len;
+ memcpy(data->rx_msg_data, msg->msg.data + 1, data->rx_msg_len);
+ } else
+ data->rx_msg_len = 0;
+
+ ipmi_free_recv_msg(msg);
+ complete(&data->read_complete);
+}
+
+/* ID functions */
+
+/* Obtain an id */
+static int aem_idr_get(int *id)
+{
+ int i, err;
+
+again:
+ if (unlikely(!idr_pre_get(&aem_idr, GFP_KERNEL)))
+ return -ENOMEM;
+
+ spin_lock(&aem_idr_lock);
+ err = idr_get_new(&aem_idr, NULL, &i);
+ spin_unlock(&aem_idr_lock);
+
+ if (unlikely(err == -EAGAIN))
+ goto again;
+ else if (unlikely(err))
+ return err;
+
+ *id = i & MAX_ID_MASK;
+ return 0;
+}
+
+/* Release an object ID */
+static void aem_idr_put(int id)
+{
+ spin_lock(&aem_idr_lock);
+ idr_remove(&aem_idr, id);
+ spin_unlock(&aem_idr_lock);
+}
+
+/* Sensor support functions */
+
+/* Read a sensor value */
+static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg,
+ void *buf, size_t size)
+{
+ int rs_size, res;
+ struct aem_read_sensor_req rs_req;
+ struct aem_read_sensor_resp *rs_resp;
+ struct aem_ipmi_data *ipmi = &data->ipmi;
+
+ /* AEM registers are 1, 2, 4 or 8 bytes */
+ switch (size) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rs_req.id = system_x_id;
+ rs_req.module_handle = data->module_handle;
+ rs_req.element = elt;
+ rs_req.subcommand = AEM_READ_REGISTER;
+ rs_req.reg = reg;
+ rs_req.rx_buf_size = size;
+
+ ipmi->tx_message.cmd = AEM_ELEMENT_CMD;
+ ipmi->tx_message.data = (char *)&rs_req;
+ ipmi->tx_message.data_len = sizeof(rs_req);
+
+ rs_size = sizeof(*rs_resp) + size;
+ rs_resp = kzalloc(rs_size, GFP_KERNEL);
+ if (!rs_resp)
+ return -ENOMEM;
+
+ ipmi->rx_msg_data = rs_resp;
+ ipmi->rx_msg_len = rs_size;
+
+ aem_send_message(ipmi);
+
+ res = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT);
+ if (!res)
+ return -ETIMEDOUT;
+
+ if (ipmi->rx_result || ipmi->rx_msg_len != rs_size ||
+ memcmp(&rs_resp->id, &system_x_id, sizeof(system_x_id))) {
+ kfree(rs_resp);
+ return -ENOENT;
+ }
+
+ switch (size) {
+ case 1: {
+ u8 *x = buf;
+ *x = rs_resp->bytes[0];
+ break;
+ }
+ case 2: {
+ u16 *x = buf;
+ *x = be16_to_cpup((__be16 *)rs_resp->bytes);
+ break;
+ }
+ case 4: {
+ u32 *x = buf;
+ *x = be32_to_cpup((__be32 *)rs_resp->bytes);
+ break;
+ }
+ case 8: {
+ u64 *x = buf;
+ *x = be64_to_cpup((__be64 *)rs_resp->bytes);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/* Update AEM energy registers */
+static void update_aem_energy(struct aem_data *data)
+{
+ aem_read_sensor(data, AEM_ENERGY_ELEMENT, 0, &data->energy[0], 8);
+ if (data->ver_major < 2)
+ return;
+ aem_read_sensor(data, AEM_ENERGY_ELEMENT, 1, &data->energy[1], 8);
+}
+
+/* Update all AEM1 sensors */
+static void update_aem1_sensors(struct aem_data *data)
+{
+ mutex_lock(&data->lock);
+ if (time_before(jiffies, data->last_updated + REFRESH_INTERVAL) &&
+ data->valid)
+ goto out;
+
+ update_aem_energy(data);
+out:
+ mutex_unlock(&data->lock);
+}
+
+/* Update all AEM2 sensors */
+static void update_aem2_sensors(struct aem_data *data)
+{
+ int i;
+
+ mutex_lock(&data->lock);
+ if (time_before(jiffies, data->last_updated + REFRESH_INTERVAL) &&
+ data->valid)
+ goto out;
+
+ update_aem_energy(data);
+ aem_read_sensor(data, AEM_EXHAUST_ELEMENT, 0, &data->temp[0], 1);
+ aem_read_sensor(data, AEM_EXHAUST_ELEMENT, 1, &data->temp[1], 1);
+
+ for (i = POWER_CAP; i <= POWER_AUX; i++)
+ aem_read_sensor(data, AEM_POWER_CAP_ELEMENT, i,
+ &data->pcap[i], 2);
+out:
+ mutex_unlock(&data->lock);
+}
+
+/* Delete an AEM instance */
+static void aem_delete(struct aem_data *data)
+{
+ list_del(&data->list);
+ aem_remove_sensors(data);
+ hwmon_device_unregister(data->hwmon_dev);
+ ipmi_destroy_user(data->ipmi.user);
+ dev_set_drvdata(&data->pdev->dev, NULL);
+ platform_device_unregister(data->pdev);
+ aem_idr_put(data->id);
+ kfree(data);
+}
+
+/* Probe functions for AEM1 devices */
+
+/* Retrieve version and module handle for an AEM1 instance */
+static int aem_find_aem1_count(struct aem_ipmi_data *data)
+{
+ int res;
+ struct aem_find_firmware_req ff_req;
+ struct aem_find_firmware_resp ff_resp;
+
+ ff_req.id = system_x_id;
+ ff_req.index = 0;
+ ff_req.module_type_id = cpu_to_be16(AEM_MODULE_TYPE_ID);
+
+ data->tx_message.cmd = AEM_FIND_FW_CMD;
+ data->tx_message.data = (char *)&ff_req;
+ data->tx_message.data_len = sizeof(ff_req);
+
+ data->rx_msg_data = &ff_resp;
+ data->rx_msg_len = sizeof(ff_resp);
+
+ aem_send_message(data);
+
+ res = wait_for_completion_timeout(&data->read_complete, IPMI_TIMEOUT);
+ if (!res)
+ return -ETIMEDOUT;
+
+ if (data->rx_result || data->rx_msg_len != sizeof(ff_resp) ||
+ memcmp(&ff_resp.id, &system_x_id, sizeof(system_x_id)))
+ return -ENOENT;
+
+ return ff_resp.num_instances;
+}
+
+/* Find and initialize one AEM1 instance */
+static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle)
+{
+ struct aem_data *data;
+ int i;
+ int res = -ENOMEM;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return res;
+ mutex_init(&data->lock);
+
+ /* Copy instance data */
+ data->ver_major = 1;
+ data->ver_minor = 0;
+ data->module_handle = module_handle;
+ for (i = 0; i < AEM1_NUM_ENERGY_REGS; i++)
+ data->power_period[i] = AEM_DEFAULT_POWER_INTERVAL;
+
+ /* Create sub-device for this fw instance */
+ if (aem_idr_get(&data->id))
+ goto id_err;
+
+ data->pdev = platform_device_alloc(DRVNAME, data->id);
+ if (!data->pdev)
+ goto dev_err;
+ data->pdev->dev.driver = &aem_driver;
+
+ res = platform_device_add(data->pdev);
+ if (res)
+ goto ipmi_err;
+
+ dev_set_drvdata(&data->pdev->dev, data);
+
+ /* Set up IPMI interface */
+ if (aem_init_ipmi_data(&data->ipmi, probe->interface,
+ probe->bmc_device))
+ goto ipmi_err;
+
+ /* Register with hwmon */
+ data->hwmon_dev = hwmon_device_register(&data->pdev->dev);
+
+ if (IS_ERR(data->hwmon_dev)) {
+ dev_err(&data->pdev->dev, "Unable to register hwmon "
+ "device for IPMI interface %d\n",
+ probe->interface);
+ goto hwmon_reg_err;
+ }
+
+ data->update = update_aem1_sensors;
+
+ /* Find sensors */
+ if (aem1_find_sensors(data))
+ goto sensor_err;
+
+ /* Add to our list of AEM devices */
+ list_add_tail(&data->list, &driver_data.aem_devices);
+
+ dev_info(data->ipmi.bmc_device, "Found AEM v%d.%d at 0x%X\n",
+ data->ver_major, data->ver_minor,
+ data->module_handle);
+ return 0;
+
+sensor_err:
+ hwmon_device_unregister(data->hwmon_dev);
+hwmon_reg_err:
+ ipmi_destroy_user(data->ipmi.user);
+ipmi_err:
+ dev_set_drvdata(&data->pdev->dev, NULL);
+ platform_device_unregister(data->pdev);
+dev_err:
+ aem_idr_put(data->id);
+id_err:
+ kfree(data);
+
+ return res;
+}
+
+/* Find and initialize all AEM1 instances */
+static int aem_init_aem1(struct aem_ipmi_data *probe)
+{
+ int num, i, err;
+
+ num = aem_find_aem1_count(probe);
+ for (i = 0; i < num; i++) {
+ err = aem_init_aem1_inst(probe, i);
+ if (err) {
+ dev_err(probe->bmc_device,
+ "Error %d initializing AEM1 0x%X\n",
+ err, i);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/* Probe functions for AEM2 devices */
+
+/* Retrieve version and module handle for an AEM2 instance */
+static int aem_find_aem2(struct aem_ipmi_data *data,
+ struct aem_find_instance_resp *fi_resp,
+ int instance_num)
+{
+ int res;
+ struct aem_find_instance_req fi_req;
+
+ fi_req.id = system_x_id;
+ fi_req.instance_number = instance_num;
+ fi_req.module_type_id = cpu_to_be16(AEM_MODULE_TYPE_ID);
+
+ data->tx_message.cmd = AEM_FW_INSTANCE_CMD;
+ data->tx_message.data = (char *)&fi_req;
+ data->tx_message.data_len = sizeof(fi_req);
+
+ data->rx_msg_data = fi_resp;
+ data->rx_msg_len = sizeof(*fi_resp);
+
+ aem_send_message(data);
+
+ res = wait_for_completion_timeout(&data->read_complete, IPMI_TIMEOUT);
+ if (!res)
+ return -ETIMEDOUT;
+
+ if (data->rx_result || data->rx_msg_len != sizeof(*fi_resp) ||
+ memcmp(&fi_resp->id, &system_x_id, sizeof(system_x_id)))
+ return -ENOENT;
+
+ return 0;
+}
+
+/* Find and initialize one AEM2 instance */
+static int aem_init_aem2_inst(struct aem_ipmi_data *probe,
+ struct aem_find_instance_resp *fi_resp)
+{
+ struct aem_data *data;
+ int i;
+ int res = -ENOMEM;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return res;
+ mutex_init(&data->lock);
+
+ /* Copy instance data */
+ data->ver_major = fi_resp->major;
+ data->ver_minor = fi_resp->minor;
+ data->module_handle = fi_resp->module_handle;
+ for (i = 0; i < AEM2_NUM_ENERGY_REGS; i++)
+ data->power_period[i] = AEM_DEFAULT_POWER_INTERVAL;
+
+ /* Create sub-device for this fw instance */
+ if (aem_idr_get(&data->id))
+ goto id_err;
+
+ data->pdev = platform_device_alloc(DRVNAME, data->id);
+ if (!data->pdev)
+ goto dev_err;
+ data->pdev->dev.driver = &aem_driver;
+
+ res = platform_device_add(data->pdev);
+ if (res)
+ goto ipmi_err;
+
+ dev_set_drvdata(&data->pdev->dev, data);
+
+ /* Set up IPMI interface */
+ if (aem_init_ipmi_data(&data->ipmi, probe->interface,
+ probe->bmc_device))
+ goto ipmi_err;
+
+ /* Register with hwmon */
+ data->hwmon_dev = hwmon_device_register(&data->pdev->dev);
+
+ if (IS_ERR(data->hwmon_dev)) {
+ dev_err(&data->pdev->dev, "Unable to register hwmon "
+ "device for IPMI interface %d\n",
+ probe->interface);
+ goto hwmon_reg_err;
+ }
+
+ data->update = update_aem2_sensors;
+
+ /* Find sensors */
+ if (aem2_find_sensors(data))
+ goto sensor_err;
+
+ /* Add to our list of AEM devices */
+ list_add_tail(&data->list, &driver_data.aem_devices);
+
+ dev_info(data->ipmi.bmc_device, "Found AEM v%d.%d at 0x%X\n",
+ data->ver_major, data->ver_minor,
+ data->module_handle);
+ return 0;
+
+sensor_err:
+ hwmon_device_unregister(data->hwmon_dev);
+hwmon_reg_err:
+ ipmi_destroy_user(data->ipmi.user);
+ipmi_err:
+ dev_set_drvdata(&data->pdev->dev, NULL);
+ platform_device_unregister(data->pdev);
+dev_err:
+ aem_idr_put(data->id);
+id_err:
+ kfree(data);
+
+ return res;
+}
+
+/* Find and initialize all AEM2 instances */
+static int aem_init_aem2(struct aem_ipmi_data *probe)
+{
+ struct aem_find_instance_resp fi_resp;
+ int err;
+ int i = 0;
+
+ while (!aem_find_aem2(probe, &fi_resp, i)) {
+ if (fi_resp.major != 2) {
+ dev_err(probe->bmc_device, "Unknown AEM v%d; please "
+ "report this to the maintainer.\n",
+ fi_resp.major);
+ i++;
+ continue;
+ }
+ err = aem_init_aem2_inst(probe, &fi_resp);
+ if (err) {
+ dev_err(probe->bmc_device,
+ "Error %d initializing AEM2 0x%X\n",
+ err, fi_resp.module_handle);
+ return err;
+ }
+ i++;
+ }
+
+ return 0;
+}
+
+/* Probe a BMC for AEM firmware instances */
+static void aem_register_bmc(int iface, struct device *dev)
+{
+ struct aem_ipmi_data probe;
+
+ if (aem_init_ipmi_data(&probe, iface, dev))
+ return;
+
+ /* Ignore probe errors; they won't cause problems */
+ aem_init_aem1(&probe);
+ aem_init_aem2(&probe);
+
+ ipmi_destroy_user(probe.user);
+}
+
+/* Handle BMC deletion */
+static void aem_bmc_gone(int iface)
+{
+ struct aem_data *p1, *next1;
+
+ list_for_each_entry_safe(p1, next1, &driver_data.aem_devices, list)
+ if (p1->ipmi.interface == iface)
+ aem_delete(p1);
+}
+
+/* sysfs support functions */
+
+/* AEM device name */
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct aem_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s%d\n", DRVNAME, data->ver_major);
+}
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
+/* AEM device version */
+static ssize_t show_version(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct aem_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d.%d\n", data->ver_major, data->ver_minor);
+}
+static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, 0);
+
+/* Display power use */
+static ssize_t aem_show_power(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct aem_data *data = dev_get_drvdata(dev);
+ u64 before, after, delta, time;
+ signed long leftover;
+ struct timespec b, a;
+
+ mutex_lock(&data->lock);
+ update_aem_energy(data);
+ getnstimeofday(&b);
+ before = data->energy[attr->index];
+
+ leftover = schedule_timeout_interruptible(
+ msecs_to_jiffies(data->power_period[attr->index])
+ );
+ if (leftover) {
+ mutex_unlock(&data->lock);
+ return 0;
+ }
+
+ update_aem_energy(data);
+ getnstimeofday(&a);
+ after = data->energy[attr->index];
+ mutex_unlock(&data->lock);
+
+ time = timespec_to_ns(&a) - timespec_to_ns(&b);
+ delta = (after - before) * UJ_PER_MJ;
+
+ return sprintf(buf, "%llu\n",
+ (unsigned long long)div64_u64(delta * NSEC_PER_SEC, time));
+}
+
+/* Display energy use */
+static ssize_t aem_show_energy(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct aem_data *a = dev_get_drvdata(dev);
+ a->update(a);
+
+ return sprintf(buf, "%llu\n",
+ (unsigned long long)a->energy[attr->index] * 1000);
+}
+
+/* Display power interval registers */
+static ssize_t aem_show_power_period(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct aem_data *a = dev_get_drvdata(dev);
+ a->update(a);
+
+ return sprintf(buf, "%lu\n", a->power_period[attr->index]);
+}
+
+/* Set power interval registers */
+static ssize_t aem_set_power_period(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct aem_data *a = dev_get_drvdata(dev);
+ unsigned long temp;
+ int res;
+
+ res = strict_strtoul(buf, 10, &temp);
+ if (res)
+ return res;
+
+ if (temp < AEM_MIN_POWER_INTERVAL)
+ return -EINVAL;
+
+ mutex_lock(&a->lock);
+ a->power_period[attr->index] = temp;
+ mutex_unlock(&a->lock);
+
+ return count;
+}
+
+/* Discover sensors on an AEM device */
+static int aem_register_sensors(struct aem_data *data,
+ struct aem_ro_sensor_template *ro,
+ struct aem_rw_sensor_template *rw)
+{
+ struct device *dev = &data->pdev->dev;
+ struct sensor_device_attribute *sensors = data->sensors;
+ int err;
+
+ /* Set up read-only sensors */
+ while (ro->label) {
+ sensors->dev_attr.attr.name = ro->label;
+ sensors->dev_attr.attr.mode = S_IRUGO;
+ sensors->dev_attr.show = ro->show;
+ sensors->index = ro->index;
+
+ err = device_create_file(dev, &sensors->dev_attr);
+ if (err) {
+ sensors->dev_attr.attr.name = NULL;
+ goto error;
+ }
+ sensors++;
+ ro++;
+ }
+
+ /* Set up read-write sensors */
+ while (rw->label) {
+ sensors->dev_attr.attr.name = rw->label;
+ sensors->dev_attr.attr.mode = S_IRUGO | S_IWUSR;
+ sensors->dev_attr.show = rw->show;
+ sensors->dev_attr.store = rw->set;
+ sensors->index = rw->index;
+
+ err = device_create_file(dev, &sensors->dev_attr);
+ if (err) {
+ sensors->dev_attr.attr.name = NULL;
+ goto error;
+ }
+ sensors++;
+ rw++;
+ }
+
+ err = device_create_file(dev, &sensor_dev_attr_name.dev_attr);
+ if (err)
+ goto error;
+ err = device_create_file(dev, &sensor_dev_attr_version.dev_attr);
+ return err;
+
+error:
+ aem_remove_sensors(data);
+ return err;
+}
+
+/* sysfs support functions for AEM2 sensors */
+
+/* Display temperature use */
+static ssize_t aem2_show_temp(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct aem_data *a = dev_get_drvdata(dev);
+ a->update(a);
+
+ return sprintf(buf, "%u\n", a->temp[attr->index] * 1000);
+}
+
+/* Display power-capping registers */
+static ssize_t aem2_show_pcap_value(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct aem_data *a = dev_get_drvdata(dev);
+ a->update(a);
+
+ return sprintf(buf, "%u\n", a->pcap[attr->index] * 100000);
+}
+
+/* Remove sensors attached to an AEM device */
+static void aem_remove_sensors(struct aem_data *data)
+{
+ int i;
+
+ for (i = 0; i < AEM_NUM_SENSORS; i++) {
+ if (!data->sensors[i].dev_attr.attr.name)
+ continue;
+ device_remove_file(&data->pdev->dev,
+ &data->sensors[i].dev_attr);
+ }
+
+ device_remove_file(&data->pdev->dev,
+ &sensor_dev_attr_name.dev_attr);
+ device_remove_file(&data->pdev->dev,
+ &sensor_dev_attr_version.dev_attr);
+}
+
+/* Sensor probe functions */
+
+/* Description of AEM1 sensors */
+static struct aem_ro_sensor_template aem1_ro_sensors[] = {
+{"energy1_input", aem_show_energy, 0},
+{"power1_average", aem_show_power, 0},
+{NULL, NULL, 0},
+};
+
+static struct aem_rw_sensor_template aem1_rw_sensors[] = {
+{"power1_average_interval", aem_show_power_period, aem_set_power_period, 0},
+{NULL, NULL, NULL, 0},
+};
+
+/* Description of AEM2 sensors */
+static struct aem_ro_sensor_template aem2_ro_sensors[] = {
+{"energy1_input", aem_show_energy, 0},
+{"energy2_input", aem_show_energy, 1},
+{"power1_average", aem_show_power, 0},
+{"power2_average", aem_show_power, 1},
+{"temp1_input", aem2_show_temp, 0},
+{"temp2_input", aem2_show_temp, 1},
+
+{"power4_average", aem2_show_pcap_value, POWER_CAP_MAX_HOTPLUG},
+{"power5_average", aem2_show_pcap_value, POWER_CAP_MAX},
+{"power6_average", aem2_show_pcap_value, POWER_CAP_MIN_WARNING},
+{"power7_average", aem2_show_pcap_value, POWER_CAP_MIN},
+
+{"power3_average", aem2_show_pcap_value, POWER_AUX},
+{"power_cap", aem2_show_pcap_value, POWER_CAP},
+{NULL, NULL, 0},
+};
+
+static struct aem_rw_sensor_template aem2_rw_sensors[] = {
+{"power1_average_interval", aem_show_power_period, aem_set_power_period, 0},
+{"power2_average_interval", aem_show_power_period, aem_set_power_period, 1},
+{NULL, NULL, NULL, 0},
+};
+
+/* Set up AEM1 sensor attrs */
+static int aem1_find_sensors(struct aem_data *data)
+{
+ return aem_register_sensors(data, aem1_ro_sensors, aem1_rw_sensors);
+}
+
+/* Set up AEM2 sensor attrs */
+static int aem2_find_sensors(struct aem_data *data)
+{
+ return aem_register_sensors(data, aem2_ro_sensors, aem2_rw_sensors);
+}
+
+/* Module init/exit routines */
+
+static int __init aem_init(void)
+{
+ int res;
+
+ res = driver_register(&aem_driver);
+ if (res) {
+ printk(KERN_ERR "Can't register aem driver\n");
+ return res;
+ }
+
+ res = ipmi_smi_watcher_register(&driver_data.bmc_events);
+ if (res)
+ goto ipmi_reg_err;
+ return 0;
+
+ipmi_reg_err:
+ driver_unregister(&aem_driver);
+ return res;
+
+}
+
+static void __exit aem_exit(void)
+{
+ struct aem_data *p1, *next1;
+
+ ipmi_smi_watcher_unregister(&driver_data.bmc_events);
+ driver_unregister(&aem_driver);
+ list_for_each_entry_safe(p1, next1, &driver_data.aem_devices, list)
+ aem_delete(p1);
+}
+
+MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_DESCRIPTION("IBM Active Energy Manager power/temp sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(aem_init);
+module_exit(aem_exit);
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index fa7696905154..de698dc73020 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -251,10 +251,13 @@ static int lm75_detach_client(struct i2c_client *client)
the SMBus standard. */
static int lm75_read_value(struct i2c_client *client, u8 reg)
{
+ int value;
+
if (reg == LM75_REG_CONF)
return i2c_smbus_read_byte_data(client, reg);
- else
- return swab16(i2c_smbus_read_word_data(client, reg));
+
+ value = i2c_smbus_read_word_data(client, reg);
+ return (value < 0) ? value : swab16(value);
}
static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value)
@@ -287,9 +290,16 @@ static struct lm75_data *lm75_update_device(struct device *dev)
int i;
dev_dbg(&client->dev, "Starting lm75 update\n");
- for (i = 0; i < ARRAY_SIZE(data->temp); i++)
- data->temp[i] = lm75_read_value(client,
- LM75_REG_TEMP[i]);
+ for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+ int status;
+
+ status = lm75_read_value(client, LM75_REG_TEMP[i]);
+ if (status < 0)
+ dev_dbg(&client->dev, "reg %d, err %d\n",
+ LM75_REG_TEMP[i], status);
+ else
+ data->temp[i] = status;
+ }
data->last_updated = jiffies;
data->valid = 1;
}
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index 182fe6a5605f..ee5eca1c1921 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -192,23 +192,20 @@ static int RANGE_TO_REG( int range )
{
int i;
- if ( range < lm85_range_map[0] ) {
- return 0 ;
- } else if ( range > lm85_range_map[15] ) {
+ if (range >= lm85_range_map[15])
return 15 ;
- } else { /* find closest match */
- for ( i = 14 ; i >= 0 ; --i ) {
- if ( range > lm85_range_map[i] ) { /* range bracketed */
- if ((lm85_range_map[i+1] - range) <
- (range - lm85_range_map[i])) {
- i++;
- break;
- }
- break;
- }
+
+ /* Find the closest match */
+ for (i = 14; i >= 0; --i) {
+ if (range >= lm85_range_map[i]) {
+ if ((lm85_range_map[i + 1] - range) <
+ (range - lm85_range_map[i]))
+ return i + 1;
+ return i;
}
}
- return( i & 0x0f );
+
+ return 0;
}
#define RANGE_FROM_REG(val) (lm85_range_map[(val)&0x0f])
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 1305ef190fc1..9e8c875437be 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -290,12 +290,12 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
* bus, or started a new i2c message
*/
- if (iicstat & S3C2410_IICSTAT_LASTBIT &&
+ if (iicstat & S3C2410_IICSTAT_LASTBIT &&
!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
/* ack was not received... */
dev_dbg(i2c->dev, "ack was not received\n");
- s3c24xx_i2c_stop(i2c, -EREMOTEIO);
+ s3c24xx_i2c_stop(i2c, -ENXIO);
goto out_ack;
}
@@ -305,7 +305,7 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
i2c->state = STATE_WRITE;
/* terminate the transfer if there is nothing to do
- * (used by the i2c probe to find devices */
+ * as this is used by the i2c probe to find devices. */
if (is_lastmsg(i2c) && i2c->msg->len == 0) {
s3c24xx_i2c_stop(i2c, 0);
@@ -323,7 +323,17 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
* end of the message, and if so, work out what to do
*/
+ if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
+ if (iicstat & S3C2410_IICSTAT_LASTBIT) {
+ dev_dbg(i2c->dev, "WRITE: No Ack\n");
+
+ s3c24xx_i2c_stop(i2c, -ECONNREFUSED);
+ goto out_ack;
+ }
+ }
+
retry_write:
+
if (!is_msgend(i2c)) {
byte = i2c->msg->buf[i2c->msg_ptr++];
writeb(byte, i2c->regs + S3C2410_IICDS);
@@ -377,17 +387,6 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
* going to do any more read/write
*/
- if (!(i2c->msg->flags & I2C_M_IGNORE_NAK) &&
- !(is_msglast(i2c) && is_lastmsg(i2c))) {
-
- if (iicstat & S3C2410_IICSTAT_LASTBIT) {
- dev_dbg(i2c->dev, "READ: No Ack\n");
-
- s3c24xx_i2c_stop(i2c, -ECONNREFUSED);
- goto out_ack;
- }
- }
-
byte = readb(i2c->regs + S3C2410_IICDS);
i2c->msg->buf[i2c->msg_ptr++] = byte;
@@ -949,3 +948,4 @@ MODULE_DESCRIPTION("S3C24XX I2C Bus driver");
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:s3c2410-i2c");
+MODULE_ALIAS("platform:s3c2440-i2c");
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index b4f3aefa12b6..1607536ff5fb 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -1028,6 +1028,7 @@ endif
config BLK_DEV_HD_ONLY
bool "Old hard disk (MFM/RLL/IDE) driver"
+ depends on !ARM || ARCH_RPC || ARCH_SHARK || BROKEN
help
There are two drivers for MFM/RLL/IDE hard disks. Most people use
the newer enhanced driver, but this old one is still around for two
diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c
index 713cef20622e..8e8c28104b45 100644
--- a/drivers/ide/arm/bast-ide.c
+++ b/drivers/ide/arm/bast-ide.c
@@ -42,6 +42,7 @@ static int __init bastide_register(unsigned int base, unsigned int aux, int irq)
hw.io_ports.ctl_addr = aux + (6 * 0x20);
hw.irq = irq;
+ hw.chipset = ide_generic;
hwif = ide_find_port();
if (hwif == NULL)
diff --git a/drivers/ide/arm/ide_arm.c b/drivers/ide/arm/ide_arm.c
index 4263ffd4ab20..2f311da4c963 100644
--- a/drivers/ide/arm/ide_arm.c
+++ b/drivers/ide/arm/ide_arm.c
@@ -49,6 +49,7 @@ static int __init ide_arm_init(void)
memset(&hw, 0, sizeof(hw));
ide_std_init_ports(&hw, base, ctl);
hw.irq = IDE_ARM_IRQ;
+ hw.chipset = ide_generic;
hwif = ide_find_port();
if (hwif) {
diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c
index 96378ebfb31f..2f2b4f4cf229 100644
--- a/drivers/ide/arm/palm_bk3710.c
+++ b/drivers/ide/arm/palm_bk3710.c
@@ -76,7 +76,7 @@ struct palm_bk3710_udmatiming {
#include "../ide-timing.h"
-static long ide_palm_clk;
+static unsigned ideclk_period; /* in nanoseconds */
static const struct palm_bk3710_udmatiming palm_bk3710_udmatimings[6] = {
{160, 240}, /* UDMA Mode 0 */
@@ -86,8 +86,6 @@ static const struct palm_bk3710_udmatiming palm_bk3710_udmatimings[6] = {
{85, 60}, /* UDMA Mode 4 */
};
-static struct clk *ideclkp;
-
static void palm_bk3710_setudmamode(void __iomem *base, unsigned int dev,
unsigned int mode)
{
@@ -97,10 +95,10 @@ static void palm_bk3710_setudmamode(void __iomem *base, unsigned int dev,
/* DMA Data Setup */
t0 = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].cycletime,
- ide_palm_clk) - 1;
- tenv = DIV_ROUND_UP(20, ide_palm_clk) - 1;
+ ideclk_period) - 1;
+ tenv = DIV_ROUND_UP(20, ideclk_period) - 1;
trp = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].rptime,
- ide_palm_clk) - 1;
+ ideclk_period) - 1;
/* udmatim Register */
val16 = readw(base + BK3710_UDMATIM) & (dev ? 0xFF0F : 0xFFF0);
@@ -141,8 +139,8 @@ static void palm_bk3710_setdmamode(void __iomem *base, unsigned int dev,
cycletime = max_t(int, t->cycle, min_cycle);
/* DMA Data Setup */
- t0 = DIV_ROUND_UP(cycletime, ide_palm_clk);
- td = DIV_ROUND_UP(t->active, ide_palm_clk);
+ t0 = DIV_ROUND_UP(cycletime, ideclk_period);
+ td = DIV_ROUND_UP(t->active, ideclk_period);
tkw = t0 - td - 1;
td -= 1;
@@ -168,9 +166,9 @@ static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate,
struct ide_timing *t;
/* PIO Data Setup */
- t0 = DIV_ROUND_UP(cycletime, ide_palm_clk);
+ t0 = DIV_ROUND_UP(cycletime, ideclk_period);
t2 = DIV_ROUND_UP(ide_timing_find_mode(XFER_PIO_0 + mode)->active,
- ide_palm_clk);
+ ideclk_period);
t2i = t0 - t2 - 1;
t2 -= 1;
@@ -192,8 +190,8 @@ static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate,
/* TASKFILE Setup */
t = ide_timing_find_mode(XFER_PIO_0 + mode);
- t0 = DIV_ROUND_UP(t->cyc8b, ide_palm_clk);
- t2 = DIV_ROUND_UP(t->act8b, ide_palm_clk);
+ t0 = DIV_ROUND_UP(t->cyc8b, ideclk_period);
+ t2 = DIV_ROUND_UP(t->act8b, ideclk_period);
t2i = t0 - t2 - 1;
t2 -= 1;
@@ -350,22 +348,22 @@ static const struct ide_port_info __devinitdata palm_bk3710_port_info = {
static int __devinit palm_bk3710_probe(struct platform_device *pdev)
{
- struct clk *clkp;
+ struct clk *clk;
struct resource *mem, *irq;
ide_hwif_t *hwif;
- void __iomem *base;
- int pribase, i;
+ unsigned long base, rate;
+ int i;
hw_regs_t hw;
u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
- clkp = clk_get(NULL, "IDECLK");
- if (IS_ERR(clkp))
+ clk = clk_get(NULL, "IDECLK");
+ if (IS_ERR(clk))
return -ENODEV;
- ideclkp = clkp;
- clk_enable(ideclkp);
- ide_palm_clk = clk_get_rate(ideclkp)/100000;
- ide_palm_clk = (10000/ide_palm_clk) + 1;
+ clk_enable(clk);
+ rate = clk_get_rate(clk);
+ ideclk_period = 1000000000UL / rate;
+
/* Register the IDE interface with Linux ATA Interface */
memset(&hw, 0, sizeof(hw));
@@ -374,22 +372,27 @@ static int __devinit palm_bk3710_probe(struct platform_device *pdev)
printk(KERN_ERR "failed to get memory region resource\n");
return -ENODEV;
}
+
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (irq == NULL) {
printk(KERN_ERR "failed to get IRQ resource\n");
return -ENODEV;
}
- base = (void *)mem->start;
+ if (request_mem_region(mem->start, mem->end - mem->start + 1,
+ "palm_bk3710") == NULL) {
+ printk(KERN_ERR "failed to request memory region\n");
+ return -EBUSY;
+ }
+
+ base = IO_ADDRESS(mem->start);
/* Configure the Palm Chip controller */
- palm_bk3710_chipinit(base);
+ palm_bk3710_chipinit((void __iomem *)base);
- pribase = mem->start + IDE_PALM_ATA_PRI_REG_OFFSET;
for (i = 0; i < IDE_NR_PORTS - 2; i++)
- hw.io_ports_array[i] = pribase + i;
- hw.io_ports.ctl_addr = mem->start +
- IDE_PALM_ATA_PRI_CTL_OFFSET;
+ hw.io_ports_array[i] = base + IDE_PALM_ATA_PRI_REG_OFFSET + i;
+ hw.io_ports.ctl_addr = base + IDE_PALM_ATA_PRI_CTL_OFFSET;
hw.irq = irq->start;
hw.chipset = ide_palm3710;
@@ -409,9 +412,6 @@ static int __devinit palm_bk3710_probe(struct platform_device *pdev)
ide_device_add(idx, &palm_bk3710_port_info);
- if (!hwif->present)
- goto out;
-
return 0;
out:
printk(KERN_WARNING "Palm Chip BK3710 IDE Register Fail\n");
@@ -437,4 +437,3 @@ static int __init palm_bk3710_init(void)
module_init(palm_bk3710_init);
MODULE_LICENSE("GPL");
-
diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c
index a6073e248f45..2d92214096ab 100644
--- a/drivers/ide/ide-generic.c
+++ b/drivers/ide/ide-generic.c
@@ -22,6 +22,10 @@
#define DRV_NAME "ide_generic"
+static int probe_mask = 0x03;
+module_param(probe_mask, int, 0);
+MODULE_PARM_DESC(probe_mask, "probe mask for legacy ISA IDE ports");
+
static ssize_t store_add(struct class *cls, const char *buf, size_t n)
{
ide_hwif_t *hwif;
@@ -89,6 +93,9 @@ static int __init ide_generic_init(void)
u8 idx[MAX_HWIFS];
int i;
+ printk(KERN_INFO DRV_NAME ": please use \"probe_mask=0x3f\" module "
+ "parameter for probing all legacy ISA IDE ports\n");
+
for (i = 0; i < MAX_HWIFS; i++) {
ide_hwif_t *hwif;
unsigned long io_addr = ide_default_io_base(i);
@@ -96,7 +103,7 @@ static int __init ide_generic_init(void)
idx[i] = 0xff;
- if (io_addr) {
+ if ((probe_mask & (1 << i)) && io_addr) {
if (!request_region(io_addr, 8, DRV_NAME)) {
printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX "
"not free.\n",
@@ -125,6 +132,7 @@ static int __init ide_generic_init(void)
memset(&hw, 0, sizeof(hw));
ide_std_init_ports(&hw, io_addr, io_addr + 0x206);
hw.irq = ide_default_irq(io_addr);
+ hw.chipset = ide_generic;
ide_init_port_hw(hwif, &hw);
idx[i] = i;
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
index 6a8953f68e9f..adbd01784162 100644
--- a/drivers/ide/ide-pnp.c
+++ b/drivers/ide/ide-pnp.c
@@ -55,6 +55,7 @@ static int idepnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
memset(&hw, 0, sizeof(hw));
ide_std_init_ports(&hw, base, ctl);
hw.irq = pnp_irq(dev, 0);
+ hw.chipset = ide_generic;
hwif = ide_find_port();
if (hwif) {
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 34b0d4f26b58..26e68b65b7cf 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -646,15 +646,12 @@ static int ide_register_port(ide_hwif_t *hwif)
goto out;
}
- get_device(&hwif->gendev);
-
- hwif->portdev = device_create(ide_port_class, &hwif->gendev,
- MKDEV(0, 0), hwif->name);
+ hwif->portdev = device_create_drvdata(ide_port_class, &hwif->gendev,
+ MKDEV(0, 0), hwif, hwif->name);
if (IS_ERR(hwif->portdev)) {
ret = PTR_ERR(hwif->portdev);
device_unregister(&hwif->gendev);
}
- dev_set_drvdata(hwif->portdev, hwif);
out:
return ret;
}
@@ -1221,16 +1218,12 @@ static void drive_release_dev (struct device *dev)
complete(&drive->gendev_rel_comp);
}
-#ifndef ide_default_irq
-#define ide_default_irq(irq) 0
-#endif
-
static int hwif_init(ide_hwif_t *hwif)
{
int old_irq;
if (!hwif->irq) {
- hwif->irq = ide_default_irq(hwif->io_ports.data_addr);
+ hwif->irq = __ide_default_irq(hwif->io_ports.data_addr);
if (!hwif->irq) {
printk("%s: DISABLED, NO IRQ\n", hwif->name);
return 0;
@@ -1260,7 +1253,7 @@ static int hwif_init(ide_hwif_t *hwif)
* It failed to initialise. Find the default IRQ for
* this port and try that.
*/
- hwif->irq = ide_default_irq(hwif->io_ports.data_addr);
+ hwif->irq = __ide_default_irq(hwif->io_ports.data_addr);
if (!hwif->irq) {
printk("%s: Disabled unable to get IRQ %d.\n",
hwif->name, old_irq);
@@ -1334,8 +1327,7 @@ static void ide_port_init_devices(ide_hwif_t *hwif)
static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
const struct ide_port_info *d)
{
- if (d->chipset != ide_etrax100)
- hwif->channel = port;
+ hwif->channel = port;
if (d->chipset)
hwif->chipset = d->chipset;
@@ -1520,7 +1512,7 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d)
continue;
}
- if (d->chipset != ide_etrax100 && (i & 1) && mate) {
+ if ((i & 1) && mate) {
hwif->mate = mate;
mate->mate = hwif;
}
@@ -1666,6 +1658,7 @@ static void ide_legacy_init_one(u8 *idx, hw_regs_t *hw, u8 port_no,
ide_std_init_ports(hw, base, ctl);
hw->irq = irq;
+ hw->chipset = d->chipset;
hwif = ide_find_port_slot(d);
if (hwif) {
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index 8d6ad812a014..8af88bf0969b 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -63,7 +63,6 @@ static int proc_ide_read_imodel
case ide_pmac: name = "mac-io"; break;
case ide_au1xxx: name = "au1xxx"; break;
case ide_palm3710: name = "palm3710"; break;
- case ide_etrax100: name = "etrax100"; break;
case ide_acorn: name = "acorn"; break;
default: name = "(unknown)"; break;
}
@@ -77,7 +76,7 @@ static int proc_ide_read_mate
ide_hwif_t *hwif = (ide_hwif_t *) data;
int len;
- if (hwif && hwif->mate && hwif->mate->present)
+ if (hwif && hwif->mate)
len = sprintf(page, "%s\n", hwif->mate->name);
else
len = sprintf(page, "(none)\n");
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 0c908ca3ff79..ab545ffa1549 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -225,10 +225,10 @@ static u8 wait_drive_not_busy(ide_drive_t *drive)
u8 stat;
/*
- * Last sector was transfered, wait until drive is ready.
- * This can take up to 10 usec, but we will wait max 1 ms.
+ * Last sector was transfered, wait until device is ready. This can
+ * take up to 6 ms on some ATAPI devices, so we will wait max 10 ms.
*/
- for (retries = 0; retries < 100; retries++) {
+ for (retries = 0; retries < 1000; retries++) {
stat = ide_read_status(drive);
if (stat & BUSY_STAT)
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index c758dcb13b14..300431d080a9 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -315,13 +315,14 @@ void ide_unregister(ide_hwif_t *hwif)
BUG_ON(in_interrupt());
BUG_ON(irqs_disabled());
+
mutex_lock(&ide_cfg_mtx);
- spin_lock_irq(&ide_lock);
- if (!hwif->present)
- goto abort;
- __ide_port_unregister_devices(hwif);
- hwif->present = 0;
+ spin_lock_irq(&ide_lock);
+ if (hwif->present) {
+ __ide_port_unregister_devices(hwif);
+ hwif->present = 0;
+ }
spin_unlock_irq(&ide_lock);
ide_proc_unregister_port(hwif);
@@ -351,16 +352,15 @@ void ide_unregister(ide_hwif_t *hwif)
blk_unregister_region(MKDEV(hwif->major, 0), MAX_DRIVES<<PARTN_BITS);
kfree(hwif->sg_table);
unregister_blkdev(hwif->major, hwif->name);
- spin_lock_irq(&ide_lock);
if (hwif->dma_base)
ide_release_dma_engine(hwif);
+ spin_lock_irq(&ide_lock);
/* restore hwif data to pristine status */
ide_init_port_data(hwif, hwif->index);
-
-abort:
spin_unlock_irq(&ide_lock);
+
mutex_unlock(&ide_cfg_mtx);
}
@@ -1094,13 +1094,6 @@ struct bus_type ide_bus_type = {
EXPORT_SYMBOL_GPL(ide_bus_type);
-static void ide_port_class_release(struct device *portdev)
-{
- ide_hwif_t *hwif = dev_get_drvdata(portdev);
-
- put_device(&hwif->gendev);
-}
-
int ide_vlb_clk;
EXPORT_SYMBOL_GPL(ide_vlb_clk);
@@ -1305,7 +1298,6 @@ static int __init ide_init(void)
ret = PTR_ERR(ide_port_class);
goto out_port_class;
}
- ide_port_class->dev_release = ide_port_class_release;
init_ide_data();
diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c
index 5c730e4dd735..9a1d27ef3f8a 100644
--- a/drivers/ide/legacy/buddha.c
+++ b/drivers/ide/legacy/buddha.c
@@ -138,6 +138,8 @@ static void __init buddha_setup_ports(hw_regs_t *hw, unsigned long base,
hw->irq = IRQ_AMIGA_PORTS;
hw->ack_intr = ack_intr;
+
+ hw->chipset = ide_generic;
}
/*
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
index 9e449a0c623f..af11028b4794 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/legacy/falconide.c
@@ -81,6 +81,8 @@ static void __init falconide_setup_ports(hw_regs_t *hw)
hw->irq = IRQ_MFP_IDE;
hw->ack_intr = NULL;
+
+ hw->chipset = ide_generic;
}
/*
diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c
index a9c2593a898c..fed7d812761c 100644
--- a/drivers/ide/legacy/gayle.c
+++ b/drivers/ide/legacy/gayle.c
@@ -16,6 +16,7 @@
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/zorro.h>
+#include <linux/module.h>
#include <asm/setup.h>
#include <asm/amigahw.h>
@@ -62,7 +63,10 @@
GAYLE_NUM_HWIFS-1)
#define GAYLE_HAS_CONTROL_REG (!ide_doubler)
#define GAYLE_IDEREG_SIZE (ide_doubler ? 0x1000 : 0x2000)
+
int ide_doubler = 0; /* support IDE doublers? */
+EXPORT_SYMBOL_GPL(ide_doubler);
+
module_param_named(doubler, ide_doubler, bool, 0);
MODULE_PARM_DESC(doubler, "enable support for IDE doublers");
#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
@@ -112,6 +116,8 @@ static void __init gayle_setup_ports(hw_regs_t *hw, unsigned long base,
hw->irq = IRQ_AMIGA_PORTS;
hw->ack_intr = ack_intr;
+
+ hw->chipset = ide_generic;
}
/*
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index aa2ea3deac85..3381424d70a1 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -135,13 +135,17 @@ static void ide_detach(struct pcmcia_device *link)
{
ide_info_t *info = link->priv;
ide_hwif_t *hwif = info->hwif;
+ unsigned long data_addr, ctl_addr;
DEBUG(0, "ide_detach(0x%p)\n", link);
+ data_addr = hwif->io_ports.data_addr;
+ ctl_addr = hwif->io_ports.ctl_addr;
+
ide_release(link);
- release_region(hwif->io_ports.ctl_addr, 1);
- release_region(hwif->io_ports.data_addr, 8);
+ release_region(ctl_addr, 1);
+ release_region(data_addr, 8);
kfree(info);
} /* ide_detach */
@@ -194,6 +198,16 @@ static ide_hwif_t *idecs_register(unsigned long io, unsigned long ctl,
if (hwif->present)
return hwif;
+ /* retry registration in case device is still spinning up */
+ for (i = 0; i < 10; i++) {
+ msleep(100);
+ ide_port_scan(hwif);
+ if (hwif->present)
+ return hwif;
+ }
+
+ return hwif;
+
out_release:
release_region(ctl, 1);
release_region(io, 8);
@@ -222,7 +236,7 @@ static int ide_config(struct pcmcia_device *link)
cistpl_cftable_entry_t dflt;
} *stk = NULL;
cistpl_cftable_entry_t *cfg;
- int i, pass, last_ret = 0, last_fn = 0, is_kme = 0;
+ int pass, last_ret = 0, last_fn = 0, is_kme = 0;
unsigned long io_base, ctl_base;
ide_hwif_t *hwif;
@@ -319,30 +333,15 @@ static int ide_config(struct pcmcia_device *link)
if (is_kme)
outb(0x81, ctl_base+1);
- /* retry registration in case device is still spinning up */
- for (i = 0; i < 10; i++) {
- hwif = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link);
- if (hwif)
- break;
- if (link->io.NumPorts1 == 0x20) {
+ hwif = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link);
+ if (hwif == NULL && link->io.NumPorts1 == 0x20) {
outb(0x02, ctl_base + 0x10);
hwif = idecs_register(io_base + 0x10, ctl_base + 0x10,
link->irq.AssignedIRQ, link);
- if (hwif) {
- io_base += 0x10;
- ctl_base += 0x10;
- break;
- }
- }
- msleep(100);
}
- if (hwif == NULL) {
- printk(KERN_NOTICE "ide-cs: ide_register() at 0x%3lx & 0x%3lx"
- ", irq %u failed\n", io_base, ctl_base,
- link->irq.AssignedIRQ);
+ if (hwif == NULL)
goto failed;
- }
info->ndev = 1;
sprintf(info->node.dev_name, "hd%c", 'a' + hwif->index * 2);
@@ -411,6 +410,7 @@ static struct pcmcia_device_id ide_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001), /* Mitsubishi CFA */
PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), /* SanDisk CFA */
+ PCMCIA_DEVICE_MANF_CARD(0x004f, 0x0000), /* Kingston */
PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */
PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */
@@ -440,6 +440,7 @@ static struct pcmcia_device_id ide_ids[] = {
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("M-Systems", "CF300", 0x7ed2ad87, 0x7e9e78ee),
PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c),
PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79),
PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
@@ -450,6 +451,7 @@ static struct pcmcia_device_id ide_ids[] = {
PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF45", 0x709b1bf1, 0xf68b6f32),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
index caa2632dd08e..2e84290d0bcc 100644
--- a/drivers/ide/legacy/macide.c
+++ b/drivers/ide/legacy/macide.c
@@ -78,6 +78,8 @@ static void __init macide_setup_ports(hw_regs_t *hw, unsigned long base,
hw->irq = irq;
hw->ack_intr = ack_intr;
+
+ hw->chipset = ide_generic;
}
static const char *mac_ide_name[] =
diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c
index 6f535d00e638..8ff6e2d20834 100644
--- a/drivers/ide/legacy/q40ide.c
+++ b/drivers/ide/legacy/q40ide.c
@@ -70,6 +70,8 @@ static void q40_ide_setup_ports(hw_regs_t *hw, unsigned long base,
hw->irq = irq;
hw->ack_intr = ack_intr;
+
+ hw->chipset = ide_generic;
}
static void q40ide_input_data(ide_drive_t *drive, struct request *rq,
diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
index aaf38109eaec..b38a1980dcd5 100644
--- a/drivers/ide/pci/cmd640.c
+++ b/drivers/ide/pci/cmd640.c
@@ -747,9 +747,11 @@ static int __init cmd640x_init(void)
ide_std_init_ports(&hw[0], 0x1f0, 0x3f6);
hw[0].irq = 14;
+ hw[0].chipset = ide_cmd640;
ide_std_init_ports(&hw[1], 0x170, 0x376);
hw[1].irq = 15;
+ hw[1].chipset = ide_cmd640;
printk(KERN_INFO "cmd640: buggy cmd640%c interface on %s, config=0x%02x"
"\n", 'a' + cmd640_chip_version - 1, bus_type, cfr);
diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c
index b9e457996d0e..af0f30051d5a 100644
--- a/drivers/ide/pci/delkin_cb.c
+++ b/drivers/ide/pci/delkin_cb.c
@@ -47,13 +47,18 @@ static const struct ide_port_ops delkin_cb_port_ops = {
.quirkproc = ide_undecoded_slave,
};
+static const struct ide_port_info delkin_cb_port_info = {
+ .port_ops = &delkin_cb_port_ops,
+ .host_flags = IDE_HFLAG_IO_32BIT | IDE_HFLAG_UNMASK_IRQS |
+ IDE_HFLAG_NO_DMA,
+};
+
static int __devinit
delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
{
unsigned long base;
hw_regs_t hw;
ide_hwif_t *hwif = NULL;
- ide_drive_t *drive;
int i, rc;
u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
@@ -79,6 +84,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
memset(&hw, 0, sizeof(hw));
ide_std_init_ports(&hw, base + 0x10, base + 0x1e);
hw.irq = dev->irq;
+ hw.dev = &dev->dev;
hw.chipset = ide_pci; /* this enables IRQ sharing */
hwif = ide_find_port();
@@ -89,26 +95,16 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
ide_init_port_data(hwif, i);
ide_init_port_hw(hwif, &hw);
- hwif->port_ops = &delkin_cb_port_ops;
idx[0] = i;
- ide_device_add(idx, NULL);
-
- if (!hwif->present)
- goto out_disable;
+ ide_device_add(idx, &delkin_cb_port_info);
pci_set_drvdata(dev, hwif);
- hwif->dev = &dev->dev;
- drive = &hwif->drives[0];
- if (drive->present) {
- drive->io_32bit = 1;
- drive->unmask = 1;
- }
+
return 0;
out_disable:
- printk(KERN_ERR "delkin_cb: no IDE devices found\n");
pci_release_regions(dev);
pci_disable_device(dev);
return -ENODEV;
@@ -139,14 +135,12 @@ static struct pci_driver driver = {
.remove = delkin_cb_remove,
};
-static int
-delkin_cb_init (void)
+static int __init delkin_cb_init(void)
{
return pci_register_driver(&driver);
}
-static void
-delkin_cb_exit (void)
+static void __exit delkin_cb_exit(void)
{
pci_unregister_driver(&driver);
}
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
index 9053c8771e6e..2b71bdf74e73 100644
--- a/drivers/ide/pci/it8213.c
+++ b/drivers/ide/pci/it8213.c
@@ -184,8 +184,7 @@ static const struct ide_port_info it8213_chipsets[] __devinitdata = {
static int __devinit it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- ide_setup_pci_device(dev, &it8213_chipsets[id->driver_data]);
- return 0;
+ return ide_setup_pci_device(dev, &it8213_chipsets[id->driver_data]);
}
static const struct pci_device_id it8213_pci_tbl[] = {
diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
index fec4955f449b..a7a41bb82778 100644
--- a/drivers/ide/pci/ns87415.c
+++ b/drivers/ide/pci/ns87415.c
@@ -225,10 +225,6 @@ static int ns87415_dma_setup(ide_drive_t *drive)
return 1;
}
-#ifndef ide_default_irq
-#define ide_default_irq(irq) 0
-#endif
-
static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
@@ -288,7 +284,7 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
}
if (!using_inta)
- hwif->irq = ide_default_irq(hwif->io_ports.data_addr);
+ hwif->irq = __ide_default_irq(hwif->io_ports.data_addr);
else if (!hwif->irq && hwif->mate && hwif->mate->irq)
hwif->irq = hwif->mate->irq; /* share IRQ with mate */
diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c
index 6e99080497bf..725c80508d90 100644
--- a/drivers/ide/pci/opti621.c
+++ b/drivers/ide/pci/opti621.c
@@ -81,8 +81,6 @@
* 0.5 doesn't work.
*/
-#define OPTI621_DEBUG /* define for debug messages */
-
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -92,28 +90,6 @@
#include <asm/io.h>
-//#define OPTI621_MAX_PIO 3
-/* In fact, I do not have any PIO 4 drive
- * (address: 25 ns, data: 70 ns, recovery: 35 ns),
- * but OPTi 82C621 is programmable and it can do (minimal values):
- * on 40MHz PCI bus (pulse 25 ns):
- * address: 25 ns, data: 25 ns, recovery: 50 ns;
- * on 20MHz PCI bus (pulse 50 ns):
- * address: 50 ns, data: 50 ns, recovery: 100 ns.
- */
-
-/* #define READ_PREFETCH 0 */
-/* Uncomment for disable read prefetch.
- * There is some readprefetch capatibility in hdparm,
- * but when I type hdparm -P 1 /dev/hda, I got errors
- * and till reset drive is inaccessible.
- * This (hw) read prefetch is safe on my drive.
- */
-
-#ifndef READ_PREFETCH
-#define READ_PREFETCH 0x40 /* read prefetch is enabled */
-#endif /* else read prefetch is disabled */
-
#define READ_REG 0 /* index of Read cycle timing register */
#define WRITE_REG 1 /* index of Write cycle timing register */
#define CNTRL_REG 3 /* index of Control register */
@@ -122,51 +98,8 @@
static int reg_base;
-#define PIO_NOT_EXIST 254
-#define PIO_DONT_KNOW 255
-
static DEFINE_SPINLOCK(opti621_lock);
-/* there are stored pio numbers from other calls of opti621_set_pio_mode */
-static void compute_pios(ide_drive_t *drive, const u8 pio)
-/* Store values into drive->drive_data
- * second_contr - 0 for primary controller, 1 for secondary
- * slave_drive - 0 -> pio is for master, 1 -> pio is for slave
- * pio - PIO mode for selected drive (for other we don't know)
- */
-{
- int d;
- ide_hwif_t *hwif = HWIF(drive);
-
- drive->drive_data = pio;
-
- for (d = 0; d < 2; ++d) {
- drive = &hwif->drives[d];
- if (drive->present) {
- if (drive->drive_data == PIO_DONT_KNOW)
- drive->drive_data = ide_get_best_pio_mode(drive, 255, 3);
-#ifdef OPTI621_DEBUG
- printk("%s: Selected PIO mode %d\n",
- drive->name, drive->drive_data);
-#endif
- } else {
- drive->drive_data = PIO_NOT_EXIST;
- }
- }
-}
-
-static int cmpt_clk(int time, int bus_speed)
-/* Returns (rounded up) time in clocks for time in ns,
- * with bus_speed in MHz.
- * Example: bus_speed = 40 MHz, time = 80 ns
- * 1000/40 = 25 ns (clk value),
- * 80/25 = 3.2, rounded up to 4 (I hope ;-)).
- * Use idebus=xx to select right frequency.
- */
-{
- return ((time*bus_speed+999)/1000);
-}
-
/* Write value to register reg, base of register
* is at reg_base (0x1f0 primary, 0x170 secondary,
* if not changed by PCI configuration).
@@ -199,83 +132,29 @@ static u8 read_reg(int reg)
return ret;
}
-typedef struct pio_clocks_s {
- int address_time; /* Address setup (clocks) */
- int data_time; /* Active/data pulse (clocks) */
- int recovery_time; /* Recovery time (clocks) */
-} pio_clocks_t;
-
-static void compute_clocks(int pio, pio_clocks_t *clks)
-{
- if (pio != PIO_NOT_EXIST) {
- int adr_setup, data_pls;
- int bus_speed = ide_pci_clk ? ide_pci_clk : system_bus_clock();
-
- adr_setup = ide_pio_timings[pio].setup_time;
- data_pls = ide_pio_timings[pio].active_time;
- clks->address_time = cmpt_clk(adr_setup, bus_speed);
- clks->data_time = cmpt_clk(data_pls, bus_speed);
- clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
- - adr_setup-data_pls, bus_speed);
- if (clks->address_time < 1)
- clks->address_time = 1;
- if (clks->address_time > 4)
- clks->address_time = 4;
- if (clks->data_time < 1)
- clks->data_time = 1;
- if (clks->data_time > 16)
- clks->data_time = 16;
- if (clks->recovery_time < 2)
- clks->recovery_time = 2;
- if (clks->recovery_time > 17)
- clks->recovery_time = 17;
- } else {
- clks->address_time = 1;
- clks->data_time = 1;
- clks->recovery_time = 2;
- /* minimal values */
- }
-}
-
static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- /* primary and secondary drives share some registers,
- * so we have to program both drives
- */
+ ide_hwif_t *hwif = drive->hwif;
+ ide_drive_t *pair = ide_get_paired_drive(drive);
unsigned long flags;
- u8 pio1 = 0, pio2 = 0;
- pio_clocks_t first, second;
- int ax, drdy;
- u8 cycle1, cycle2, misc;
- ide_hwif_t *hwif = HWIF(drive);
-
- /* sets drive->drive_data for both drives */
- compute_pios(drive, pio);
- pio1 = hwif->drives[0].drive_data;
- pio2 = hwif->drives[1].drive_data;
-
- compute_clocks(pio1, &first);
- compute_clocks(pio2, &second);
-
- /* ax = max(a1,a2) */
- ax = (first.address_time < second.address_time) ? second.address_time : first.address_time;
-
- drdy = 2; /* DRDY is default 2 (by OPTi Databook) */
-
- cycle1 = ((first.data_time-1)<<4) | (first.recovery_time-2);
- cycle2 = ((second.data_time-1)<<4) | (second.recovery_time-2);
- misc = READ_PREFETCH | ((ax-1)<<4) | ((drdy-2)<<1);
-
-#ifdef OPTI621_DEBUG
- printk("%s: master: address: %d, data: %d, "
- "recovery: %d, drdy: %d [clk]\n",
- hwif->name, ax, first.data_time,
- first.recovery_time, drdy);
- printk("%s: slave: address: %d, data: %d, "
- "recovery: %d, drdy: %d [clk]\n",
- hwif->name, ax, second.data_time,
- second.recovery_time, drdy);
-#endif
+ u8 tim, misc, addr_pio = pio, clk;
+
+ /* DRDY is default 2 (by OPTi Databook) */
+ static const u8 addr_timings[2][5] = {
+ { 0x20, 0x10, 0x00, 0x00, 0x00 }, /* 33 MHz */
+ { 0x10, 0x10, 0x00, 0x00, 0x00 }, /* 25 MHz */
+ };
+ static const u8 data_rec_timings[2][5] = {
+ { 0x5b, 0x45, 0x32, 0x21, 0x20 }, /* 33 MHz */
+ { 0x48, 0x34, 0x21, 0x10, 0x10 } /* 25 MHz */
+ };
+
+ drive->drive_data = XFER_PIO_0 + pio;
+
+ if (pair->present) {
+ if (pair->drive_data && pair->drive_data < drive->drive_data)
+ addr_pio = pair->drive_data - XFER_PIO_0;
+ }
spin_lock_irqsave(&opti621_lock, flags);
@@ -289,24 +168,21 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio)
(void)inb(reg_base + CNTRL_REG);
/* if reads 0xc0, no interface exist? */
read_reg(CNTRL_REG);
- /* read version, probably 0 */
- read_reg(STRAP_REG);
- /* program primary drive */
- /* select Index-0 for Register-A */
- write_reg(0, MISC_REG);
- /* set read cycle timings */
- write_reg(cycle1, READ_REG);
- /* set write cycle timings */
- write_reg(cycle1, WRITE_REG);
+ /* check CLK speed */
+ clk = read_reg(STRAP_REG) & 1;
+
+ printk(KERN_INFO "%s: CLK = %d MHz\n", hwif->name, clk ? 25 : 33);
- /* program secondary drive */
- /* select Index-1 for Register-B */
- write_reg(1, MISC_REG);
+ tim = data_rec_timings[clk][pio];
+ misc = addr_timings[clk][addr_pio];
+
+ /* select Index-0/1 for Register-A/B */
+ write_reg(drive->select.b.unit, MISC_REG);
/* set read cycle timings */
- write_reg(cycle2, READ_REG);
+ write_reg(tim, READ_REG);
/* set write cycle timings */
- write_reg(cycle2, WRITE_REG);
+ write_reg(tim, WRITE_REG);
/* use Register-A for drive 0 */
/* use Register-B for drive 1 */
@@ -319,45 +195,26 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio)
spin_unlock_irqrestore(&opti621_lock, flags);
}
-static void __devinit opti621_port_init_devs(ide_hwif_t *hwif)
-{
- hwif->drives[0].drive_data = PIO_DONT_KNOW;
- hwif->drives[1].drive_data = PIO_DONT_KNOW;
-}
-
static const struct ide_port_ops opti621_port_ops = {
- .port_init_devs = opti621_port_init_devs,
.set_pio_mode = opti621_set_pio_mode,
};
-static const struct ide_port_info opti621_chipsets[] __devinitdata = {
- { /* 0 */
- .name = "OPTI621",
- .enablebits = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} },
- .port_ops = &opti621_port_ops,
- .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA,
- .pio_mask = ATA_PIO3,
- .swdma_mask = ATA_SWDMA2,
- .mwdma_mask = ATA_MWDMA2,
- }, { /* 1 */
- .name = "OPTI621X",
- .enablebits = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} },
- .port_ops = &opti621_port_ops,
- .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA,
- .pio_mask = ATA_PIO3,
- .swdma_mask = ATA_SWDMA2,
- .mwdma_mask = ATA_MWDMA2,
- }
+static const struct ide_port_info opti621_chipset __devinitdata = {
+ .name = "OPTI621/X",
+ .enablebits = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} },
+ .port_ops = &opti621_port_ops,
+ .host_flags = IDE_HFLAG_NO_DMA,
+ .pio_mask = ATA_PIO4,
};
static int __devinit opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- return ide_setup_pci_device(dev, &opti621_chipsets[id->driver_data]);
+ return ide_setup_pci_device(dev, &opti621_chipset);
}
static const struct pci_device_id opti621_pci_tbl[] = {
{ PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 },
- { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 1 },
+ { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 0 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, opti621_pci_tbl);
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
index 4b0b85d8faf5..e127eb25ab63 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -569,6 +569,11 @@ static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_devi
{
struct ide_port_info d = sis5513_chipset;
u8 udma_rates[] = { 0x00, 0x00, 0x07, 0x1f, 0x3f, 0x3f, 0x7f, 0x7f };
+ int rc;
+
+ rc = pci_enable_device(dev);
+ if (rc)
+ return rc;
if (sis_find_family(dev) == 0)
return -ENOTSUPP;
diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c
index f0e638dcc3ab..236f9c38e519 100644
--- a/drivers/ide/ppc/mpc8xx.c
+++ b/drivers/ide/ppc/mpc8xx.c
@@ -303,6 +303,8 @@ static int __init m8xx_ide_init_ports(hw_regs_t *hw, unsigned long data_port)
pcmp->pcmc_per = 0x100000 >> (16 * _slot_);
#endif /* CONFIG_IDE_8xx_PCCARD */
+ hw->chipset = ide_generic;
+
return 0;
}
#endif /* CONFIG_IDE_8xx_PCCARD || CONFIG_IDE_8xx_DIRECT */
@@ -377,6 +379,8 @@ static int __init m8xx_ide_init_ports(hw_regs_t *hw, unsigned long data_port)
((immap_t *) IMAP_ADDR)->im_siu_conf.sc_siel |=
(0x80000000 >> ioport_dsc[data_port].irq);
+ hw->chipset = ide_generic;
+
return 0;
}
#endif /* CONFIG_IDE_8xx_DIRECT */
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 48aa019127bc..ba2d58727964 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -59,7 +59,6 @@ typedef struct pmac_ide_hwif {
int irq;
int kind;
int aapl_bus_id;
- unsigned cable_80 : 1;
unsigned mediabay : 1;
unsigned broken_dma : 1;
unsigned broken_dma_warn : 1;
@@ -918,10 +917,40 @@ pmac_ide_do_resume(ide_hwif_t *hwif)
return 0;
}
+static u8 pmac_ide_cable_detect(ide_hwif_t *hwif)
+{
+ pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)ide_get_hwifdata(hwif);
+ struct device_node *np = pmif->node;
+ const char *cable = of_get_property(np, "cable-type", NULL);
+
+ /* Get cable type from device-tree. */
+ if (cable && !strncmp(cable, "80-", 3))
+ return ATA_CBL_PATA80;
+
+ /*
+ * G5's seem to have incorrect cable type in device-tree.
+ * Let's assume they have a 80 conductor cable, this seem
+ * to be always the case unless the user mucked around.
+ */
+ if (of_device_is_compatible(np, "K2-UATA") ||
+ of_device_is_compatible(np, "shasta-ata"))
+ return ATA_CBL_PATA80;
+
+ return ATA_CBL_PATA40;
+}
+
static const struct ide_port_ops pmac_ide_ata6_port_ops = {
.set_pio_mode = pmac_ide_set_pio_mode,
.set_dma_mode = pmac_ide_set_dma_mode,
.selectproc = pmac_ide_kauai_selectproc,
+ .cable_detect = pmac_ide_cable_detect,
+};
+
+static const struct ide_port_ops pmac_ide_ata4_port_ops = {
+ .set_pio_mode = pmac_ide_set_pio_mode,
+ .set_dma_mode = pmac_ide_set_dma_mode,
+ .selectproc = pmac_ide_selectproc,
+ .cable_detect = pmac_ide_cable_detect,
};
static const struct ide_port_ops pmac_ide_port_ops = {
@@ -949,10 +978,7 @@ static const struct ide_port_info pmac_port_info = {
/*
* Setup, register & probe an IDE channel driven by this driver, this is
- * called by one of the 2 probe functions (macio or PCI). Note that a channel
- * that ends up beeing free of any device is not kept around by this driver
- * (it is kept in 2.4). This introduce an interface numbering change on some
- * rare machines unfortunately, but it's better this way.
+ * called by one of the 2 probe functions (macio or PCI).
*/
static int __devinit
pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw)
@@ -962,7 +988,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw)
u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
struct ide_port_info d = pmac_port_info;
- pmif->cable_80 = 0;
pmif->broken_dma = pmif->broken_dma_warn = 0;
if (of_device_is_compatible(np, "shasta-ata")) {
pmif->kind = controller_sh_ata6;
@@ -979,6 +1004,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw)
} else if (of_device_is_compatible(np, "keylargo-ata")) {
if (strcmp(np->name, "ata-4") == 0) {
pmif->kind = controller_kl_ata4;
+ d.port_ops = &pmac_ide_ata4_port_ops;
d.udma_mask = ATA_UDMA4;
} else
pmif->kind = controller_kl_ata3;
@@ -992,22 +1018,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw)
bidp = of_get_property(np, "AAPL,bus-id", NULL);
pmif->aapl_bus_id = bidp ? *bidp : 0;
- /* Get cable type from device-tree */
- if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6
- || pmif->kind == controller_k2_ata6
- || pmif->kind == controller_sh_ata6) {
- const char* cable = of_get_property(np, "cable-type", NULL);
- if (cable && !strncmp(cable, "80-", 3))
- pmif->cable_80 = 1;
- }
- /* G5's seem to have incorrect cable type in device-tree. Let's assume
- * they have a 80 conductor cable, this seem to be always the case unless
- * the user mucked around
- */
- if (of_device_is_compatible(np, "K2-UATA") ||
- of_device_is_compatible(np, "shasta-ata"))
- pmif->cable_80 = 1;
-
/* On Kauai-type controllers, we make sure the FCR is correct */
if (pmif->kauai_fcr)
writel(KAUAI_FCR_UATA_MAGIC |
@@ -1053,7 +1063,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw)
hwif->hwif_data = pmif;
ide_init_port_hw(hwif, hw);
- hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s, irq %d\n",
hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
@@ -1070,11 +1079,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw)
}
}
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
- if (pmif->cable_80 == 0)
- d.udma_mask &= ATA_UDMA2;
-#endif
-
idx[0] = hwif->index;
ide_device_add(idx, &d);
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index 545663ef820b..95f45f9b8e5e 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -4,7 +4,7 @@ menu "IEEE 1394 (FireWire) support"
source "drivers/firewire/Kconfig"
config IEEE1394
- tristate "IEEE 1394 (FireWire) support"
+ tristate "Stable FireWire stack"
depends on PCI || BROKEN
help
IEEE 1394 describes a high performance serial bus, which is also
@@ -19,30 +19,45 @@ config IEEE1394
To compile this driver as a module, say M here: the
module will be called ieee1394.
-comment "Subsystem Options"
- depends on IEEE1394
-
-config IEEE1394_VERBOSEDEBUG
- bool "Excessive debugging output"
- depends on IEEE1394
+config IEEE1394_OHCI1394
+ tristate "OHCI-1394 controllers"
+ depends on PCI && IEEE1394
help
- If you say Y here, you will get very verbose debugging logs from
- the subsystem which includes a dump of the header of every sent
- and received packet. This can amount to a high amount of data
- collected in a very short time which is usually also saved to
- disk by the system logging daemons.
+ Enable this driver if you have an IEEE 1394 controller based on the
+ OHCI-1394 specification. The current driver is only tested with OHCI
+ chipsets made by Texas Instruments and NEC. Most third-party vendors
+ use one of these chipsets. It should work with any OHCI-1394
+ compliant card, however.
- Say Y if you really want or need the debugging output, everyone
- else says N.
+ To compile this driver as a module, say M here: the
+ module will be called ohci1394.
-comment "Controllers"
- depends on IEEE1394
+ NOTE:
-comment "Texas Instruments PCILynx requires I2C"
+ You should only build either ohci1394 or the new firewire-ohci driver,
+ but not both. If you nevertheless want to install both, you should
+ configure them only as modules and blacklist the driver(s) which you
+ don't want to have auto-loaded. Add either
+
+ blacklist firewire-ohci
+ or
+ blacklist ohci1394
+ blacklist video1394
+ blacklist dv1394
+
+ to /etc/modprobe.conf or /etc/modprobe.d/* and update modprobe.conf
+ depending on your distribution. The latter two modules should be
+ blacklisted together with ohci1394 because they depend on ohci1394.
+
+ If you have an old modprobe which doesn't implement the blacklist
+ directive, use "install modulename /bin/true" for the modules to be
+ blacklisted.
+
+comment "PCILynx controller requires I2C"
depends on IEEE1394 && I2C=n
config IEEE1394_PCILYNX
- tristate "Texas Instruments PCILynx support"
+ tristate "PCILynx controller"
depends on PCI && IEEE1394 && I2C
select I2C_ALGOBIT
help
@@ -57,35 +72,11 @@ config IEEE1394_PCILYNX
PowerMacs G3 B&W contain the PCILynx controller. Therefore
almost everybody can say N here.
-config IEEE1394_OHCI1394
- tristate "OHCI-1394 support"
- depends on PCI && IEEE1394
- help
- Enable this driver if you have an IEEE 1394 controller based on the
- OHCI-1394 specification. The current driver is only tested with OHCI
- chipsets made by Texas Instruments and NEC. Most third-party vendors
- use one of these chipsets. It should work with any OHCI-1394
- compliant card, however.
-
- To compile this driver as a module, say M here: the
- module will be called ohci1394.
-
-comment "Protocols"
- depends on IEEE1394
-
-config IEEE1394_VIDEO1394
- tristate "OHCI-1394 Video support"
- depends on IEEE1394 && IEEE1394_OHCI1394
- help
- This option enables video device usage for OHCI-1394 cards. Enable
- this option only if you have an IEEE 1394 video device connected to
- an OHCI-1394 card.
-
comment "SBP-2 support (for storage devices) requires SCSI"
depends on IEEE1394 && SCSI=n
config IEEE1394_SBP2
- tristate "SBP-2 support (Harddisks etc.)"
+ tristate "Storage devices (SBP-2 protocol)"
depends on IEEE1394 && SCSI
help
This option enables you to use SBP-2 devices connected to an IEEE
@@ -127,24 +118,47 @@ config IEEE1394_ETH1394
The module is called eth1394 although it does not emulate Ethernet.
+config IEEE1394_RAWIO
+ tristate "raw1394 userspace interface"
+ depends on IEEE1394
+ help
+ This option adds support for the raw1394 device file which enables
+ direct communication of user programs with IEEE 1394 devices
+ (isochronous and asynchronous). Almost all application programs
+ which access FireWire require this option.
+
+ To compile this driver as a module, say M here: the module will be
+ called raw1394.
+
+config IEEE1394_VIDEO1394
+ tristate "video1394 userspace interface"
+ depends on IEEE1394 && IEEE1394_OHCI1394
+ help
+ This option adds support for the video1394 device files which enable
+ isochronous communication of user programs with IEEE 1394 devices,
+ especially video capture or export. This interface is used by all
+ libdc1394 based programs and by several other programs, in addition to
+ the raw1394 interface. It is generally not required for DV capture.
+
+ To compile this driver as a module, say M here: the module will be
+ called video1394.
+
config IEEE1394_DV1394
- tristate "OHCI-DV I/O support (deprecated)"
+ tristate "dv1394 userspace interface (deprecated)"
depends on IEEE1394 && IEEE1394_OHCI1394
help
The dv1394 driver is unsupported and may be removed from Linux in a
future release. Its functionality is now provided by raw1394 together
with libraries such as libiec61883.
-config IEEE1394_RAWIO
- tristate "Raw IEEE1394 I/O support"
+config IEEE1394_VERBOSEDEBUG
+ bool "Excessive debugging output"
depends on IEEE1394
help
- This option adds support for the raw1394 device file which enables
- direct communication of user programs with the IEEE 1394 bus and thus
- with the attached peripherals. Almost all application programs which
- access FireWire require this option.
+ If you say Y here, you will get very verbose debugging logs from the
+ ieee1394 drivers, including sent and received packet headers. This
+ will quickly result in large amounts of data sent to the system log.
- To compile this driver as a module, say M here: the module will be
- called raw1394.
+ Say Y if you really need the debugging output. Everyone else says N.
endmenu
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 16b9d0ad154e..a5ceff287a28 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -1539,15 +1539,13 @@ static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb,
static void sbp2_create_command_orb(struct sbp2_lu *lu,
struct sbp2_command_info *cmd,
- unchar *scsi_cmd,
- unsigned int scsi_use_sg,
- unsigned int scsi_request_bufflen,
- struct scatterlist *sg,
- enum dma_data_direction dma_dir)
+ struct scsi_cmnd *SCpnt)
{
struct sbp2_fwhost_info *hi = lu->hi;
struct sbp2_command_orb *orb = &cmd->command_orb;
u32 orb_direction;
+ unsigned int scsi_request_bufflen = scsi_bufflen(SCpnt);
+ enum dma_data_direction dma_dir = SCpnt->sc_data_direction;
/*
* Set-up our command ORB.
@@ -1580,13 +1578,14 @@ static void sbp2_create_command_orb(struct sbp2_lu *lu,
orb->data_descriptor_lo = 0x0;
orb->misc |= ORB_SET_DIRECTION(1);
} else
- sbp2_prep_command_orb_sg(orb, hi, cmd, scsi_use_sg, sg,
+ sbp2_prep_command_orb_sg(orb, hi, cmd, scsi_sg_count(SCpnt),
+ scsi_sglist(SCpnt),
orb_direction, dma_dir);
sbp2util_cpu_to_be32_buffer(orb, sizeof(*orb));
- memset(orb->cdb, 0, 12);
- memcpy(orb->cdb, scsi_cmd, COMMAND_SIZE(*scsi_cmd));
+ memset(orb->cdb, 0, sizeof(orb->cdb));
+ memcpy(orb->cdb, SCpnt->cmnd, SCpnt->cmd_len);
}
static void sbp2_link_orb_command(struct sbp2_lu *lu,
@@ -1669,16 +1668,13 @@ static void sbp2_link_orb_command(struct sbp2_lu *lu,
static int sbp2_send_command(struct sbp2_lu *lu, struct scsi_cmnd *SCpnt,
void (*done)(struct scsi_cmnd *))
{
- unchar *scsi_cmd = (unchar *)SCpnt->cmnd;
struct sbp2_command_info *cmd;
cmd = sbp2util_allocate_command_orb(lu, SCpnt, done);
if (!cmd)
return -EIO;
- sbp2_create_command_orb(lu, cmd, scsi_cmd, scsi_sg_count(SCpnt),
- scsi_bufflen(SCpnt), scsi_sglist(SCpnt),
- SCpnt->sc_data_direction);
+ sbp2_create_command_orb(lu, cmd, SCpnt);
sbp2_link_orb_command(lu, cmd);
return 0;
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index fbe16d5250a4..1adf2efd3cb3 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -747,7 +747,9 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
break;
case IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED:
kmem_cache_free(ib_mad_cache, mad_priv);
- break;
+ kfree(local);
+ ret = 1;
+ goto out;
case IB_MAD_RESULT_SUCCESS:
/* Treat like an incoming receive MAD */
port_priv = ib_get_mad_port(mad_agent_priv->agent.device,
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index fe78f7d25099..a1768dbb0720 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -150,7 +150,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
ret = 0;
while (npages) {
ret = get_user_pages(current, current->mm, cur_base,
- min_t(int, npages,
+ min_t(unsigned long, npages,
PAGE_SIZE / sizeof (struct page *)),
1, !umem->writable, page_list, vma_list);
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index ef6dd825fee9..208c7f34323c 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -1018,8 +1018,9 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
if (cdev_add(port->cdev, base_dev + port->dev_num, 1))
goto err_cdev;
- port->dev = device_create(umad_class, device->dma_device,
- port->cdev->dev, "umad%d", port->dev_num);
+ port->dev = device_create_drvdata(umad_class, device->dma_device,
+ port->cdev->dev, port,
+ "umad%d", port->dev_num);
if (IS_ERR(port->dev))
goto err_cdev;
@@ -1037,15 +1038,12 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
if (cdev_add(port->sm_cdev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1))
goto err_sm_cdev;
- port->sm_dev = device_create(umad_class, device->dma_device,
- port->sm_cdev->dev,
- "issm%d", port->dev_num);
+ port->sm_dev = device_create_drvdata(umad_class, device->dma_device,
+ port->sm_cdev->dev, port,
+ "issm%d", port->dev_num);
if (IS_ERR(port->sm_dev))
goto err_sm_cdev;
- dev_set_drvdata(port->dev, port);
- dev_set_drvdata(port->sm_dev, port);
-
if (device_create_file(port->sm_dev, &dev_attr_ibdev))
goto err_sm_dev;
if (device_create_file(port->sm_dev, &dev_attr_port))
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index fdfcf7910d9a..0f34858e31e7 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -423,7 +423,7 @@ static void ib_uverbs_async_handler(struct ib_uverbs_file *file,
unsigned long flags;
spin_lock_irqsave(&file->async_file->lock, flags);
- if (!file->async_file->is_closed) {
+ if (file->async_file->is_closed) {
spin_unlock_irqrestore(&file->async_file->lock, flags);
return;
}
@@ -766,14 +766,15 @@ static void ib_uverbs_add_one(struct ib_device *device)
if (cdev_add(uverbs_dev->cdev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1))
goto err_cdev;
- uverbs_dev->dev = device_create(uverbs_class, device->dma_device,
- uverbs_dev->cdev->dev,
- "uverbs%d", uverbs_dev->devnum);
+ uverbs_dev->dev = device_create_drvdata(uverbs_class,
+ device->dma_device,
+ uverbs_dev->cdev->dev,
+ uverbs_dev,
+ "uverbs%d",
+ uverbs_dev->devnum);
if (IS_ERR(uverbs_dev->dev))
goto err_cdev;
- dev_set_drvdata(uverbs_dev->dev, uverbs_dev);
-
if (device_create_file(uverbs_dev->dev, &dev_attr_ibdev))
goto err_class;
if (device_create_file(uverbs_dev->dev, &dev_attr_abi_version))
diff --git a/drivers/infiniband/hw/amso1100/c2_rnic.c b/drivers/infiniband/hw/amso1100/c2_rnic.c
index 9a054c6941a4..b1441aeb60c2 100644
--- a/drivers/infiniband/hw/amso1100/c2_rnic.c
+++ b/drivers/infiniband/hw/amso1100/c2_rnic.c
@@ -455,8 +455,7 @@ int __devinit c2_rnic_init(struct c2_dev *c2dev)
IB_DEVICE_CURR_QP_STATE_MOD |
IB_DEVICE_SYS_IMAGE_GUID |
IB_DEVICE_ZERO_STAG |
- IB_DEVICE_MEM_WINDOW |
- IB_DEVICE_SEND_W_INV);
+ IB_DEVICE_MEM_WINDOW);
/* Allocate the qptr_array */
c2dev->qptr_array = vmalloc(C2_MAX_CQS * sizeof(void *));
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index 8934178a23ee..95f82cfb6c54 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -1096,7 +1096,9 @@ static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr, ch
struct net_device *lldev = iwch_dev->rdev.t3cdev_p->lldev;
PDBG("%s dev 0x%p\n", __func__, dev);
+ rtnl_lock();
lldev->ethtool_ops->get_drvinfo(lldev, &info);
+ rtnl_unlock();
return sprintf(buf, "%s\n", info.fw_version);
}
@@ -1109,7 +1111,9 @@ static ssize_t show_hca(struct device *dev, struct device_attribute *attr,
struct net_device *lldev = iwch_dev->rdev.t3cdev_p->lldev;
PDBG("%s dev 0x%p\n", __func__, dev);
+ rtnl_lock();
lldev->ethtool_ops->get_drvinfo(lldev, &info);
+ rtnl_unlock();
return sprintf(buf, "%s\n", info.driver);
}
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index 79dbe5beae52..992613799228 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -229,7 +229,7 @@ int iwch_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct ib_send_wr **bad_wr)
{
int err = 0;
- u8 t3_wr_flit_cnt;
+ u8 uninitialized_var(t3_wr_flit_cnt);
enum t3_wr_opcode t3_wr_opcode = 0;
enum t3_wr_flags t3_wr_flags;
struct iwch_qp *qhp;
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index bbe0436f4f75..f093b0033daf 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -421,8 +421,10 @@ int ehca_post_send(struct ib_qp *qp,
int ret = 0;
unsigned long flags;
- if (unlikely(my_qp->state != IB_QPS_RTS)) {
- ehca_err(qp->device, "QP not in RTS state qpn=%x", qp->qp_num);
+ /* Reject WR if QP is in RESET, INIT or RTR state */
+ if (unlikely(my_qp->state < IB_QPS_RTS)) {
+ ehca_err(qp->device, "Invalid QP state qp_state=%d qpn=%x",
+ my_qp->state, qp->qp_num);
return -EINVAL;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 59a8b254b97f..0bd8bcb184a1 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -232,6 +232,11 @@ struct ipath_sdma_desc {
#define IPATH_SDMA_TXREQ_S_ABORTED 2
#define IPATH_SDMA_TXREQ_S_SHUTDOWN 3
+#define IPATH_SDMA_STATUS_SCORE_BOARD_DRAIN_IN_PROG (1ull << 63)
+#define IPATH_SDMA_STATUS_ABORT_IN_PROG (1ull << 62)
+#define IPATH_SDMA_STATUS_INTERNAL_SDMA_ENABLE (1ull << 61)
+#define IPATH_SDMA_STATUS_SCB_EMPTY (1ull << 30)
+
/* max dwords in small buffer packet */
#define IPATH_SMALLBUF_DWORDS (dd->ipath_piosize2k >> 2)
diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c
index 1ff46ae7dd99..5f9315d77a43 100644
--- a/drivers/infiniband/hw/ipath/ipath_mad.c
+++ b/drivers/infiniband/hw/ipath/ipath_mad.c
@@ -1492,6 +1492,10 @@ static int process_subn(struct ib_device *ibdev, int mad_flags,
goto bail;
}
+ case IB_MGMT_METHOD_TRAP:
+ case IB_MGMT_METHOD_REPORT:
+ case IB_MGMT_METHOD_REPORT_RESP:
+ case IB_MGMT_METHOD_TRAP_REPRESS:
case IB_MGMT_METHOD_GET_RESP:
/*
* The ib_mad module will call us to process responses
diff --git a/drivers/infiniband/hw/ipath/ipath_sdma.c b/drivers/infiniband/hw/ipath/ipath_sdma.c
index 3697449c1ba4..eaba03273e4f 100644
--- a/drivers/infiniband/hw/ipath/ipath_sdma.c
+++ b/drivers/infiniband/hw/ipath/ipath_sdma.c
@@ -263,14 +263,10 @@ static void sdma_abort_task(unsigned long opaque)
hwstatus = ipath_read_kreg64(dd,
dd->ipath_kregs->kr_senddmastatus);
- if (/* ScoreBoardDrainInProg */
- test_bit(63, &hwstatus) ||
- /* AbortInProg */
- test_bit(62, &hwstatus) ||
- /* InternalSDmaEnable */
- test_bit(61, &hwstatus) ||
- /* ScbEmpty */
- !test_bit(30, &hwstatus)) {
+ if ((hwstatus & (IPATH_SDMA_STATUS_SCORE_BOARD_DRAIN_IN_PROG |
+ IPATH_SDMA_STATUS_ABORT_IN_PROG |
+ IPATH_SDMA_STATUS_INTERNAL_SDMA_ENABLE)) ||
+ !(hwstatus & IPATH_SDMA_STATUS_SCB_EMPTY)) {
if (dd->ipath_sdma_reset_wait > 0) {
/* not done shutting down sdma */
--dd->ipath_sdma_reset_wait;
@@ -345,7 +341,7 @@ resched:
* state change
*/
if (jiffies > dd->ipath_sdma_abort_jiffies) {
- ipath_dbg("looping with status 0x%016llx\n",
+ ipath_dbg("looping with status 0x%08lx\n",
dd->ipath_sdma_status);
dd->ipath_sdma_abort_jiffies = jiffies + 5 * HZ;
}
@@ -615,7 +611,7 @@ void ipath_restart_sdma(struct ipath_devdata *dd)
}
spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
if (!needed) {
- ipath_dbg("invalid attempt to restart SDMA, status 0x%016llx\n",
+ ipath_dbg("invalid attempt to restart SDMA, status 0x%08lx\n",
dd->ipath_sdma_status);
goto bail;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c
index 7fd18e833907..0596ec16fcbd 100644
--- a/drivers/infiniband/hw/ipath/ipath_uc.c
+++ b/drivers/infiniband/hw/ipath/ipath_uc.c
@@ -407,12 +407,11 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
dev->n_pkt_drops++;
goto done;
}
- /* XXX Need to free SGEs */
+ wc.opcode = IB_WC_RECV;
last_imm:
ipath_copy_sge(&qp->r_sge, data, tlen);
wc.wr_id = qp->r_wr_id;
wc.status = IB_WC_SUCCESS;
- wc.opcode = IB_WC_RECV;
wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
wc.slid = qp->remote_ah_attr.dlid;
@@ -514,6 +513,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
goto done;
}
wc.byte_len = qp->r_len;
+ wc.opcode = IB_WC_RECV_RDMA_WITH_IMM;
goto last_imm;
case OP(RDMA_WRITE_LAST):
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index e0ec540042bf..7779165b2c2c 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -1494,7 +1494,8 @@ static int ipath_query_device(struct ib_device *ibdev,
props->device_cap_flags = IB_DEVICE_BAD_PKEY_CNTR |
IB_DEVICE_BAD_QKEY_CNTR | IB_DEVICE_SHUTDOWN_PORT |
- IB_DEVICE_SYS_IMAGE_GUID;
+ IB_DEVICE_SYS_IMAGE_GUID | IB_DEVICE_RC_RNR_NAK_GEN |
+ IB_DEVICE_PORT_ACTIVE_EVENT | IB_DEVICE_SRQ_RESIZE;
props->page_size_cap = PAGE_SIZE;
props->vendor_id = dev->dd->ipath_vendorid;
props->vendor_part_id = dev->dd->ipath_deviceid;
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 8e02ecfec188..a80df22deae8 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -333,6 +333,9 @@ static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
cap->max_inline_data + sizeof (struct mlx4_wqe_inline_seg)) +
send_wqe_overhead(type, qp->flags);
+ if (s > dev->dev->caps.max_sq_desc_sz)
+ return -EINVAL;
+
/*
* Hermon supports shrinking WQEs, such that a single work
* request can include multiple units of 1 << wqe_shift. This
@@ -372,9 +375,6 @@ static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
qp->sq.wqe_shift = ilog2(roundup_pow_of_two(s));
for (;;) {
- if (1 << qp->sq.wqe_shift > dev->dev->caps.max_sq_desc_sz)
- return -EINVAL;
-
qp->sq_max_wqes_per_wr = DIV_ROUND_UP(s, 1U << qp->sq.wqe_shift);
/*
@@ -395,7 +395,8 @@ static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
++qp->sq.wqe_shift;
}
- qp->sq.max_gs = ((qp->sq_max_wqes_per_wr << qp->sq.wqe_shift) -
+ qp->sq.max_gs = (min(dev->dev->caps.max_sq_desc_sz,
+ (qp->sq_max_wqes_per_wr << qp->sq.wqe_shift)) -
send_wqe_overhead(type, qp->flags)) /
sizeof (struct mlx4_wqe_data_seg);
@@ -411,7 +412,9 @@ static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
cap->max_send_wr = qp->sq.max_post =
(qp->sq.wqe_cnt - qp->sq_spare_wqes) / qp->sq_max_wqes_per_wr;
- cap->max_send_sge = qp->sq.max_gs;
+ cap->max_send_sge = min(qp->sq.max_gs,
+ min(dev->dev->caps.max_sq_sg,
+ dev->dev->caps.max_rq_sg));
/* We don't support inline sends for kernel QPs (yet) */
cap->max_inline_data = 0;
@@ -1457,7 +1460,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
unsigned ind;
int uninitialized_var(stamp);
int uninitialized_var(size);
- unsigned seglen;
+ unsigned uninitialized_var(seglen);
int i;
spin_lock_irqsave(&qp->sq.lock, flags);
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index 9ebadd6e0cfb..200cf13fc9bb 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -45,6 +45,7 @@
#include "mthca_cmd.h"
#include "mthca_profile.h"
#include "mthca_memfree.h"
+#include "mthca_wqe.h"
MODULE_AUTHOR("Roland Dreier");
MODULE_DESCRIPTION("Mellanox InfiniBand HCA low-level driver");
@@ -200,7 +201,18 @@ static int mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim *dev_lim)
mdev->limits.gid_table_len = dev_lim->max_gids;
mdev->limits.pkey_table_len = dev_lim->max_pkeys;
mdev->limits.local_ca_ack_delay = dev_lim->local_ca_ack_delay;
- mdev->limits.max_sg = dev_lim->max_sg;
+ /*
+ * Need to allow for worst case send WQE overhead and check
+ * whether max_desc_sz imposes a lower limit than max_sg; UD
+ * send has the biggest overhead.
+ */
+ mdev->limits.max_sg = min_t(int, dev_lim->max_sg,
+ (dev_lim->max_desc_sz -
+ sizeof (struct mthca_next_seg) -
+ (mthca_is_memfree(mdev) ?
+ sizeof (struct mthca_arbel_ud_seg) :
+ sizeof (struct mthca_tavor_ud_seg))) /
+ sizeof (struct mthca_data_seg));
mdev->limits.max_wqes = dev_lim->max_qp_sz;
mdev->limits.max_qp_init_rdma = dev_lim->max_requester_per_qp;
mdev->limits.reserved_qps = dev_lim->reserved_qps;
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
index b224079d4e1f..d5862e5d99a0 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -109,7 +109,11 @@ static int mthca_alloc_icm_pages(struct scatterlist *mem, int order, gfp_t gfp_m
{
struct page *page;
- page = alloc_pages(gfp_mask, order);
+ /*
+ * Use __GFP_ZERO because buggy firmware assumes ICM pages are
+ * cleared, and subtle failures are seen if they aren't.
+ */
+ page = alloc_pages(gfp_mask | __GFP_ZERO, order);
if (!page)
return -ENOMEM;
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index 99b3c4ae86eb..d617da9bd351 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -2456,10 +2456,8 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
if ((page_count!=0)&&(page_count<<12)-(region->offset&(4096-1))>=region->length)
goto enough_pages;
if ((page_count&0x01FF) == 0) {
- if (page_count>(1024*512)) {
+ if (page_count >= 1024 * 512) {
ib_umem_release(region);
- pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
- vpbl.pbl_pbase);
nes_free_resource(nesadapter,
nesadapter->allocated_mrs, stag_index);
kfree(nesmr);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index d00a2c174aee..3f663fb852c1 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -194,7 +194,13 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
/* Set the cached Q_Key before we attach if it's the broadcast group */
if (!memcmp(mcast->mcmember.mgid.raw, priv->dev->broadcast + 4,
sizeof (union ib_gid))) {
+ spin_lock_irq(&priv->lock);
+ if (!priv->broadcast) {
+ spin_unlock_irq(&priv->lock);
+ return -EAGAIN;
+ }
priv->qkey = be32_to_cpu(priv->broadcast->mcmember.qkey);
+ spin_unlock_irq(&priv->lock);
priv->tx_wr.wr.ud.remote_qkey = priv->qkey;
}
diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c
index eebc72465fc9..72c63e5dd630 100644
--- a/drivers/input/ff-core.c
+++ b/drivers/input/ff-core.c
@@ -28,6 +28,7 @@
#include <linux/input.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/sched.h>
/*
* Check that the effect_id is a valid effect and whether the user
@@ -166,8 +167,10 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect,
if (ret)
goto out;
+ spin_lock_irq(&dev->event_lock);
ff->effects[id] = *effect;
ff->effect_owners[id] = file;
+ spin_unlock_irq(&dev->event_lock);
out:
mutex_unlock(&ff->mutex);
@@ -189,16 +192,22 @@ static int erase_effect(struct input_dev *dev, int effect_id,
if (error)
return error;
+ spin_lock_irq(&dev->event_lock);
ff->playback(dev, effect_id, 0);
+ ff->effect_owners[effect_id] = NULL;
+ spin_unlock_irq(&dev->event_lock);
if (ff->erase) {
error = ff->erase(dev, effect_id);
- if (error)
+ if (error) {
+ spin_lock_irq(&dev->event_lock);
+ ff->effect_owners[effect_id] = file;
+ spin_unlock_irq(&dev->event_lock);
+
return error;
+ }
}
- ff->effect_owners[effect_id] = NULL;
-
return 0;
}
@@ -263,8 +272,6 @@ int input_ff_event(struct input_dev *dev, unsigned int type,
if (type != EV_FF)
return 0;
- mutex_lock(&ff->mutex);
-
switch (code) {
case FF_GAIN:
if (!test_bit(FF_GAIN, dev->ffbit) || value > 0xffff)
@@ -286,7 +293,6 @@ int input_ff_event(struct input_dev *dev, unsigned int type,
break;
}
- mutex_unlock(&ff->mutex);
return 0;
}
EXPORT_SYMBOL_GPL(input_ff_event);
diff --git a/drivers/input/keyboard/aaed2000_kbd.c b/drivers/input/keyboard/aaed2000_kbd.c
index a293e8b3f508..8a77bfcd05bc 100644
--- a/drivers/input/keyboard/aaed2000_kbd.c
+++ b/drivers/input/keyboard/aaed2000_kbd.c
@@ -183,4 +183,4 @@ module_exit(aaedkbd_exit);
MODULE_AUTHOR("Nicolas Bellido Y Ortega");
MODULE_DESCRIPTION("AAED-2000 Keyboard Driver");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 4a95adc4cc78..af58a6f1e898 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -807,6 +807,8 @@ static int atkbd_activate(struct atkbd *atkbd)
static void atkbd_cleanup(struct serio *serio)
{
struct atkbd *atkbd = serio_get_drvdata(serio);
+
+ atkbd_disable(atkbd);
ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_BAT);
}
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index 29fbec6218b9..1aa46ae12630 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -412,5 +412,5 @@ module_exit(corgikbd_exit);
MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
MODULE_DESCRIPTION("Corgi Keyboard Driver");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:corgi-keyboard");
diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c
index 9387da343f97..781fc6102860 100644
--- a/drivers/input/keyboard/jornada680_kbd.c
+++ b/drivers/input/keyboard/jornada680_kbd.c
@@ -275,5 +275,5 @@ module_exit(jornada680kbd_exit);
MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
MODULE_DESCRIPTION("HP Jornada 620/660/680/690 Keyboard Driver");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:jornada680_kbd");
diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c
index a1164a0c7736..ce650af6d649 100644
--- a/drivers/input/keyboard/jornada720_kbd.c
+++ b/drivers/input/keyboard/jornada720_kbd.c
@@ -29,7 +29,7 @@
MODULE_AUTHOR("Kristoffer Ericson <Kristoffer.Ericson@gmail.com>");
MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
static unsigned short jornada_std_keymap[128] = { /* ROW */
0, KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, /* #1 */
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c
index 3dea0c5077a9..45767e73f071 100644
--- a/drivers/input/keyboard/pxa27x_keypad.c
+++ b/drivers/input/keyboard/pxa27x_keypad.c
@@ -136,6 +136,9 @@ static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
set_bit(code, input_dev->keybit);
}
+ for (i = 0; i < pdata->direct_key_num; i++)
+ set_bit(pdata->direct_key_map[i], input_dev->keybit);
+
keypad->rotary_up_key[0] = pdata->rotary0_up_key;
keypad->rotary_up_key[1] = pdata->rotary1_up_key;
keypad->rotary_down_key[0] = pdata->rotary0_down_key;
@@ -143,17 +146,21 @@ static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
keypad->rotary_rel_code[0] = pdata->rotary0_rel_code;
keypad->rotary_rel_code[1] = pdata->rotary1_rel_code;
- if (pdata->rotary0_up_key && pdata->rotary0_down_key) {
- set_bit(pdata->rotary0_up_key, input_dev->keybit);
- set_bit(pdata->rotary0_down_key, input_dev->keybit);
- } else
- set_bit(pdata->rotary0_rel_code, input_dev->relbit);
-
- if (pdata->rotary1_up_key && pdata->rotary1_down_key) {
- set_bit(pdata->rotary1_up_key, input_dev->keybit);
- set_bit(pdata->rotary1_down_key, input_dev->keybit);
- } else
- set_bit(pdata->rotary1_rel_code, input_dev->relbit);
+ if (pdata->enable_rotary0) {
+ if (pdata->rotary0_up_key && pdata->rotary0_down_key) {
+ set_bit(pdata->rotary0_up_key, input_dev->keybit);
+ set_bit(pdata->rotary0_down_key, input_dev->keybit);
+ } else
+ set_bit(pdata->rotary0_rel_code, input_dev->relbit);
+ }
+
+ if (pdata->enable_rotary1) {
+ if (pdata->rotary1_up_key && pdata->rotary1_down_key) {
+ set_bit(pdata->rotary1_up_key, input_dev->keybit);
+ set_bit(pdata->rotary1_down_key, input_dev->keybit);
+ } else
+ set_bit(pdata->rotary1_rel_code, input_dev->relbit);
+ }
}
static inline unsigned int lookup_matrix_keycode(
@@ -484,8 +491,13 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
keypad->input_dev = input_dev;
input_set_drvdata(input_dev, keypad);
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
- BIT_MASK(EV_REL);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+ if ((keypad->pdata->enable_rotary0 &&
+ keypad->pdata->rotary0_rel_code) ||
+ (keypad->pdata->enable_rotary1 &&
+ keypad->pdata->rotary1_rel_code)) {
+ input_dev->evbit[0] |= BIT_MASK(EV_REL);
+ }
pxa27x_keypad_build_keycode(keypad);
platform_set_drvdata(pdev, keypad);
diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c
index 61e401bc9109..1aa37181c40f 100644
--- a/drivers/input/keyboard/spitzkbd.c
+++ b/drivers/input/keyboard/spitzkbd.c
@@ -494,5 +494,5 @@ module_exit(spitzkbd_exit);
MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
MODULE_DESCRIPTION("Spitz Keyboard Driver");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:spitz-keyboard");
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 3ad8bd9f7543..432699d61c58 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -15,7 +15,6 @@ if INPUT_MISC
config INPUT_PCSPKR
tristate "PC Speaker support"
depends on PCSPKR_PLATFORM
- depends on SND_PCSP=n
help
Say Y here if you want the standard PC Speaker to be used for
bells and whistles.
diff --git a/drivers/input/misc/apanel.c b/drivers/input/misc/apanel.c
index 9531d8c7444f..d82f7f727f7a 100644
--- a/drivers/input/misc/apanel.c
+++ b/drivers/input/misc/apanel.c
@@ -20,7 +20,6 @@
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/io.h>
-#include <linux/module.h>
#include <linux/input-polldev.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index 8dd3942f3022..ce6fdec19e14 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -589,6 +589,21 @@ static void atp_close(struct input_dev *input)
dev->open = 0;
}
+static int atp_handle_geyser(struct atp *dev)
+{
+ struct usb_device *udev = dev->udev;
+
+ if (!atp_is_fountain(dev)) {
+ /* switch to raw sensor mode */
+ if (atp_geyser_init(udev))
+ return -EIO;
+
+ printk(KERN_INFO "appletouch: Geyser mode initialized.\n");
+ }
+
+ return 0;
+}
+
static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id)
{
struct atp *dev;
@@ -633,14 +648,6 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
else
dev->datalen = 81;
- if (!atp_is_fountain(dev)) {
- /* switch to raw sensor mode */
- if (atp_geyser_init(udev))
- goto err_free_devs;
-
- printk(KERN_INFO "appletouch: Geyser mode initialized.\n");
- }
-
dev->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->urb)
goto err_free_devs;
@@ -654,6 +661,10 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
usb_rcvintpipe(udev, int_in_endpointAddr),
dev->data, dev->datalen, atp_complete, dev, 1);
+ error = atp_handle_geyser(dev);
+ if (error)
+ goto err_free_buffer;
+
usb_make_path(udev, dev->phys, sizeof(dev->phys));
strlcat(dev->phys, "/input0", sizeof(dev->phys));
@@ -744,6 +755,20 @@ static void atp_disconnect(struct usb_interface *iface)
printk(KERN_INFO "input: appletouch disconnected\n");
}
+static int atp_recover(struct atp *dev)
+{
+ int error;
+
+ error = atp_handle_geyser(dev);
+ if (error)
+ return error;
+
+ if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC))
+ return -EIO;
+
+ return 0;
+}
+
static int atp_suspend(struct usb_interface *iface, pm_message_t message)
{
struct atp *dev = usb_get_intfdata(iface);
@@ -764,12 +789,20 @@ static int atp_resume(struct usb_interface *iface)
return 0;
}
+static int atp_reset_resume(struct usb_interface *iface)
+{
+ struct atp *dev = usb_get_intfdata(iface);
+
+ return atp_recover(dev);
+}
+
static struct usb_driver atp_driver = {
.name = "appletouch",
.probe = atp_probe,
.disconnect = atp_disconnect,
.suspend = atp_suspend,
.resume = atp_resume,
+ .reset_resume = atp_reset_resume,
.id_table = atp_table,
};
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 5ece9f56babc..78eb7841174c 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -193,6 +193,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
},
},
{
+ .ident = "Fujitsu-Siemens Amilo Pro 2030",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "AMILO PRO V2030"),
+ },
+ },
+ {
/*
* No data is coming from the touchscreen unless KBC
* is in legacy mode.
@@ -331,6 +338,13 @@ static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = {
},
},
{
+ .ident = "Acer TravelMate 660",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"),
+ },
+ },
+ {
.ident = "Acer TravelMate 2490",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 65a74cfc187b..170f71ee5772 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -885,6 +885,20 @@ static long i8042_panic_blink(long count)
#undef DELAY
+#ifdef CONFIG_X86
+static void i8042_dritek_enable(void)
+{
+ char param = 0x90;
+ int error;
+
+ error = i8042_command(&param, 0x1059);
+ if (error)
+ printk(KERN_WARNING
+ "Failed to enable DRITEK extension: %d\n",
+ error);
+}
+#endif
+
#ifdef CONFIG_PM
/*
* Here we try to restore the original BIOS settings. We only want to
@@ -938,10 +952,20 @@ static int i8042_resume(struct platform_device *dev)
i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS;
i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT);
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
- printk(KERN_ERR "i8042: Can't write CTR to resume\n");
- return -EIO;
+ printk(KERN_WARNING "i8042: Can't write CTR to resume, retrying...\n");
+ msleep(50);
+ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+ printk(KERN_ERR "i8042: CTR write retry failed\n");
+ return -EIO;
+ }
}
+
+#ifdef CONFIG_X86
+ if (i8042_dritek)
+ i8042_dritek_enable();
+#endif
+
if (i8042_mux_present) {
if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports())
printk(KERN_WARNING
@@ -1160,6 +1184,11 @@ static int __devinit i8042_probe(struct platform_device *dev)
if (error)
return error;
+#ifdef CONFIG_X86
+ if (i8042_dritek)
+ i8042_dritek_enable();
+#endif
+
if (!i8042_noaux) {
error = i8042_setup_aux();
if (error && error != -ENODEV && error != -EBUSY)
@@ -1171,14 +1200,6 @@ static int __devinit i8042_probe(struct platform_device *dev)
if (error)
goto out_fail;
}
-#ifdef CONFIG_X86
- if (i8042_dritek) {
- char param = 0x90;
- error = i8042_command(&param, 0x1059);
- if (error)
- goto out_fail;
- }
-#endif
/*
* Ok, everything is ready, let's register all serio ports
*/
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index c5a8661a1baa..1e748e46d12e 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -830,7 +830,7 @@ static int gtco_probe(struct usb_interface *usbinterface,
struct gtco *gtco;
struct input_dev *input_dev;
struct hid_descriptor *hid_desc;
- char *report = NULL;
+ char *report;
int result = 0, retry;
int error;
struct usb_endpoint_descriptor *endpoint;
@@ -916,12 +916,16 @@ static int gtco_probe(struct usb_interface *usbinterface,
le16_to_cpu(hid_desc->wDescriptorLength),
5000); /* 5 secs */
- if (result == le16_to_cpu(hid_desc->wDescriptorLength))
+ dbg("usb_control_msg result: %d", result);
+ if (result == le16_to_cpu(hid_desc->wDescriptorLength)) {
+ parse_hid_report_descriptor(gtco, report, result);
break;
+ }
}
+ kfree(report);
+
/* If we didn't get the report, fail */
- dbg("usb_control_msg result: :%d", result);
if (result != le16_to_cpu(hid_desc->wDescriptorLength)) {
err("Failed to get HID Report Descriptor of size: %d",
hid_desc->wDescriptorLength);
@@ -929,12 +933,6 @@ static int gtco_probe(struct usb_interface *usbinterface,
goto err_free_urb;
}
- /* Now we parse the report */
- parse_hid_report_descriptor(gtco, report, result);
-
- /* Now we delete it */
- kfree(report);
-
/* Create a device file node */
usb_make_path(gtco->usbdev, gtco->usbpath, sizeof(gtco->usbpath));
strlcat(gtco->usbpath, "/input0", sizeof(gtco->usbpath));
@@ -988,7 +986,6 @@ static int gtco_probe(struct usb_interface *usbinterface,
usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE,
gtco->buffer, gtco->buf_dma);
err_free_devs:
- kfree(report);
input_free_device(input_dev);
kfree(gtco);
return error;
diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c
index 742242111bf1..1aca108b1031 100644
--- a/drivers/input/touchscreen/jornada720_ts.c
+++ b/drivers/input/touchscreen/jornada720_ts.c
@@ -24,7 +24,7 @@
MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
struct jornada_ts {
struct input_dev *dev;
diff --git a/drivers/input/touchscreen/wm9713.c b/drivers/input/touchscreen/wm9713.c
index 01278bd7e65c..838458792ea0 100644
--- a/drivers/input/touchscreen/wm9713.c
+++ b/drivers/input/touchscreen/wm9713.c
@@ -85,6 +85,15 @@ module_param(delay, int, 0);
MODULE_PARM_DESC(delay, "Set adc sample delay.");
/*
+ * Set five_wire = 1 to use a 5 wire touchscreen.
+ *
+ * NOTE: Five wire mode does not allow for readback of pressure.
+ */
+static int five_wire;
+module_param(five_wire, int, 0);
+MODULE_PARM_DESC(five_wire, "Set to '1' to use 5-wire touchscreen.");
+
+/*
* Set adc mask function.
*
* Sources of glitch noise, such as signals driving an LCD display, may feed
@@ -162,6 +171,19 @@ static void wm9713_phy_init(struct wm97xx *wm)
64000 / rpu);
}
+ /* Five wire panel? */
+ if (five_wire) {
+ dig3 |= WM9713_45W;
+ dev_info(wm->dev, "setting 5-wire touchscreen mode.");
+
+ if (pil) {
+ dev_warn(wm->dev,
+ "Pressure measurement not supported in 5 "
+ "wire mode, disabling\n");
+ pil = 0;
+ }
+ }
+
/* touchpanel pressure */
if (pil == 2) {
dig3 |= WM9712_PIL;
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
index e9c7ea46b6e3..cdc24ad314e0 100644
--- a/drivers/input/touchscreen/wm97xx-core.c
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -608,6 +608,17 @@ static int wm97xx_probe(struct device *dev)
goto alloc_err;
}
+ /* set up physical characteristics */
+ wm->codec->phy_init(wm);
+
+ /* load gpio cache */
+ wm->gpio[0] = wm97xx_reg_read(wm, AC97_GPIO_CFG);
+ wm->gpio[1] = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
+ wm->gpio[2] = wm97xx_reg_read(wm, AC97_GPIO_STICKY);
+ wm->gpio[3] = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP);
+ wm->gpio[4] = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
+ wm->gpio[5] = wm97xx_reg_read(wm, AC97_MISC_AFE);
+
wm->input_dev = input_allocate_device();
if (wm->input_dev == NULL) {
ret = -ENOMEM;
@@ -616,6 +627,7 @@ static int wm97xx_probe(struct device *dev)
/* set up touch configuration */
wm->input_dev->name = "wm97xx touchscreen";
+ wm->input_dev->phys = "wm97xx";
wm->input_dev->open = wm97xx_ts_input_open;
wm->input_dev->close = wm97xx_ts_input_close;
set_bit(EV_ABS, wm->input_dev->evbit);
@@ -634,17 +646,6 @@ static int wm97xx_probe(struct device *dev)
if (ret < 0)
goto dev_alloc_err;
- /* set up physical characteristics */
- wm->codec->phy_init(wm);
-
- /* load gpio cache */
- wm->gpio[0] = wm97xx_reg_read(wm, AC97_GPIO_CFG);
- wm->gpio[1] = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
- wm->gpio[2] = wm97xx_reg_read(wm, AC97_GPIO_STICKY);
- wm->gpio[3] = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP);
- wm->gpio[4] = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
- wm->gpio[5] = wm97xx_reg_read(wm, AC97_MISC_AFE);
-
/* register our battery device */
wm->battery_dev = platform_device_alloc("wm97xx-battery", -1);
if (!wm->battery_dev) {
@@ -801,7 +802,7 @@ void wm97xx_unregister_mach_ops(struct wm97xx *wm)
EXPORT_SYMBOL_GPL(wm97xx_unregister_mach_ops);
static struct device_driver wm97xx_driver = {
- .name = "ac97",
+ .name = "wm97xx-ts",
.bus = &ac97_bus_type,
.owner = THIS_MODULE,
.probe = wm97xx_probe,
diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c
index ebef4ce1b00c..29419a8d31dc 100644
--- a/drivers/isdn/capi/capiutil.c
+++ b/drivers/isdn/capi/capiutil.c
@@ -948,17 +948,17 @@ int __init cdebug_init(void)
{
g_cmsg= kmalloc(sizeof(_cmsg), GFP_KERNEL);
if (!g_cmsg)
- return ENOMEM;
+ return -ENOMEM;
g_debbuf = kmalloc(sizeof(_cdebbuf), GFP_KERNEL);
if (!g_debbuf) {
kfree(g_cmsg);
- return ENOMEM;
+ return -ENOMEM;
}
g_debbuf->buf = kmalloc(CDEBUG_GSIZE, GFP_KERNEL);
if (!g_debbuf->buf) {
kfree(g_cmsg);
kfree(g_debbuf);
- return ENOMEM;;
+ return -ENOMEM;;
}
g_debbuf->size = CDEBUG_GSIZE;
g_debbuf->buf[0] = 0;
diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
index 65c95019a9ae..fbbcb27fb681 100644
--- a/drivers/isdn/hardware/eicon/divasmain.c
+++ b/drivers/isdn/hardware/eicon/divasmain.c
@@ -808,7 +808,6 @@ static int DIVA_INIT_FUNCTION divas_init(void)
if (!create_divas_proc()) {
#ifdef MODULE
- remove_divas_proc();
divas_unregister_chrdev();
divasfunc_exit();
#endif
diff --git a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c
index fae895828a17..040827288ec9 100644
--- a/drivers/isdn/hardware/eicon/divasproc.c
+++ b/drivers/isdn/hardware/eicon/divasproc.c
@@ -125,8 +125,8 @@ static const struct file_operations divas_fops = {
int create_divas_proc(void)
{
- proc_create(divas_proc_name, S_IFREG | S_IRUGO, proc_net_eicon,
- &divas_fops);
+ divas_proc_entry = proc_create(divas_proc_name, S_IFREG | S_IRUGO,
+ proc_net_eicon, &divas_fops);
if (!divas_proc_entry)
return (0);
diff --git a/drivers/isdn/hysdn/Kconfig b/drivers/isdn/hysdn/Kconfig
index c6d8a7042988..c9e4231968ef 100644
--- a/drivers/isdn/hysdn/Kconfig
+++ b/drivers/isdn/hysdn/Kconfig
@@ -3,7 +3,7 @@
#
config HYSDN
tristate "Hypercope HYSDN cards (Champ, Ergo, Metro) support (module only)"
- depends on m && PROC_FS && PCI && BROKEN_ON_SMP
+ depends on m && PROC_FS && PCI
help
Say Y here if you have one of Hypercope's active PCI ISDN cards
Champ, Ergo and Metro. You will then get a module called hysdn.
diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c
index 6cdbad3a9926..3eb096f0ae1b 100644
--- a/drivers/isdn/hysdn/boardergo.c
+++ b/drivers/isdn/hysdn/boardergo.c
@@ -64,10 +64,11 @@ ergo_interrupt(int intno, void *dev_id)
} /* ergo_interrupt */
/******************************************************************************/
-/* ergo_irq_bh is the function called by the immediate kernel task list after */
-/* being activated with queue_task and no interrupts active. This task is the */
-/* only one handling data transfer from or to the card after booting. The task */
-/* may be queued from everywhere (interrupts included). */
+/* ergo_irq_bh will be called as part of the kernel clearing its shared work */
+/* queue sometime after a call to schedule_work has been made passing our */
+/* work_struct. This task is the only one handling data transfer from or to */
+/* the card after booting. The task may be queued from everywhere */
+/* (interrupts included). */
/******************************************************************************/
static void
ergo_irq_bh(struct work_struct *ugli_api)
@@ -90,7 +91,6 @@ ergo_irq_bh(struct work_struct *ugli_api)
card->hw_lock = 1; /* we now lock the hardware */
do {
- sti(); /* reenable other ints */
again = 0; /* assume loop not to be repeated */
if (!dpr->ToHyFlag) {
@@ -110,7 +110,6 @@ ergo_irq_bh(struct work_struct *ugli_api)
again = 1; /* restart loop */
}
} /* a message has arrived for us */
- cli(); /* no further ints */
if (again) {
dpr->ToHyInt = 1;
dpr->ToPcInt = 1; /* interrupt to E1 for all cards */
@@ -242,7 +241,6 @@ ergo_writebootimg(struct HYSDN_CARD *card, unsigned char *buf,
byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RUN); /* start E1 processor */
/* the interrupts are still masked */
- sti();
msleep_interruptible(20); /* Timeout 20ms */
if (((tDpramBootSpooler *) card->dpram)->Len != DPRAM_SPOOLER_DATA_SIZE) {
@@ -276,7 +274,6 @@ ergo_writebootseq(struct HYSDN_CARD *card, unsigned char *buf, int len)
dst = sp->Data; /* point to data in spool structure */
buflen = sp->Len; /* maximum len of spooled data */
wr_mirror = sp->WrPtr; /* only once read */
- sti();
/* try until all bytes written or error */
i = 0x1000; /* timeout value */
@@ -380,7 +377,6 @@ ergo_waitpofready(struct HYSDN_CARD *card)
#endif /* CONFIG_HYSDN_CAPI */
return (0); /* success */
} /* data has arrived */
- sti();
msleep_interruptible(50); /* Timeout 50ms */
} /* wait until timeout */
diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c
index d3999a8e9f88..53f6ad1235db 100644
--- a/drivers/isdn/hysdn/hycapi.c
+++ b/drivers/isdn/hysdn/hycapi.c
@@ -462,11 +462,11 @@ static int hycapi_read_proc(char *page, char **start, off_t off,
default: s = "???"; break;
}
len += sprintf(page+len, "%-16s %s\n", "type", s);
- if ((s = cinfo->version[VER_DRIVER]) != 0)
+ if ((s = cinfo->version[VER_DRIVER]) != NULL)
len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
- if ((s = cinfo->version[VER_CARDTYPE]) != 0)
+ if ((s = cinfo->version[VER_CARDTYPE]) != NULL)
len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
- if ((s = cinfo->version[VER_SERIAL]) != 0)
+ if ((s = cinfo->version[VER_SERIAL]) != NULL)
len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index 15906d005b05..484299b031f8 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -207,30 +207,17 @@ hysdn_conf_write(struct file *file, const char __user *buf, size_t count, loff_t
/* read conf file -> output card info data */
/*******************************************/
static ssize_t
-hysdn_conf_read(struct file *file, char __user *buf, size_t count, loff_t * off)
+hysdn_conf_read(struct file *file, char __user *buf, size_t count, loff_t *off)
{
char *cp;
- int i;
- if (file->f_mode & FMODE_READ) {
- if (!(cp = file->private_data))
- return (-EFAULT); /* should never happen */
- i = strlen(cp); /* get total string length */
- if (*off < i) {
- /* still bytes to transfer */
- cp += *off; /* point to desired data offset */
- i -= *off; /* remaining length */
- if (i > count)
- i = count; /* limit length to transfer */
- if (copy_to_user(buf, cp, i))
- return (-EFAULT); /* copy error */
- *off += i; /* adjust offset */
- } else
- return (0);
- } else
- return (-EPERM); /* no permission to read */
-
- return (i);
+ if (!(file->f_mode & FMODE_READ))
+ return -EPERM; /* no permission to read */
+
+ if (!(cp = file->private_data))
+ return -EFAULT; /* should never happen */
+
+ return simple_read_from_buffer(buf, count, off, cp, strlen(cp));
} /* hysdn_conf_read */
/******************/
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 5158c606ff5b..7188c59a76ff 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -1978,8 +1978,10 @@ isdn_writebuf_stub(int drvidx, int chan, const u_char __user * buf, int len)
if (!skb)
return -ENOMEM;
skb_reserve(skb, hl);
- if (copy_from_user(skb_put(skb, len), buf, len))
+ if (copy_from_user(skb_put(skb, len), buf, len)) {
+ dev_kfree_skb(skb);
return -EFAULT;
+ }
ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb);
if (ret <= 0)
dev_kfree_skb(skb);
diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c
index 7817d2244921..1081091bbfaf 100644
--- a/drivers/isdn/sc/ioctl.c
+++ b/drivers/isdn/sc/ioctl.c
@@ -226,6 +226,7 @@ int sc_ioctl(int card, scs_ioctl *data)
*/
if (copy_from_user(spid, data->dataptr, SCIOC_SPIDSIZE)) {
kfree(rcvmsg);
+ kfree(spid);
return -EFAULT;
}
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index b3c54be74556..559a40861c39 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -103,13 +103,11 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
{
int rc;
- led_cdev->dev = device_create(leds_class, parent, 0, "%s",
- led_cdev->name);
+ led_cdev->dev = device_create_drvdata(leds_class, parent, 0, led_cdev,
+ "%s", led_cdev->name);
if (IS_ERR(led_cdev->dev))
return PTR_ERR(led_cdev->dev);
- dev_set_drvdata(led_cdev->dev, led_cdev);
-
/* register the attributes */
rc = device_create_file(led_cdev->dev, &dev_attr_brightness);
if (rc)
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c
index 8080249957af..1a8de57289eb 100644
--- a/drivers/lguest/lguest_device.c
+++ b/drivers/lguest/lguest_device.c
@@ -20,14 +20,11 @@
/* The pointer to our (page) of device descriptions. */
static void *lguest_devices;
-/* Unique numbering for lguest devices. */
-static unsigned int dev_index;
-
/* For Guests, device memory can be used as normal memory, so we cast away the
* __iomem to quieten sparse. */
static inline void *lguest_map(unsigned long phys_addr, unsigned long pages)
{
- return (__force void *)ioremap(phys_addr, PAGE_SIZE*pages);
+ return (__force void *)ioremap_cache(phys_addr, PAGE_SIZE*pages);
}
static inline void lguest_unmap(void *addr)
@@ -325,8 +322,10 @@ static struct device lguest_root = {
* As Andrew Tridgell says, "Untested code is buggy code".
*
* It's worth reading this carefully: we start with a pointer to the new device
- * descriptor in the "lguest_devices" page. */
-static void add_lguest_device(struct lguest_device_desc *d)
+ * descriptor in the "lguest_devices" page, and the offset into the device
+ * descriptor page so we can uniquely identify it if things go badly wrong. */
+static void add_lguest_device(struct lguest_device_desc *d,
+ unsigned int offset)
{
struct lguest_device *ldev;
@@ -334,18 +333,14 @@ static void add_lguest_device(struct lguest_device_desc *d)
* it. */
ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
if (!ldev) {
- printk(KERN_EMERG "Cannot allocate lguest dev %u\n",
- dev_index++);
+ printk(KERN_EMERG "Cannot allocate lguest dev %u type %u\n",
+ offset, d->type);
return;
}
/* This devices' parent is the lguest/ dir. */
ldev->vdev.dev.parent = &lguest_root;
/* We have a unique device index thanks to the dev_index counter. */
- ldev->vdev.index = dev_index++;
- /* The device type comes straight from the descriptor. There's also a
- * device vendor field in the virtio_device struct, which we leave as
- * 0. */
ldev->vdev.id.device = d->type;
/* We have a simple set of routines for querying the device's
* configuration information and setting its status. */
@@ -357,8 +352,8 @@ static void add_lguest_device(struct lguest_device_desc *d)
* virtio_device and calls device_register(). This makes the bus
* infrastructure look for a matching driver. */
if (register_virtio_device(&ldev->vdev) != 0) {
- printk(KERN_ERR "Failed to register lguest device %u\n",
- ldev->vdev.index);
+ printk(KERN_ERR "Failed to register lguest dev %u type %u\n",
+ offset, d->type);
kfree(ldev);
}
}
@@ -379,7 +374,7 @@ static void scan_devices(void)
break;
printk("Device at %i has size %u\n", i, desc_size(d));
- add_lguest_device(d);
+ add_lguest_device(d, i);
}
}
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c
index 5126d5d9ea0e..2e554a4ab337 100644
--- a/drivers/lguest/x86/core.c
+++ b/drivers/lguest/x86/core.c
@@ -176,7 +176,7 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
* we set it now, so we can trap and pass that trap to the Guest if it
* uses the FPU. */
if (cpu->ts)
- lguest_set_ts();
+ unlazy_fpu(current);
/* SYSENTER is an optimized way of doing system calls. We can't allow
* it because it always jumps to privilege level 0. A normal Guest
@@ -196,6 +196,10 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
* trap made the switcher code come back, and an error code which some
* traps set. */
+ /* Restore SYSENTER if it's supposed to be on. */
+ if (boot_cpu_has(X86_FEATURE_SEP))
+ wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
+
/* If the Guest page faulted, then the cr2 register will tell us the
* bad virtual address. We have to grab this now, because once we
* re-enable interrupts an interrupt could fault and thus overwrite
@@ -203,13 +207,12 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
if (cpu->regs->trapnum == 14)
cpu->arch.last_pagefault = read_cr2();
/* Similarly, if we took a trap because the Guest used the FPU,
- * we have to restore the FPU it expects to see. */
+ * we have to restore the FPU it expects to see.
+ * math_state_restore() may sleep and we may even move off to
+ * a different CPU. So all the critical stuff should be done
+ * before this. */
else if (cpu->regs->trapnum == 7)
math_state_restore();
-
- /* Restore SYSENTER if it's supposed to be on. */
- if (boot_cpu_has(X86_FEATURE_SEP))
- wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
}
/*H:130 Now we've examined the hypercall code; our Guest can make requests.
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 82add26cc665..818aba368541 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -84,7 +84,7 @@ struct media_bay_info {
int cd_irq;
int cd_retry;
#endif
-#if defined(CONFIG_BLK_DEV_IDE_PMAC) || defined(CONFIG_MAC_FLOPPY)
+#if defined(CONFIG_BLK_DEV_IDE_PMAC)
int cd_index;
#endif
};
@@ -417,6 +417,7 @@ static void poll_media_bay(struct media_bay_info* bay)
}
}
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
int check_media_bay(struct device_node *which_bay, int what)
{
int i;
@@ -432,7 +433,6 @@ int check_media_bay(struct device_node *which_bay, int what)
}
EXPORT_SYMBOL(check_media_bay);
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
int check_media_bay_by_base(unsigned long base, int what)
{
int i;
@@ -556,7 +556,8 @@ static void media_bay_step(int i)
printk("mediabay %d, registering IDE...\n", i);
pmu_suspend();
ide_port_scan(bay->cd_port);
- bay->cd_index = bay->cd_port->index;
+ if (bay->cd_port->present)
+ bay->cd_index = bay->cd_port->index;
pmu_resume();
}
if (bay->cd_index == -1) {
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index b82fcd210bf3..32cb0298f88e 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -484,12 +484,15 @@ int __init smu_init (void)
if (smu_cmdbuf_abs == 0) {
printk(KERN_ERR "SMU: Command buffer not allocated !\n");
+ of_node_put(np);
return -EINVAL;
}
smu = alloc_bootmem(sizeof(struct smu_device));
- if (smu == NULL)
+ if (smu == NULL) {
+ of_node_put(np);
return -ENOMEM;
+ }
memset(smu, 0, sizeof(*smu));
spin_lock_init(&smu->lock);
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index 54f4942a2968..5366dc93fb38 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -562,18 +562,24 @@ thermostat_init(void)
therm_type = ADT7460;
else if (of_device_is_compatible(np, "adt7467"))
therm_type = ADT7467;
- else
+ else {
+ of_node_put(np);
return -ENODEV;
+ }
prop = of_get_property(np, "hwsensor-params-version", NULL);
printk(KERN_INFO "adt746x: version %d (%ssupported)\n", *prop,
(*prop == 1)?"":"un");
- if (*prop != 1)
+ if (*prop != 1) {
+ of_node_put(np);
return -ENODEV;
+ }
prop = of_get_property(np, "reg", NULL);
- if (!prop)
+ if (!prop) {
+ of_node_put(np);
return -ENODEV;
+ }
/* look for bus either by path or using "reg" */
if (strstr(np->full_name, "/i2c-bus@") != NULL) {
@@ -610,6 +616,7 @@ thermostat_init(void)
if (of_dev == NULL) {
printk(KERN_ERR "Can't register temperatures device !\n");
+ of_node_put(np);
return -ENODEV;
}
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index c14dacdacfac..b26927ce889c 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -203,17 +203,6 @@ static void bitmap_checkfree(struct bitmap *bitmap, unsigned long page)
* bitmap file handling - read and write the bitmap file and its superblock
*/
-/* copy the pathname of a file to a buffer */
-char *file_path(struct file *file, char *buf, int count)
-{
- if (!buf)
- return NULL;
-
- buf = d_path(&file->f_path, buf, count);
-
- return IS_ERR(buf) ? NULL : buf;
-}
-
/*
* basic page I/O operations
*/
@@ -721,11 +710,13 @@ static void bitmap_file_kick(struct bitmap *bitmap)
if (bitmap->file) {
path = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (path)
- ptr = file_path(bitmap->file, path, PAGE_SIZE);
+ ptr = d_path(&bitmap->file->f_path, path,
+ PAGE_SIZE);
+
printk(KERN_ALERT
"%s: kicking failed bitmap file %s from array!\n",
- bmname(bitmap), ptr ? ptr : "");
+ bmname(bitmap), IS_ERR(ptr) ? "" : ptr);
kfree(path);
} else
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 835def11419d..ab6a61db63ce 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -432,6 +432,7 @@ static int crypt_convert(struct crypt_config *cc,
case 0:
atomic_dec(&ctx->pending);
ctx->sector++;
+ cond_resched();
continue;
/* error */
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 83eb78b00137..2580ac1b9b0f 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -74,6 +74,8 @@ static DEFINE_SPINLOCK(pers_lock);
static void md_print_devices(void);
+static DECLARE_WAIT_QUEUE_HEAD(resync_wait);
+
#define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); }
/*
@@ -274,6 +276,7 @@ static mddev_t * mddev_find(dev_t unit)
atomic_set(&new->active, 1);
spin_lock_init(&new->write_lock);
init_waitqueue_head(&new->sb_wait);
+ init_waitqueue_head(&new->recovery_wait);
new->reshape_position = MaxSector;
new->resync_max = MaxSector;
new->level = LEVEL_NONE;
@@ -3013,6 +3016,36 @@ degraded_show(mddev_t *mddev, char *page)
static struct md_sysfs_entry md_degraded = __ATTR_RO(degraded);
static ssize_t
+sync_force_parallel_show(mddev_t *mddev, char *page)
+{
+ return sprintf(page, "%d\n", mddev->parallel_resync);
+}
+
+static ssize_t
+sync_force_parallel_store(mddev_t *mddev, const char *buf, size_t len)
+{
+ long n;
+
+ if (strict_strtol(buf, 10, &n))
+ return -EINVAL;
+
+ if (n != 0 && n != 1)
+ return -EINVAL;
+
+ mddev->parallel_resync = n;
+
+ if (mddev->sync_thread)
+ wake_up(&resync_wait);
+
+ return len;
+}
+
+/* force parallel resync, even with shared block devices */
+static struct md_sysfs_entry md_sync_force_parallel =
+__ATTR(sync_force_parallel, S_IRUGO|S_IWUSR,
+ sync_force_parallel_show, sync_force_parallel_store);
+
+static ssize_t
sync_speed_show(mddev_t *mddev, char *page)
{
unsigned long resync, dt, db;
@@ -3187,6 +3220,7 @@ static struct attribute *md_redundancy_attrs[] = {
&md_sync_min.attr,
&md_sync_max.attr,
&md_sync_speed.attr,
+ &md_sync_force_parallel.attr,
&md_sync_completed.attr,
&md_max_sync.attr,
&md_suspend_lo.attr,
@@ -3691,6 +3725,8 @@ static int do_md_stop(mddev_t * mddev, int mode)
module_put(mddev->pers->owner);
mddev->pers = NULL;
+ /* tell userspace to handle 'inactive' */
+ sysfs_notify(&mddev->kobj, NULL, "array_state");
set_capacity(disk, 0);
mddev->changed = 1;
@@ -3861,8 +3897,10 @@ static void autorun_devices(int part)
md_probe(dev, NULL, NULL);
mddev = mddev_find(dev);
- if (!mddev) {
- printk(KERN_ERR
+ if (!mddev || !mddev->gendisk) {
+ if (mddev)
+ mddev_put(mddev);
+ printk(KERN_ERR
"md: cannot allocate memory for md drive.\n");
break;
}
@@ -3987,8 +4025,8 @@ static int get_bitmap_file(mddev_t * mddev, void __user * arg)
if (!buf)
goto out;
- ptr = file_path(mddev->bitmap->file, buf, sizeof(file->pathname));
- if (!ptr)
+ ptr = d_path(&mddev->bitmap->file->f_path, buf, sizeof(file->pathname));
+ if (IS_ERR(ptr))
goto out;
strcpy(file->pathname, ptr);
@@ -5399,7 +5437,7 @@ void md_done_sync(mddev_t *mddev, int blocks, int ok)
atomic_sub(blocks, &mddev->recovery_active);
wake_up(&mddev->recovery_wait);
if (!ok) {
- set_bit(MD_RECOVERY_ERR, &mddev->recovery);
+ set_bit(MD_RECOVERY_INTR, &mddev->recovery);
md_wakeup_thread(mddev->thread);
// stop recovery, signal do_sync ....
}
@@ -5435,8 +5473,11 @@ void md_write_start(mddev_t *mddev, struct bio *bi)
md_wakeup_thread(mddev->thread);
}
spin_unlock_irq(&mddev->write_lock);
+ sysfs_notify(&mddev->kobj, NULL, "array_state");
}
- wait_event(mddev->sb_wait, mddev->flags==0);
+ wait_event(mddev->sb_wait,
+ !test_bit(MD_CHANGE_CLEAN, &mddev->flags) &&
+ !test_bit(MD_CHANGE_PENDING, &mddev->flags));
}
void md_write_end(mddev_t *mddev)
@@ -5471,13 +5512,17 @@ void md_allow_write(mddev_t *mddev)
mddev->safemode = 1;
spin_unlock_irq(&mddev->write_lock);
md_update_sb(mddev, 0);
+
+ sysfs_notify(&mddev->kobj, NULL, "array_state");
+ /* wait for the dirty state to be recorded in the metadata */
+ wait_event(mddev->sb_wait,
+ !test_bit(MD_CHANGE_CLEAN, &mddev->flags) &&
+ !test_bit(MD_CHANGE_PENDING, &mddev->flags));
} else
spin_unlock_irq(&mddev->write_lock);
}
EXPORT_SYMBOL_GPL(md_allow_write);
-static DECLARE_WAIT_QUEUE_HEAD(resync_wait);
-
#define SYNC_MARKS 10
#define SYNC_MARK_STEP (3*HZ)
void md_do_sync(mddev_t *mddev)
@@ -5541,8 +5586,9 @@ void md_do_sync(mddev_t *mddev)
for_each_mddev(mddev2, tmp) {
if (mddev2 == mddev)
continue;
- if (mddev2->curr_resync &&
- match_mddev_units(mddev,mddev2)) {
+ if (!mddev->parallel_resync
+ && mddev2->curr_resync
+ && match_mddev_units(mddev, mddev2)) {
DEFINE_WAIT(wq);
if (mddev < mddev2 && mddev->curr_resync == 2) {
/* arbitrarily yield */
@@ -5622,7 +5668,6 @@ void md_do_sync(mddev_t *mddev)
window/2,(unsigned long long) max_sectors/2);
atomic_set(&mddev->recovery_active, 0);
- init_waitqueue_head(&mddev->recovery_wait);
last_check = 0;
if (j>2) {
@@ -5647,7 +5692,7 @@ void md_do_sync(mddev_t *mddev)
sectors = mddev->pers->sync_request(mddev, j, &skipped,
currspeed < speed_min(mddev));
if (sectors == 0) {
- set_bit(MD_RECOVERY_ERR, &mddev->recovery);
+ set_bit(MD_RECOVERY_INTR, &mddev->recovery);
goto out;
}
@@ -5670,8 +5715,7 @@ void md_do_sync(mddev_t *mddev)
last_check = io_sectors;
- if (test_bit(MD_RECOVERY_INTR, &mddev->recovery) ||
- test_bit(MD_RECOVERY_ERR, &mddev->recovery))
+ if (test_bit(MD_RECOVERY_INTR, &mddev->recovery))
break;
repeat:
@@ -5725,8 +5769,7 @@ void md_do_sync(mddev_t *mddev)
/* tell personality that we are finished */
mddev->pers->sync_request(mddev, max_sectors, &skipped, 1);
- if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) &&
- !test_bit(MD_RECOVERY_CHECK, &mddev->recovery) &&
+ if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery) &&
mddev->curr_resync > 2) {
if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
@@ -5795,7 +5838,10 @@ static int remove_and_add_spares(mddev_t *mddev)
}
if (mddev->degraded) {
- rdev_for_each(rdev, rtmp, mddev)
+ rdev_for_each(rdev, rtmp, mddev) {
+ if (rdev->raid_disk >= 0 &&
+ !test_bit(In_sync, &rdev->flags))
+ spares++;
if (rdev->raid_disk < 0
&& !test_bit(Faulty, &rdev->flags)) {
rdev->recovery_offset = 0;
@@ -5813,6 +5859,7 @@ static int remove_and_add_spares(mddev_t *mddev)
} else
break;
}
+ }
}
return spares;
}
@@ -5826,7 +5873,7 @@ static int remove_and_add_spares(mddev_t *mddev)
* to do that as needed.
* When it is determined that resync is needed, we set MD_RECOVERY_RUNNING in
* "->recovery" and create a thread at ->sync_thread.
- * When the thread finishes it sets MD_RECOVERY_DONE (and might set MD_RECOVERY_ERR)
+ * When the thread finishes it sets MD_RECOVERY_DONE
* and wakeups up this thread which will reap the thread and finish up.
* This thread also removes any faulty devices (with nr_pending == 0).
*
@@ -5901,8 +5948,7 @@ void md_check_recovery(mddev_t *mddev)
/* resync has finished, collect result */
md_unregister_thread(mddev->sync_thread);
mddev->sync_thread = NULL;
- if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) &&
- !test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
+ if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
/* success...*/
/* activate any spares */
mddev->pers->spare_active(mddev);
@@ -5926,7 +5972,6 @@ void md_check_recovery(mddev_t *mddev)
* might be left set
*/
clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
- clear_bit(MD_RECOVERY_ERR, &mddev->recovery);
clear_bit(MD_RECOVERY_INTR, &mddev->recovery);
clear_bit(MD_RECOVERY_DONE, &mddev->recovery);
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 4f4d1f383842..e968116e0de9 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -327,7 +327,8 @@ static int multipath_remove_disk(mddev_t *mddev, int number)
if (rdev) {
if (test_bit(In_sync, &rdev->flags) ||
atomic_read(&rdev->nr_pending)) {
- printk(KERN_ERR "hot-remove-disk, slot %d is identified" " but is still operational!\n", number);
+ printk(KERN_ERR "hot-remove-disk, slot %d is identified"
+ " but is still operational!\n", number);
err = -EBUSY;
goto abort;
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index ac409b7d83f5..c610b947218a 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -773,7 +773,7 @@ static int make_request(struct request_queue *q, struct bio * bio)
r1bio_t *r1_bio;
struct bio *read_bio;
int i, targets = 0, disks;
- struct bitmap *bitmap = mddev->bitmap;
+ struct bitmap *bitmap;
unsigned long flags;
struct bio_list bl;
struct page **behind_pages = NULL;
@@ -802,6 +802,8 @@ static int make_request(struct request_queue *q, struct bio * bio)
wait_barrier(conf);
+ bitmap = mddev->bitmap;
+
disk_stat_inc(mddev->gendisk, ios[rw]);
disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bio));
@@ -1025,7 +1027,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
/*
* if recovery is running, make sure it aborts.
*/
- set_bit(MD_RECOVERY_ERR, &mddev->recovery);
+ set_bit(MD_RECOVERY_INTR, &mddev->recovery);
} else
set_bit(Faulty, &rdev->flags);
set_bit(MD_CHANGE_DEVS, &mddev->flags);
@@ -1146,6 +1148,14 @@ static int raid1_remove_disk(mddev_t *mddev, int number)
err = -EBUSY;
goto abort;
}
+ /* Only remove non-faulty devices is recovery
+ * is not possible.
+ */
+ if (!test_bit(Faulty, &rdev->flags) &&
+ mddev->degraded < conf->raid_disks) {
+ err = -EBUSY;
+ goto abort;
+ }
p->rdev = NULL;
synchronize_rcu();
if (atomic_read(&rdev->nr_pending)) {
@@ -1282,6 +1292,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
rdev_dec_pending(conf->mirrors[i].rdev, mddev);
} else {
/* fixup the bio for reuse */
+ int size;
sbio->bi_vcnt = vcnt;
sbio->bi_size = r1_bio->sectors << 9;
sbio->bi_idx = 0;
@@ -1295,10 +1306,20 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
sbio->bi_sector = r1_bio->sector +
conf->mirrors[i].rdev->data_offset;
sbio->bi_bdev = conf->mirrors[i].rdev->bdev;
- for (j = 0; j < vcnt ; j++)
- memcpy(page_address(sbio->bi_io_vec[j].bv_page),
+ size = sbio->bi_size;
+ for (j = 0; j < vcnt ; j++) {
+ struct bio_vec *bi;
+ bi = &sbio->bi_io_vec[j];
+ bi->bv_offset = 0;
+ if (size > PAGE_SIZE)
+ bi->bv_len = PAGE_SIZE;
+ else
+ bi->bv_len = size;
+ size -= PAGE_SIZE;
+ memcpy(page_address(bi->bv_page),
page_address(pbio->bi_io_vec[j].bv_page),
PAGE_SIZE);
+ }
}
}
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 8536ede1e712..a71277b640ab 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1020,7 +1020,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
/*
* if recovery is running, make sure it aborts.
*/
- set_bit(MD_RECOVERY_ERR, &mddev->recovery);
+ set_bit(MD_RECOVERY_INTR, &mddev->recovery);
}
set_bit(Faulty, &rdev->flags);
set_bit(MD_CHANGE_DEVS, &mddev->flags);
@@ -1171,6 +1171,14 @@ static int raid10_remove_disk(mddev_t *mddev, int number)
err = -EBUSY;
goto abort;
}
+ /* Only remove faulty devices in recovery
+ * is not possible.
+ */
+ if (!test_bit(Faulty, &rdev->flags) &&
+ enough(conf)) {
+ err = -EBUSY;
+ goto abort;
+ }
p->rdev = NULL;
synchronize_rcu();
if (atomic_read(&rdev->nr_pending)) {
@@ -1237,6 +1245,7 @@ static void end_sync_write(struct bio *bio, int error)
if (!uptodate)
md_error(mddev, conf->mirrors[d].rdev);
+
update_head_pos(i, r10_bio);
while (atomic_dec_and_test(&r10_bio->remaining)) {
@@ -1844,7 +1853,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
if (rb2)
atomic_dec(&rb2->remaining);
r10_bio = rb2;
- if (!test_and_set_bit(MD_RECOVERY_ERR, &mddev->recovery))
+ if (!test_and_set_bit(MD_RECOVERY_INTR,
+ &mddev->recovery))
printk(KERN_INFO "raid10: %s: insufficient working devices for recovery.\n",
mdname(mddev));
break;
@@ -2127,6 +2137,8 @@ static int run(mddev_t *mddev)
!test_bit(In_sync, &disk->rdev->flags)) {
disk->head_position = 0;
mddev->degraded++;
+ if (disk->rdev)
+ conf->fullsync = 1;
}
}
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 93fde48c0f42..3b27df52456b 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -94,6 +94,8 @@
#define __inline__
#endif
+#define printk_rl(args...) ((void) (printk_ratelimit() && printk(args)))
+
#if !RAID6_USE_EMPTY_ZERO_PAGE
/* In .bss so it's zeroed */
const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256)));
@@ -1143,10 +1145,12 @@ static void raid5_end_read_request(struct bio * bi, int error)
set_bit(R5_UPTODATE, &sh->dev[i].flags);
if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
rdev = conf->disks[i].rdev;
- printk(KERN_INFO "raid5:%s: read error corrected (%lu sectors at %llu on %s)\n",
- mdname(conf->mddev), STRIPE_SECTORS,
- (unsigned long long)(sh->sector + rdev->data_offset),
- bdevname(rdev->bdev, b));
+ printk_rl(KERN_INFO "raid5:%s: read error corrected"
+ " (%lu sectors at %llu on %s)\n",
+ mdname(conf->mddev), STRIPE_SECTORS,
+ (unsigned long long)(sh->sector
+ + rdev->data_offset),
+ bdevname(rdev->bdev, b));
clear_bit(R5_ReadError, &sh->dev[i].flags);
clear_bit(R5_ReWrite, &sh->dev[i].flags);
}
@@ -1160,16 +1164,22 @@ static void raid5_end_read_request(struct bio * bi, int error)
clear_bit(R5_UPTODATE, &sh->dev[i].flags);
atomic_inc(&rdev->read_errors);
if (conf->mddev->degraded)
- printk(KERN_WARNING "raid5:%s: read error not correctable (sector %llu on %s).\n",
- mdname(conf->mddev),
- (unsigned long long)(sh->sector + rdev->data_offset),
- bdn);
+ printk_rl(KERN_WARNING
+ "raid5:%s: read error not correctable "
+ "(sector %llu on %s).\n",
+ mdname(conf->mddev),
+ (unsigned long long)(sh->sector
+ + rdev->data_offset),
+ bdn);
else if (test_bit(R5_ReWrite, &sh->dev[i].flags))
/* Oh, no!!! */
- printk(KERN_WARNING "raid5:%s: read error NOT corrected!! (sector %llu on %s).\n",
- mdname(conf->mddev),
- (unsigned long long)(sh->sector + rdev->data_offset),
- bdn);
+ printk_rl(KERN_WARNING
+ "raid5:%s: read error NOT corrected!! "
+ "(sector %llu on %s).\n",
+ mdname(conf->mddev),
+ (unsigned long long)(sh->sector
+ + rdev->data_offset),
+ bdn);
else if (atomic_read(&rdev->read_errors)
> conf->max_nr_stripes)
printk(KERN_WARNING
@@ -1258,7 +1268,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
/*
* if recovery was running, make sure it aborts.
*/
- set_bit(MD_RECOVERY_ERR, &mddev->recovery);
+ set_bit(MD_RECOVERY_INTR, &mddev->recovery);
}
set_bit(Faulty, &rdev->flags);
printk (KERN_ALERT
@@ -1992,6 +2002,7 @@ static int __handle_issuing_new_read_requests5(struct stripe_head *sh,
* have quiesced.
*/
if ((s->uptodate == disks - 1) &&
+ (s->failed && disk_idx == s->failed_num) &&
!test_bit(STRIPE_OP_CHECK, &sh->ops.pending)) {
set_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending);
set_bit(R5_Wantcompute, &dev->flags);
@@ -2006,12 +2017,7 @@ static int __handle_issuing_new_read_requests5(struct stripe_head *sh,
*/
s->uptodate++;
return 0; /* uptodate + compute == disks */
- } else if ((s->uptodate < disks - 1) &&
- test_bit(R5_Insync, &dev->flags)) {
- /* Note: we hold off compute operations while checks are
- * in flight, but we still prefer 'compute' over 'read'
- * hence we only read if (uptodate < * disks-1)
- */
+ } else if (test_bit(R5_Insync, &dev->flags)) {
set_bit(R5_LOCKED, &dev->flags);
set_bit(R5_Wantread, &dev->flags);
if (!test_and_set_bit(STRIPE_OP_IO, &sh->ops.pending))
@@ -2077,7 +2083,9 @@ static void handle_issuing_new_read_requests6(struct stripe_head *sh,
/* we would like to get this block, possibly
* by computing it, but we might not be able to
*/
- if (s->uptodate == disks-1) {
+ if ((s->uptodate == disks - 1) &&
+ (s->failed && (i == r6s->failed_num[0] ||
+ i == r6s->failed_num[1]))) {
pr_debug("Computing stripe %llu block %d\n",
(unsigned long long)sh->sector, i);
compute_block_1(sh, i, 0);
@@ -2635,6 +2643,7 @@ static void handle_stripe5(struct stripe_head *sh)
struct r5dev *dev;
unsigned long pending = 0;
mdk_rdev_t *blocked_rdev = NULL;
+ int prexor;
memset(&s, 0, sizeof(s));
pr_debug("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d "
@@ -2764,9 +2773,11 @@ static void handle_stripe5(struct stripe_head *sh)
/* leave prexor set until postxor is done, allows us to distinguish
* a rmw from a rcw during biodrain
*/
+ prexor = 0;
if (test_bit(STRIPE_OP_PREXOR, &sh->ops.complete) &&
test_bit(STRIPE_OP_POSTXOR, &sh->ops.complete)) {
+ prexor = 1;
clear_bit(STRIPE_OP_PREXOR, &sh->ops.complete);
clear_bit(STRIPE_OP_PREXOR, &sh->ops.ack);
clear_bit(STRIPE_OP_PREXOR, &sh->ops.pending);
@@ -2800,6 +2811,8 @@ static void handle_stripe5(struct stripe_head *sh)
if (!test_and_set_bit(
STRIPE_OP_IO, &sh->ops.pending))
sh->ops.count++;
+ if (prexor)
+ continue;
if (!test_bit(R5_Insync, &dev->flags) ||
(i == sh->pd_idx && s.failed == 0))
set_bit(STRIPE_INSYNC, &sh->state);
@@ -2880,6 +2893,8 @@ static void handle_stripe5(struct stripe_head *sh)
for (i = conf->raid_disks; i--; ) {
set_bit(R5_Wantwrite, &sh->dev[i].flags);
+ set_bit(R5_LOCKED, &dev->flags);
+ s.locked++;
if (!test_and_set_bit(STRIPE_OP_IO, &sh->ops.pending))
sh->ops.count++;
}
@@ -2893,6 +2908,7 @@ static void handle_stripe5(struct stripe_head *sh)
conf->raid_disks);
s.locked += handle_write_operations5(sh, 1, 1);
} else if (s.expanded &&
+ s.locked == 0 &&
!test_bit(STRIPE_OP_POSTXOR, &sh->ops.pending)) {
clear_bit(STRIPE_EXPAND_READY, &sh->state);
atomic_dec(&conf->reshape_stripes);
@@ -4287,7 +4303,9 @@ static int run(mddev_t *mddev)
" disk %d\n", bdevname(rdev->bdev,b),
raid_disk);
working_disks++;
- }
+ } else
+ /* Cannot rely on bitmap to complete recovery */
+ conf->fullsync = 1;
}
/*
@@ -4564,6 +4582,14 @@ static int raid5_remove_disk(mddev_t *mddev, int number)
err = -EBUSY;
goto abort;
}
+ /* Only remove non-faulty devices if recovery
+ * isn't possible.
+ */
+ if (!test_bit(Faulty, &rdev->flags) &&
+ mddev->degraded <= conf->max_degraded) {
+ err = -EBUSY;
+ goto abort;
+ }
p->rdev = NULL;
synchronize_rcu();
if (atomic_read(&rdev->nr_pending)) {
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index cc11c4c0e7e7..09a829d8a7e7 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -2,12 +2,7 @@
# Makefile for the kernel multimedia device drivers.
#
-obj-y := common/
-
-obj-$(CONFIG_VIDEO_MEDIA) += common/
-
-# Since hybrid devices are here, should be compiled if DVB and/or V4L
-obj-$(CONFIG_VIDEO_MEDIA) += video/
+obj-y += common/ video/
obj-$(CONFIG_VIDEO_DEV) += radio/
obj-$(CONFIG_DVB_CORE) += dvb/
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index a3485817e46c..8fa91f846d59 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -2201,3 +2201,41 @@ IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE] = {
[0x25] = KEY_POWER, /* power */
};
EXPORT_SYMBOL_GPL(ir_codes_powercolor_real_angel);
+
+IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE] = {
+ [0x20] = KEY_LIST,
+ [0x00] = KEY_POWER,
+ [0x28] = KEY_1,
+ [0x18] = KEY_2,
+ [0x38] = KEY_3,
+ [0x24] = KEY_4,
+ [0x14] = KEY_5,
+ [0x34] = KEY_6,
+ [0x2c] = KEY_7,
+ [0x1c] = KEY_8,
+ [0x3c] = KEY_9,
+ [0x12] = KEY_SUBTITLE,
+ [0x22] = KEY_0,
+ [0x32] = KEY_REWIND,
+ [0x3a] = KEY_SHUFFLE,
+ [0x02] = KEY_PRINT,
+ [0x11] = KEY_CHANNELDOWN,
+ [0x31] = KEY_CHANNELUP,
+ [0x0c] = KEY_ZOOM,
+ [0x1e] = KEY_VOLUMEDOWN,
+ [0x3e] = KEY_VOLUMEUP,
+ [0x0a] = KEY_MUTE,
+ [0x04] = KEY_AUDIO,
+ [0x26] = KEY_RECORD,
+ [0x06] = KEY_PLAY,
+ [0x36] = KEY_STOP,
+ [0x16] = KEY_PAUSE,
+ [0x2e] = KEY_REWIND,
+ [0x0e] = KEY_FASTFORWARD,
+ [0x30] = KEY_TEXT,
+ [0x21] = KEY_GREEN,
+ [0x01] = KEY_BLUE,
+ [0x08] = KEY_EPG,
+ [0x2a] = KEY_MENU,
+};
+EXPORT_SYMBOL_GPL(ir_codes_avermedia_a16d);
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
index d6206540476b..85482960d012 100644
--- a/drivers/media/common/tuners/Kconfig
+++ b/drivers/media/common/tuners/Kconfig
@@ -21,6 +21,7 @@ config MEDIA_TUNER
tristate
default VIDEO_MEDIA && I2C
depends on VIDEO_MEDIA && I2C
+ select FW_LOADER if !MEDIA_TUNER_CUSTOMIZE && HOTPLUG
select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE && HOTPLUG
select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE && HOTPLUG
select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMIZE
diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c
index 5d05b5390f66..0dc2bef9f6a3 100644
--- a/drivers/media/common/tuners/mxl5005s.c
+++ b/drivers/media/common/tuners/mxl5005s.c
@@ -101,7 +101,7 @@ enum {
MXL_QAM,
MXL_ANALOG_CABLE,
MXL_ANALOG_OTA
-} tuner_modu_type;
+};
/* MXL5005 Tuner Register Struct */
struct TunerReg {
@@ -194,7 +194,7 @@ enum {
RFSYN_DIVM, /* 88 */
DN_BYPASS_AGC_I2C /* 89 */
#endif
-} MXL5005_ControlName;
+};
/*
* The following context is source code provided by MaxLinear.
diff --git a/drivers/media/common/tuners/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c
index 42b5f5d4bfe6..6fb5b4586569 100644
--- a/drivers/media/common/tuners/tda18271-common.c
+++ b/drivers/media/common/tuners/tda18271-common.c
@@ -648,11 +648,19 @@ int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq)
unsigned char *regs = priv->tda18271_regs;
u8 val;
- tda18271_lookup_map(fe, RF_CAL, freq, &val);
+ int ret = tda18271_lookup_map(fe, RF_CAL, freq, &val);
+ /* The TDA18271HD/C1 rf_cal map lookup is expected to go out of range
+ * for frequencies above 61.1 MHz. In these cases, the internal RF
+ * tracking filters calibration mechanism is used.
+ *
+ * There is no need to warn the user about this.
+ */
+ if (ret < 0)
+ goto fail;
regs[R_EB14] = val;
-
- return 0;
+fail:
+ return ret;
}
/*
diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c
index 89c01fb1f859..93063c6fbbf6 100644
--- a/drivers/media/common/tuners/tda18271-fe.c
+++ b/drivers/media/common/tuners/tda18271-fe.c
@@ -45,6 +45,21 @@ static inline int charge_pump_source(struct dvb_frontend *fe, int force)
TDA18271_MAIN_PLL, force);
}
+static inline void tda18271_set_if_notch(struct dvb_frontend *fe)
+{
+ struct tda18271_priv *priv = fe->tuner_priv;
+ unsigned char *regs = priv->tda18271_regs;
+
+ switch (priv->mode) {
+ case TDA18271_ANALOG:
+ regs[R_MPD] &= ~0x80; /* IF notch = 0 */
+ break;
+ case TDA18271_DIGITAL:
+ regs[R_MPD] |= 0x80; /* IF notch = 1 */
+ break;
+ }
+}
+
static int tda18271_channel_configuration(struct dvb_frontend *fe,
struct tda18271_std_map_item *map,
u32 freq, u32 bw)
@@ -60,25 +75,18 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe,
regs[R_EP3] &= ~0x1f; /* clear std bits */
regs[R_EP3] |= (map->agc_mode << 3) | map->std;
- /* set rfagc to high speed mode */
- regs[R_EP3] &= ~0x04;
+ if (priv->id == TDA18271HDC2) {
+ /* set rfagc to high speed mode */
+ regs[R_EP3] &= ~0x04;
+ }
/* set cal mode to normal */
regs[R_EP4] &= ~0x03;
- /* update IF output level & IF notch frequency */
+ /* update IF output level */
regs[R_EP4] &= ~0x1c; /* clear if level bits */
regs[R_EP4] |= (map->if_lvl << 2);
- switch (priv->mode) {
- case TDA18271_ANALOG:
- regs[R_MPD] &= ~0x80; /* IF notch = 0 */
- break;
- case TDA18271_DIGITAL:
- regs[R_MPD] |= 0x80; /* IF notch = 1 */
- break;
- }
-
/* update FM_RFn */
regs[R_EP4] &= ~0x80;
regs[R_EP4] |= map->fm_rfn << 7;
@@ -95,6 +103,9 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe,
/* disable Power Level Indicator */
regs[R_EP1] |= 0x40;
+ /* make sure thermometer is off */
+ regs[R_TM] &= ~0x10;
+
/* frequency dependent parameters */
tda18271_calc_ir_measure(fe, &freq);
@@ -135,6 +146,7 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe,
switch (priv->role) {
case TDA18271_MASTER:
tda18271_calc_main_pll(fe, N);
+ tda18271_set_if_notch(fe);
tda18271_write_regs(fe, R_MPD, 4);
break;
case TDA18271_SLAVE:
@@ -142,6 +154,7 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe,
tda18271_write_regs(fe, R_CPD, 4);
regs[R_MPD] = regs[R_CPD] & 0x7f;
+ tda18271_set_if_notch(fe);
tda18271_write_regs(fe, R_MPD, 1);
break;
}
@@ -160,12 +173,14 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe,
msleep(20);
- /* set rfagc to normal speed mode */
- if (map->fm_rfn)
- regs[R_EP3] &= ~0x04;
- else
- regs[R_EP3] |= 0x04;
- ret = tda18271_write_regs(fe, R_EP3, 1);
+ if (priv->id == TDA18271HDC2) {
+ /* set rfagc to normal speed mode */
+ if (map->fm_rfn)
+ regs[R_EP3] &= ~0x04;
+ else
+ regs[R_EP3] |= 0x04;
+ ret = tda18271_write_regs(fe, R_EP3, 1);
+ }
fail:
return ret;
}
@@ -507,7 +522,7 @@ static int tda18271_powerscan_init(struct dvb_frontend *fe)
/* set cal mode to normal */
regs[R_EP4] &= ~0x03;
- /* update IF output level & IF notch frequency */
+ /* update IF output level */
regs[R_EP4] &= ~0x1c; /* clear if level bits */
ret = tda18271_write_regs(fe, R_EP3, 2);
diff --git a/drivers/media/common/tuners/tda827x.c b/drivers/media/common/tuners/tda827x.c
index d30d2c9094d9..8555d9cf9051 100644
--- a/drivers/media/common/tuners/tda827x.c
+++ b/drivers/media/common/tuners/tda827x.c
@@ -418,13 +418,13 @@ static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
unsigned char buf[] = {0x22, 0x01};
int arg;
int gp_func;
- struct i2c_msg msg = { .addr = priv->cfg->switch_addr, .flags = 0,
- .buf = buf, .len = sizeof(buf) };
+ struct i2c_msg msg = { .flags = 0, .buf = buf, .len = sizeof(buf) };
if (NULL == priv->cfg) {
dprintk("tda827x_config not defined, cannot set LNA gain!\n");
return;
}
+ msg.addr = priv->cfg->switch_addr;
if (priv->cfg->config) {
if (high)
dprintk("setting LNA to high gain\n");
diff --git a/drivers/media/common/tuners/tea5761.c b/drivers/media/common/tuners/tea5761.c
index b93cdef9ac73..b23dadeecd05 100644
--- a/drivers/media/common/tuners/tea5761.c
+++ b/drivers/media/common/tuners/tea5761.c
@@ -295,7 +295,7 @@ struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
{
struct tea5761_priv *priv = NULL;
- if (tea5761_autodetection(i2c_adap, i2c_addr) == EINVAL)
+ if (tea5761_autodetection(i2c_adap, i2c_addr) != 0)
return NULL;
priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL);
diff --git a/drivers/media/common/tuners/tuner-i2c.h b/drivers/media/common/tuners/tuner-i2c.h
index 3ad6c8e0b04c..cb1c7141f0c6 100644
--- a/drivers/media/common/tuners/tuner-i2c.h
+++ b/drivers/media/common/tuners/tuner-i2c.h
@@ -170,4 +170,12 @@ __fail: \
__ret; \
})
+#define hybrid_tuner_report_instance_count(state) \
+({ \
+ int __ret = 0; \
+ if (state) \
+ __ret = state->i2c_props.count; \
+ __ret; \
+})
+
#endif /* __TUNER_I2C_H__ */
diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c
index be8d903171b7..266c255cf0d8 100644
--- a/drivers/media/common/tuners/tuner-simple.c
+++ b/drivers/media/common/tuners/tuner-simple.c
@@ -1018,8 +1018,10 @@ struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
fe->ops.i2c_gate_ctrl(fe, 1);
if (1 != i2c_transfer(i2c_adap, &msg, 1))
- tuner_warn("unable to probe %s, proceeding anyway.",
- tuners[type].name);
+ printk(KERN_WARNING "tuner-simple %d-%04x: "
+ "unable to probe %s, proceeding anyway.",
+ i2c_adapter_id(i2c_adap), i2c_addr,
+ tuners[type].name);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c
index 9e9003cffc7f..0cbde17bfbb7 100644
--- a/drivers/media/common/tuners/tuner-xc2028.c
+++ b/drivers/media/common/tuners/tuner-xc2028.c
@@ -46,7 +46,7 @@ module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
"default firmware name\n");
-static LIST_HEAD(xc2028_list);
+static LIST_HEAD(hybrid_tuner_instance_list);
static DEFINE_MUTEX(xc2028_list_mutex);
/* struct for storing firmware table */
@@ -68,12 +68,11 @@ struct firmware_properties {
};
struct xc2028_data {
- struct list_head xc2028_list;
+ struct list_head hybrid_tuner_instance_list;
struct tuner_i2c_props i2c_props;
int (*tuner_callback) (void *dev,
int command, int arg);
void *video_dev;
- int count;
__u32 frequency;
struct firmware_description *firm;
@@ -1072,20 +1071,19 @@ static int xc2028_dvb_release(struct dvb_frontend *fe)
mutex_lock(&xc2028_list_mutex);
- priv->count--;
-
- if (!priv->count) {
- list_del(&priv->xc2028_list);
-
+ /* only perform final cleanup if this is the last instance */
+ if (hybrid_tuner_report_instance_count(priv) == 1) {
kfree(priv->ctrl.fname);
-
free_firmware(priv);
- kfree(priv);
- fe->tuner_priv = NULL;
}
+ if (priv)
+ hybrid_tuner_release_state(priv);
+
mutex_unlock(&xc2028_list_mutex);
+ fe->tuner_priv = NULL;
+
return 0;
}
@@ -1150,7 +1148,7 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
struct xc2028_config *cfg)
{
struct xc2028_data *priv;
- void *video_dev;
+ int instance;
if (debug)
printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n");
@@ -1163,48 +1161,40 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
return NULL;
}
- video_dev = cfg->i2c_adap->algo_data;
-
- if (debug)
- printk(KERN_DEBUG "xc2028: video_dev =%p\n", video_dev);
-
mutex_lock(&xc2028_list_mutex);
- list_for_each_entry(priv, &xc2028_list, xc2028_list) {
- if (&priv->i2c_props.adap->dev == &cfg->i2c_adap->dev) {
- video_dev = NULL;
- if (debug)
- printk(KERN_DEBUG "xc2028: reusing device\n");
-
- break;
- }
- }
-
- if (video_dev) {
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (priv == NULL) {
- mutex_unlock(&xc2028_list_mutex);
- return NULL;
- }
-
- priv->i2c_props.addr = cfg->i2c_addr;
- priv->i2c_props.adap = cfg->i2c_adap;
- priv->i2c_props.name = "xc2028";
-
- priv->video_dev = video_dev;
+ instance = hybrid_tuner_request_state(struct xc2028_data, priv,
+ hybrid_tuner_instance_list,
+ cfg->i2c_adap, cfg->i2c_addr,
+ "xc2028");
+ switch (instance) {
+ case 0:
+ /* memory allocation failure */
+ goto fail;
+ break;
+ case 1:
+ /* new tuner instance */
priv->tuner_callback = cfg->callback;
priv->ctrl.max_len = 13;
mutex_init(&priv->lock);
- list_add_tail(&priv->xc2028_list, &xc2028_list);
- }
-
- fe->tuner_priv = priv;
- priv->count++;
+ /* analog side (tuner-core) uses i2c_adap->algo_data.
+ * digital side is not guaranteed to have algo_data defined.
+ *
+ * digital side will always have fe->dvb defined.
+ * analog side (tuner-core) doesn't (yet) define fe->dvb.
+ */
+ priv->video_dev = ((fe->dvb) && (fe->dvb->priv)) ?
+ fe->dvb->priv : cfg->i2c_adap->algo_data;
- if (debug)
- printk(KERN_DEBUG "xc2028: usage count is %i\n", priv->count);
+ fe->tuner_priv = priv;
+ break;
+ case 2:
+ /* existing tuner instance */
+ fe->tuner_priv = priv;
+ break;
+ }
memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
sizeof(xc2028_dvb_tuner_ops));
@@ -1217,6 +1207,11 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
mutex_unlock(&xc2028_list_mutex);
return fe;
+fail:
+ mutex_unlock(&xc2028_list_mutex);
+
+ xc2028_dvb_release(fe);
+ return NULL;
}
EXPORT_SYMBOL(xc2028_attach);
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index ceae6db901ec..7cf4f5bdb2ec 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -177,6 +177,7 @@ static XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
{"FM Radio-INPUT1", 0x0208, 0x9002}
};
+static int xc5000_is_firmware_loaded(struct dvb_frontend *fe);
static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len);
static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len);
static void xc5000_TunerReset(struct dvb_frontend *fe);
@@ -352,7 +353,7 @@ static int xc_SetTVStandard(struct xc5000_priv *priv,
static int xc_shutdown(struct xc5000_priv *priv)
{
- return 0;
+ return XC_RESULT_SUCCESS;
/* Fixme: cannot bring tuner back alive once shutdown
* without reloading the driver modules.
* return xc_write_reg(priv, XREG_POWER_DOWN, 0);
@@ -685,6 +686,25 @@ static int xc5000_set_params(struct dvb_frontend *fe,
return 0;
}
+static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
+{
+ struct xc5000_priv *priv = fe->tuner_priv;
+ int ret;
+ u16 id;
+
+ ret = xc5000_readreg(priv, XREG_PRODUCT_ID, &id);
+ if (ret == XC_RESULT_SUCCESS) {
+ if (id == XC_PRODUCT_ID_FW_NOT_LOADED)
+ ret = XC_RESULT_RESET_FAILURE;
+ else
+ ret = XC_RESULT_SUCCESS;
+ }
+
+ dprintk(1, "%s() returns %s id = 0x%x\n", __func__,
+ ret == XC_RESULT_SUCCESS ? "True" : "False", id);
+ return ret;
+}
+
static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
static int xc5000_set_analog_params(struct dvb_frontend *fe,
@@ -693,7 +713,7 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe,
struct xc5000_priv *priv = fe->tuner_priv;
int ret;
- if(priv->fwloaded == 0)
+ if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS)
xc_load_fw_and_init_tuner(fe);
dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
@@ -808,11 +828,10 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
struct xc5000_priv *priv = fe->tuner_priv;
int ret = 0;
- if (priv->fwloaded == 0) {
+ if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
ret = xc5000_fwupload(fe);
if (ret != XC_RESULT_SUCCESS)
return ret;
- priv->fwloaded = 1;
}
/* Start the tuner self-calibration process */
@@ -852,7 +871,6 @@ static int xc5000_sleep(struct dvb_frontend *fe)
return -EREMOTEIO;
}
else {
- /* priv->fwloaded = 0; */
return XC_RESULT_SUCCESS;
}
}
@@ -933,7 +951,6 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
cfg->i2c_address);
printk(KERN_INFO
"xc5000: Firmware has been loaded previously\n");
- priv->fwloaded = 1;
break;
case XC_PRODUCT_ID_FW_NOT_LOADED:
printk(KERN_INFO
@@ -941,7 +958,6 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
cfg->i2c_address);
printk(KERN_INFO
"xc5000: Firmware has not been loaded previously\n");
- priv->fwloaded = 0;
break;
default:
printk(KERN_ERR
diff --git a/drivers/media/common/tuners/xc5000_priv.h b/drivers/media/common/tuners/xc5000_priv.h
index ecebfe4745ad..a72a9887fe7f 100644
--- a/drivers/media/common/tuners/xc5000_priv.h
+++ b/drivers/media/common/tuners/xc5000_priv.h
@@ -30,7 +30,6 @@ struct xc5000_priv {
u32 bandwidth;
u8 video_standard;
u8 rf_mode;
- u8 fwloaded;
void *devptr;
};
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c
index 449fb5c3d0b1..ae0d76a5d51d 100644
--- a/drivers/media/dvb/b2c2/flexcop-usb.c
+++ b/drivers/media/dvb/b2c2/flexcop-usb.c
@@ -379,7 +379,7 @@ static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
{
- u16 frame_size = fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize;
+ u16 frame_size = le16_to_cpu(fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize);
int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * frame_size,i,j,ret;
int buffer_offset = 0;
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index f5010e8671b8..a824f3719f81 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -82,22 +82,22 @@ enum cinergyt2_ep1_cmd {
struct dvbt_set_parameters_msg {
uint8_t cmd;
- uint32_t freq;
+ __le32 freq;
uint8_t bandwidth;
- uint16_t tps;
+ __le16 tps;
uint8_t flags;
} __attribute__((packed));
struct dvbt_get_status_msg {
- uint32_t freq;
+ __le32 freq;
uint8_t bandwidth;
- uint16_t tps;
+ __le16 tps;
uint8_t flags;
- uint16_t gain;
+ __le16 gain;
uint8_t snr;
- uint32_t viterbi_error_rate;
- uint32_t rs_error_rate;
- uint32_t uncorrected_block_count;
+ __le32 viterbi_error_rate;
+ __le32 rs_error_rate;
+ __le32 uncorrected_block_count;
uint8_t lock_bits;
uint8_t prev_lock_bits;
} __attribute__((packed));
@@ -136,6 +136,7 @@ struct cinergyt2 {
wait_queue_head_t poll_wq;
int pending_fe_events;
int disconnect_pending;
+ unsigned int uncorrected_block_count;
atomic_t inuse;
void *streambuf;
@@ -147,7 +148,7 @@ struct cinergyt2 {
char phys[64];
struct delayed_work rc_query_work;
int rc_input_event;
- u32 rc_last_code;
+ __le32 rc_last_code;
unsigned long last_event_jiffies;
#endif
};
@@ -160,7 +161,7 @@ enum {
struct cinergyt2_rc_event {
char type;
- uint32_t value;
+ __le32 value;
} __attribute__((packed));
static const uint32_t rc_keys[] = {
@@ -619,8 +620,11 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
{
uint32_t unc_count;
- unc_count = stat->uncorrected_block_count;
- stat->uncorrected_block_count = 0;
+ if (mutex_lock_interruptible(&cinergyt2->sem))
+ return -ERESTARTSYS;
+ unc_count = cinergyt2->uncorrected_block_count;
+ cinergyt2->uncorrected_block_count = 0;
+ mutex_unlock(&cinergyt2->sem);
/* UNC are already converted to host byte order... */
return put_user(unc_count,(__u32 __user *) arg);
@@ -769,7 +773,7 @@ static void cinergyt2_query_rc (struct work_struct *work)
input_sync(cinergyt2->rc_input_dev);
cinergyt2->rc_input_event = KEY_MAX;
}
- cinergyt2->rc_last_code = ~0;
+ cinergyt2->rc_last_code = cpu_to_le32(~0);
}
goto out;
}
@@ -780,7 +784,7 @@ static void cinergyt2_query_rc (struct work_struct *work)
n, le32_to_cpu(rc_events[n].value), rc_events[n].type);
if (rc_events[n].type == CINERGYT2_RC_EVENT_TYPE_NEC &&
- rc_events[n].value == ~0) {
+ rc_events[n].value == cpu_to_le32(~0)) {
/* keyrepeat bit -> just repeat last rc_input_event */
} else {
cinergyt2->rc_input_event = KEY_MAX;
@@ -795,7 +799,7 @@ static void cinergyt2_query_rc (struct work_struct *work)
if (cinergyt2->rc_input_event != KEY_MAX) {
if (rc_events[n].value == cinergyt2->rc_last_code &&
- cinergyt2->rc_last_code != ~0) {
+ cinergyt2->rc_last_code != cpu_to_le32(~0)) {
/* emit a key-up so the double event is recognized */
dprintk(1, "rc_input_event=%d UP\n", cinergyt2->rc_input_event);
input_report_key(cinergyt2->rc_input_dev,
@@ -829,7 +833,7 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
usb_make_path(cinergyt2->udev, cinergyt2->phys, sizeof(cinergyt2->phys));
strlcat(cinergyt2->phys, "/input0", sizeof(cinergyt2->phys));
cinergyt2->rc_input_event = KEY_MAX;
- cinergyt2->rc_last_code = ~0;
+ cinergyt2->rc_last_code = cpu_to_le32(~0);
INIT_DELAYED_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc);
input_dev->name = DRIVER_NAME " remote control";
@@ -840,8 +844,8 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
input_dev->keycodesize = 0;
input_dev->keycodemax = 0;
input_dev->id.bustype = BUS_USB;
- input_dev->id.vendor = cinergyt2->udev->descriptor.idVendor;
- input_dev->id.product = cinergyt2->udev->descriptor.idProduct;
+ input_dev->id.vendor = le16_to_cpu(cinergyt2->udev->descriptor.idVendor);
+ input_dev->id.product = le16_to_cpu(cinergyt2->udev->descriptor.idProduct);
input_dev->id.version = 1;
input_dev->dev.parent = &cinergyt2->udev->dev;
@@ -889,18 +893,16 @@ static void cinergyt2_query (struct work_struct *work)
char cmd [] = { CINERGYT2_EP1_GET_TUNER_STATUS };
struct dvbt_get_status_msg *s = &cinergyt2->status;
uint8_t lock_bits;
- uint32_t unc;
if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
return;
- unc = s->uncorrected_block_count;
lock_bits = s->lock_bits;
cinergyt2_command(cinergyt2, cmd, sizeof(cmd), (char *) s, sizeof(*s));
- unc += le32_to_cpu(s->uncorrected_block_count);
- s->uncorrected_block_count = unc;
+ cinergyt2->uncorrected_block_count +=
+ le32_to_cpu(s->uncorrected_block_count);
if (lock_bits != s->lock_bits) {
wake_up_interruptible(&cinergyt2->poll_wq);
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 56d871cfd7fc..c2334aef4143 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -168,7 +168,7 @@ struct dvb_net_priv {
* stolen from eth.c out of the linux kernel, hacked for dvb-device
* by Michael Holzt <kju@debian.org>
*/
-static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb,
+static __be16 dvb_net_eth_type_trans(struct sk_buff *skb,
struct net_device *dev)
{
struct ethhdr *eth;
@@ -277,10 +277,10 @@ static int handle_one_ule_extension( struct dvb_net_priv *p )
if(ext_len >= 0) {
p->ule_next_hdr += ext_len;
if (!p->ule_bridged) {
- p->ule_sndu_type = ntohs(*(unsigned short *)p->ule_next_hdr);
+ p->ule_sndu_type = ntohs(*(__be16 *)p->ule_next_hdr);
p->ule_next_hdr += 2;
} else {
- p->ule_sndu_type = ntohs(*(unsigned short *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)));
+ p->ule_sndu_type = ntohs(*(__be16 *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)));
/* This assures the extension handling loop will terminate. */
}
}
@@ -294,7 +294,7 @@ static int handle_one_ule_extension( struct dvb_net_priv *p )
if (ule_optional_ext_handlers[htype])
(void)ule_optional_ext_handlers[htype]( p );
p->ule_next_hdr += ext_len;
- p->ule_sndu_type = ntohs( *(unsigned short *)(p->ule_next_hdr-2) );
+ p->ule_sndu_type = ntohs( *(__be16 *)(p->ule_next_hdr-2) );
/*
* note: the length of the next header type is included in the
* length of THIS optional extension header
@@ -594,8 +594,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
/* Check for complete payload. */
if (priv->ule_sndu_remain <= 0) {
/* Check CRC32, we've got it in our skb already. */
- unsigned short ulen = htons(priv->ule_sndu_len);
- unsigned short utype = htons(priv->ule_sndu_type);
+ __be16 ulen = htons(priv->ule_sndu_len);
+ __be16 utype = htons(priv->ule_sndu_type);
const u8 *tail;
struct kvec iov[3] = {
{ &ulen, sizeof ulen },
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index cf4584e48b6d..f00a0eb40420 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -1,6 +1,6 @@
config DVB_USB
tristate "Support for various USB DVB devices"
- depends on DVB_CORE && USB && I2C
+ depends on DVB_CORE && USB && I2C && INPUT
depends on HOTPLUG # due to FW_LOADER
select FW_LOADER
help
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 346223856f59..c4d40fe01d57 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -111,8 +111,8 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
s8 a;
int if1=1220;
- if (adap->dev->udev->descriptor.idVendor == USB_VID_HAUPPAUGE &&
- adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_500_2) {
+ if (adap->dev->udev->descriptor.idVendor == cpu_to_le16(USB_VID_HAUPPAUGE) &&
+ adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_500_2)) {
if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a;
}
return dvb_attach(mt2060_attach,adap->fe, tun_i2c,&bristol_mt2060_config[adap->id],
@@ -402,8 +402,8 @@ static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap)
{
struct usb_device_descriptor *desc = &adap->dev->udev->descriptor;
- if (desc->idVendor == USB_VID_PINNACLE &&
- desc->idProduct == USB_PID_PINNACLE_EXPRESSCARD_320CX)
+ if (desc->idVendor == cpu_to_le16(USB_VID_PINNACLE) &&
+ desc->idProduct == cpu_to_le16(USB_PID_PINNACLE_EXPRESSCARD_320CX))
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
else
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
@@ -845,8 +845,8 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
struct i2c_adapter *tun_i2c;
s8 a;
int if1=1220;
- if (adap->dev->udev->descriptor.idVendor == USB_VID_HAUPPAUGE &&
- adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_STICK) {
+ if (adap->dev->udev->descriptor.idVendor == cpu_to_le16(USB_VID_HAUPPAUGE) &&
+ adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_STICK)) {
if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a;
}
if (st->is_dib7000pc)
@@ -990,11 +990,12 @@ static struct dib7000p_config dib7070p_dib7000p_config = {
/* STK7070P */
static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
{
- if (adap->dev->udev->descriptor.idVendor == USB_VID_PINNACLE &&
- adap->dev->udev->descriptor.idProduct == USB_PID_PINNACLE_PCTV72E)
- dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
+ struct usb_device_descriptor *p = &adap->dev->udev->descriptor;
+ if (p->idVendor == cpu_to_le16(USB_VID_PINNACLE) &&
+ p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E))
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
else
- dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
msleep(10);
dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
index e1112e39fb63..733a7ff7b207 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
@@ -127,7 +127,7 @@ int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx,
if ((*pos + hx->len + 4) >= fw->size)
return -EINVAL;
- hx->addr = le16_to_cpu( *((u16 *) &b[1]) );
+ hx->addr = b[1] | (b[2] << 8);
hx->type = b[3];
if (hx->type == 0x04) {
diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
index 0a8ac64a4e33..037f7ffb47b2 100644
--- a/drivers/media/dvb/dvb-usb/gl861.c
+++ b/drivers/media/dvb/dvb-usb/gl861.c
@@ -47,6 +47,8 @@ static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
return -EINVAL;
}
+ msleep(1); /* avoid I2C errors */
+
return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type,
value, index, rbuf, rlen, 2000);
}
@@ -92,16 +94,6 @@ static struct i2c_algorithm gl861_i2c_algo = {
};
/* Callbacks for DVB USB */
-static int gl861_identify_state(struct usb_device *udev,
- struct dvb_usb_device_properties *props,
- struct dvb_usb_device_description **desc,
- int *cold)
-{
- *cold = 0;
-
- return 0;
-}
-
static struct zl10353_config gl861_zl10353_config = {
.demod_address = 0x0f,
.no_tuner = 1,
@@ -172,7 +164,6 @@ static struct dvb_usb_device_properties gl861_properties = {
.size_of_priv = 0,
- .identify_state = gl861_identify_state,
.num_adapters = 1,
.adapter = {{
@@ -194,13 +185,15 @@ static struct dvb_usb_device_properties gl861_properties = {
.num_device_descs = 2,
.devices = {
- { "MSI Mega Sky 55801 DVB-T USB2.0",
- { &gl861_table[0], NULL },
- { NULL },
+ {
+ .name = "MSI Mega Sky 55801 DVB-T USB2.0",
+ .cold_ids = { NULL },
+ .warm_ids = { &gl861_table[0], NULL },
},
- { "A-LINK DTU DVB-T USB2.0",
- { &gl861_table[1], NULL },
- { NULL },
+ {
+ .name = "A-LINK DTU DVB-T USB2.0",
+ .cold_ids = { NULL },
+ .warm_ids = { &gl861_table[1], NULL },
},
}
};
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
index 9a942afaf0af..2653120673b7 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -146,24 +146,24 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */
if(gp8psk_load_bcm4500fw(d))
- return EINVAL;
+ return -EINVAL;
if (! (status & bmIntersilOn)) /* LNB Power */
if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0,
&buf, 1))
- return EINVAL;
+ return -EINVAL;
/* Set DVB mode to 1 */
if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
- return EINVAL;
+ return -EINVAL;
/* Abort possible TS (if previous tune crashed) */
if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0))
- return EINVAL;
+ return -EINVAL;
} else {
/* Turn off LNB power */
if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1))
- return EINVAL;
+ return -EINVAL;
/* Turn off 8psk power */
if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
return -EINVAL;
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
index a12e6f784fda..54626a0dbf68 100644
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -16,6 +16,7 @@
#include "qt1010.h"
#include "tda1004x.h"
#include "tda827x.h"
+#include <asm/unaligned.h>
/* debug */
static int dvb_usb_m920x_debug;
@@ -347,13 +348,13 @@ static int m920x_firmware_download(struct usb_device *udev, const struct firmwar
for (pass = 0; pass < 2; pass++) {
for (i = 0; i + (sizeof(u16) * 3) < fw->size;) {
- value = le16_to_cpu(*(u16 *)(fw->data + i));
+ value = get_unaligned_le16(fw->data + i);
i += sizeof(u16);
- index = le16_to_cpu(*(u16 *)(fw->data + i));
+ index = get_unaligned_le16(fw->data + i);
i += sizeof(u16);
- size = le16_to_cpu(*(u16 *)(fw->data + i));
+ size = get_unaligned_le16(fw->data + i);
i += sizeof(u16);
if (pass == 1) {
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
index 9e7653bb3b66..118aab1a3e54 100644
--- a/drivers/media/dvb/dvb-usb/umt-010.c
+++ b/drivers/media/dvb/dvb-usb/umt-010.c
@@ -107,7 +107,7 @@ static struct dvb_usb_device_properties umt_properties = {
/* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
- .count = 20,
+ .count = MAX_NO_URBS_FOR_DATA_STREAM,
.endpoint = 0x06,
.u = {
.bulk = {
diff --git a/drivers/media/dvb/frontends/au8522.c b/drivers/media/dvb/frontends/au8522.c
index 084a280c2d7f..03900d241a76 100644
--- a/drivers/media/dvb/frontends/au8522.c
+++ b/drivers/media/dvb/frontends/au8522.c
@@ -463,10 +463,13 @@ static int au8522_set_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct au8522_state *state = fe->demodulator_priv;
+ int ret = -EINVAL;
dprintk("%s(frequency=%d)\n", __func__, p->frequency);
- state->current_frequency = p->frequency;
+ if ((state->current_frequency == p->frequency) &&
+ (state->current_modulation == p->u.vsb.modulation))
+ return 0;
au8522_enable_modulation(fe, p->u.vsb.modulation);
@@ -476,11 +479,16 @@ static int au8522_set_frontend(struct dvb_frontend *fe,
if (fe->ops.tuner_ops.set_params) {
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- fe->ops.tuner_ops.set_params(fe, p);
+ ret = fe->ops.tuner_ops.set_params(fe, p);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
+ if (ret < 0)
+ return ret;
+
+ state->current_frequency = p->frequency;
+
return 0;
}
@@ -498,6 +506,16 @@ static int au8522_init(struct dvb_frontend *fe)
return 0;
}
+static int au8522_sleep(struct dvb_frontend *fe)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ dprintk("%s()\n", __func__);
+
+ state->current_frequency = 0;
+
+ return 0;
+}
+
static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct au8522_state *state = fe->demodulator_priv;
@@ -509,10 +527,8 @@ static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
if (state->current_modulation == VSB_8) {
dprintk("%s() Checking VSB_8\n", __func__);
reg = au8522_readreg(state, 0x4088);
- if (reg & 0x01)
- *status |= FE_HAS_VITERBI;
- if (reg & 0x02)
- *status |= FE_HAS_LOCK | FE_HAS_SYNC;
+ if ((reg & 0x03) == 0x03)
+ *status |= FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
} else {
dprintk("%s() Checking QAM\n", __func__);
reg = au8522_readreg(state, 0x4541);
@@ -672,6 +688,7 @@ static struct dvb_frontend_ops au8522_ops = {
},
.init = au8522_init,
+ .sleep = au8522_sleep,
.i2c_gate_ctrl = au8522_i2c_gate_ctrl,
.set_frontend = au8522_set_frontend,
.get_frontend = au8522_get_frontend,
diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h
index 786e37d33889..3eedfdf505bc 100644
--- a/drivers/media/dvb/frontends/dib0070.h
+++ b/drivers/media/dvb/frontends/dib0070.h
@@ -37,7 +37,20 @@ struct dib0070_config {
u8 flip_chip;
};
-extern struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg);
+#if defined(CONFIG_DVB_TUNER_DIB0070) || (defined(CONFIG_DVB_TUNER_DIB0070_MODULE) && defined(MODULE))
+extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct dib0070_config *cfg);
+#else
+static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct dib0070_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open);
extern u16 dib0070_wbd_offset(struct dvb_frontend *);
diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h
index 081bd81f3da2..07c4d12ed5b7 100644
--- a/drivers/media/dvb/frontends/dib7000p.h
+++ b/drivers/media/dvb/frontends/dib7000p.h
@@ -37,7 +37,20 @@ struct dib7000p_config {
#define DEFAULT_DIB7000P_I2C_ADDRESS 18
-extern struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg);
+#if defined(CONFIG_DVB_DIB7000P) || (defined(CONFIG_DVB_DIB7000P_MODULE) && defined(MODULE))
+extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap,
+ u8 i2c_addr,
+ struct dib7000p_config *cfg);
+#else
+static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap,
+ u8 i2c_addr,
+ struct dib7000p_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index c7b5785f81f2..5ed32544de39 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -126,7 +126,7 @@ static int or51132_readreg(struct or51132_state *state, u8 reg)
reg, err);
return -EREMOTEIO;
}
- return le16_to_cpup((u16*)buf);
+ return buf[0] | (buf[1] << 8);
}
static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
@@ -140,9 +140,9 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
dprintk("Firmware is %Zd bytes\n",fw->size);
/* Get size of firmware A and B */
- firmwareAsize = le32_to_cpu(*((u32*)fw->data));
+ firmwareAsize = le32_to_cpu(*((__le32*)fw->data));
dprintk("FirmwareA is %i bytes\n",firmwareAsize);
- firmwareBsize = le32_to_cpu(*((u32*)(fw->data+4)));
+ firmwareBsize = le32_to_cpu(*((__le32*)(fw->data+4)));
dprintk("FirmwareB is %i bytes\n",firmwareBsize);
/* Upload firmware */
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 17556183e871..35435bef8e79 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -63,6 +63,7 @@ struct stv0299_state {
u32 symbol_rate;
fe_code_rate_t fec_inner;
int errmode;
+ u32 ucblocks;
};
#define STATUS_BER 0
@@ -501,8 +502,10 @@ static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber)
{
struct stv0299_state* state = fe->demodulator_priv;
- if (state->errmode != STATUS_BER) return 0;
- *ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
+ if (state->errmode != STATUS_BER)
+ return -ENOSYS;
+
+ *ber = stv0299_readreg(state, 0x1e) | (stv0299_readreg(state, 0x1d) << 8);
return 0;
}
@@ -540,8 +543,12 @@ static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
{
struct stv0299_state* state = fe->demodulator_priv;
- if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0;
- else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
+ if (state->errmode != STATUS_UCBLOCKS)
+ return -ENOSYS;
+
+ state->ucblocks += stv0299_readreg(state, 0x1e);
+ state->ucblocks += (stv0299_readreg(state, 0x1d) << 8);
+ *ucblocks = state->ucblocks;
return 0;
}
diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c
index 0727b80bc4d2..c6ff5b82ff80 100644
--- a/drivers/media/dvb/frontends/tda10023.c
+++ b/drivers/media/dvb/frontends/tda10023.c
@@ -116,9 +116,12 @@ static u8 tda10023_readreg (struct tda10023_state* state, u8 reg)
int ret;
ret = i2c_transfer (state->i2c, msg, 2);
- if (ret != 2)
- printk("DVB: TDA10023: %s: readreg error (ret == %i)\n",
- __func__, ret);
+ if (ret != 2) {
+ int num = state->frontend.dvb ? state->frontend.dvb->num : -1;
+ printk(KERN_ERR "DVB: TDA10023(%d): %s: readreg error "
+ "(reg == 0x%02x, ret == %i)\n",
+ num, __func__, reg, ret);
+ }
return b1[0];
}
@@ -129,11 +132,12 @@ static int tda10023_writereg (struct tda10023_state* state, u8 reg, u8 data)
int ret;
ret = i2c_transfer (state->i2c, &msg, 1);
- if (ret != 1)
- printk("DVB: TDA10023(%d): %s, writereg error "
+ if (ret != 1) {
+ int num = state->frontend.dvb ? state->frontend.dvb->num : -1;
+ printk(KERN_ERR "DVB: TDA10023(%d): %s, writereg error "
"(reg == 0x%02x, val == 0x%02x, ret == %i)\n",
- state->frontend.dvb->num, __func__, reg, data, ret);
-
+ num, __func__, reg, data, ret);
+ }
return (ret != 1) ? -EREMOTEIO : 0;
}
@@ -464,7 +468,7 @@ struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
int i;
/* allocate memory for the internal state */
- state = kmalloc(sizeof(struct tda10023_state), GFP_KERNEL);
+ state = kzalloc(sizeof(struct tda10023_state), GFP_KERNEL);
if (state == NULL) goto error;
/* setup the state */
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index 49973846373e..a0d638653567 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -1248,11 +1248,14 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
struct i2c_adapter* i2c)
{
struct tda1004x_state *state;
+ int id;
/* allocate memory for the internal state */
state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
- if (!state)
+ if (!state) {
+ printk(KERN_ERR "Can't alocate memory for tda10045 state\n");
return NULL;
+ }
/* setup the state */
state->config = config;
@@ -1260,7 +1263,15 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
state->demod_type = TDA1004X_DEMOD_TDA10045;
/* check if the demod is there */
- if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x25) {
+ id = tda1004x_read_byte(state, TDA1004X_CHIPID);
+ if (id < 0) {
+ printk(KERN_ERR "tda10045: chip is not answering. Giving up.\n");
+ kfree(state);
+ return NULL;
+ }
+
+ if (id != 0x25) {
+ printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id);
kfree(state);
return NULL;
}
@@ -1307,11 +1318,14 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
struct i2c_adapter* i2c)
{
struct tda1004x_state *state;
+ int id;
/* allocate memory for the internal state */
state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL);
- if (!state)
+ if (!state) {
+ printk(KERN_ERR "Can't alocate memory for tda10046 state\n");
return NULL;
+ }
/* setup the state */
state->config = config;
@@ -1319,7 +1333,14 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
state->demod_type = TDA1004X_DEMOD_TDA10046;
/* check if the demod is there */
- if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) {
+ id = tda1004x_read_byte(state, TDA1004X_CHIPID);
+ if (id < 0) {
+ printk(KERN_ERR "tda10046: chip is not answering. Giving up.\n");
+ kfree(state);
+ return NULL;
+ }
+ if (id != 0x46) {
+ printk(KERN_ERR "Invalid tda1004x ID = 0x%02x. Can't proceed\n", id);
kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index d4339b1b3b68..07643e010093 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -101,6 +101,7 @@ config DVB_BUDGET
config DVB_BUDGET_CI
tristate "Budget cards with onboard CI connector"
depends on DVB_BUDGET_CORE && I2C
+ depends on INPUT # due to IR
select DVB_STV0297 if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 747e7f1a6267..f05d43d8b5cf 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -51,6 +51,7 @@
#include <linux/crc32.h>
#include <linux/i2c.h>
#include <linux/kthread.h>
+#include <asm/unaligned.h>
#include <asm/system.h>
@@ -1461,9 +1462,9 @@ static int check_firmware(struct av7110* av7110)
ptr += 4;
/* check dpram file */
- crc = ntohl(*(u32*) ptr);
+ crc = get_unaligned_be32(ptr);
ptr += 4;
- len = ntohl(*(u32*) ptr);
+ len = get_unaligned_be32(ptr);
ptr += 4;
if (len >= 512) {
printk("dvb-ttpci: dpram file is way too big.\n");
@@ -1478,9 +1479,9 @@ static int check_firmware(struct av7110* av7110)
ptr += len;
/* check root file */
- crc = ntohl(*(u32*) ptr);
+ crc = get_unaligned_be32(ptr);
ptr += 4;
- len = ntohl(*(u32*) ptr);
+ len = get_unaligned_be32(ptr);
ptr += 4;
if (len <= 200000 || len >= 300000 ||
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 3e6b650fbb81..ec55a968f204 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -965,8 +965,9 @@ static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x
static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock)
{
- int i, n;
+ unsigned i, n;
int progressive = 0;
+ int match = 0;
dprintk(2, "av7110:%p, \n", av7110);
@@ -975,12 +976,31 @@ static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len
return -EBUSY;
}
- for (i = 0; i < len - 5; i++) {
- /* get progressive flag from picture extension */
- if (buf[i] == 0x00 && buf[i+1] == 0x00 &&
- buf[i+2] == 0x01 && (unsigned char)buf[i+3] == 0xb5 &&
- (buf[i+4] & 0xf0) == 0x10)
- progressive = buf[i+5] & 0x08;
+ /* search in buf for instances of 00 00 01 b5 1? */
+ for (i = 0; i < len; i++) {
+ unsigned char c;
+ if (get_user(c, buf + i))
+ return -EFAULT;
+ if (match == 5) {
+ progressive = c & 0x08;
+ match = 0;
+ }
+ if (c == 0x00) {
+ match = (match == 1 || match == 2) ? 2 : 1;
+ continue;
+ }
+ switch (match++) {
+ case 2: if (c == 0x01)
+ continue;
+ break;
+ case 3: if (c == 0xb5)
+ continue;
+ break;
+ case 4: if ((c & 0xf0) == 0x10)
+ continue;
+ break;
+ }
+ match = 0;
}
/* setting n always > 1, fixes problems when playing stillframes
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 9d81074b31df..3a3f5279e927 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -427,6 +427,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
if (err) {
printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
__func__, type);
+ av7110->arm_errors++;
return -ETIMEDOUT;
}
msleep(1);
@@ -853,10 +854,8 @@ static osd_raw_window_t bpp2bit[8] = {
static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
{
- int ret = wait_event_interruptible_timeout(av7110->bmpq,
+ int ret = wait_event_timeout(av7110->bmpq,
av7110->bmp_state != BMP_LOADING, 10*HZ);
- if (ret == -ERESTARTSYS)
- return ret;
if (ret == 0) {
printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
ret, av7110->bmp_state);
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 732ce4de512e..5d2d81ab2371 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -552,7 +552,7 @@ static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack,
u16 csum = 0, cc;
int i;
for (i = 0; i < len; i += 2)
- csum ^= le16_to_cpup((u16 *) (muxpack + i));
+ csum ^= le16_to_cpup((__le16 *) (muxpack + i));
if (csum) {
printk("%s: muxpack with incorrect checksum, ignoring\n",
__func__);
diff --git a/drivers/media/dvb/ttusb-dec/Kconfig b/drivers/media/dvb/ttusb-dec/Kconfig
index 0712899e39a4..a23cc0aa17d3 100644
--- a/drivers/media/dvb/ttusb-dec/Kconfig
+++ b/drivers/media/dvb/ttusb-dec/Kconfig
@@ -1,6 +1,6 @@
config DVB_TTUSB_DEC
tristate "Technotrend/Hauppauge USB DEC devices"
- depends on DVB_CORE && USB
+ depends on DVB_CORE && USB && INPUT
depends on HOTPLUG # due to FW_LOADER
select FW_LOADER
select CRC32
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 42eee04daa5d..fefdc05e84ac 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -343,7 +343,7 @@ static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode,
u8 c[COMMAND_PACKET_SIZE];
int c_length;
int result;
- unsigned int tmp;
+ __be32 tmp;
dprintk("%s\n", __func__);
@@ -398,9 +398,9 @@ static void ttusb_dec_set_pids(struct ttusb_dec *dec)
0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff };
- u16 pcr = htons(dec->pid[DMX_PES_PCR]);
- u16 audio = htons(dec->pid[DMX_PES_AUDIO]);
- u16 video = htons(dec->pid[DMX_PES_VIDEO]);
+ __be16 pcr = htons(dec->pid[DMX_PES_PCR]);
+ __be16 audio = htons(dec->pid[DMX_PES_AUDIO]);
+ __be16 video = htons(dec->pid[DMX_PES_VIDEO]);
dprintk("%s\n", __func__);
@@ -435,7 +435,7 @@ static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length)
case 0x01: { /* VideoStream */
int prebytes = pva[5] & 0x03;
int postbytes = (pva[5] & 0x0c) >> 2;
- u16 v_pes_payload_length;
+ __be16 v_pes_payload_length;
if (output_pva) {
dec->video_filter->feed->cb.ts(pva, length, NULL, 0,
@@ -1006,7 +1006,7 @@ static int ttusb_dec_start_sec_feed(struct dvb_demux_feed *dvbdmxfeed)
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00 };
- u16 pid;
+ __be16 pid;
u8 c[COMMAND_PACKET_SIZE];
int c_length;
int result;
@@ -1278,9 +1278,10 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
u8 *firmware = NULL;
size_t firmware_size = 0;
u16 firmware_csum = 0;
- u16 firmware_csum_ns;
- u32 firmware_size_nl;
- u32 crc32_csum, crc32_check, tmp;
+ __be16 firmware_csum_ns;
+ __be32 firmware_size_nl;
+ u32 crc32_csum, crc32_check;
+ __be32 tmp;
const struct firmware *fw_entry = NULL;
dprintk("%s\n", __func__);
@@ -1306,7 +1307,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
valid. */
crc32_csum = crc32(~0L, firmware, 56) ^ ~0L;
memcpy(&tmp, &firmware[56], 4);
- crc32_check = htonl(tmp);
+ crc32_check = ntohl(tmp);
if (crc32_csum != crc32_check) {
printk("%s: crc32 check of DSP code failed (calculated "
"0x%08x != 0x%08x in file), file invalid.\n",
@@ -1627,7 +1628,7 @@ static int ttusb_dec_probe(struct usb_interface *intf,
usb_set_intfdata(intf, (void *)dec);
- switch (le16_to_cpu(id->idProduct)) {
+ switch (id->idProduct) {
case 0x1006:
ttusb_dec_set_model(dec, TTUSB_DEC3000S);
break;
@@ -1652,7 +1653,7 @@ static int ttusb_dec_probe(struct usb_interface *intf,
ttusb_dec_init_dvb(dec);
dec->adapter.priv = dec;
- switch (le16_to_cpu(id->idProduct)) {
+ switch (id->idProduct) {
case 0x1006:
dec->fe = ttusbdecfe_dvbs_attach(&fe_config);
break;
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
index eb5eaeccd7c4..443af24097f3 100644
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
@@ -86,7 +86,7 @@ static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_fron
0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff };
- u32 freq = htonl(p->frequency / 1000);
+ __be32 freq = htonl(p->frequency / 1000);
memcpy(&b[4], &freq, sizeof (u32));
state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL);
@@ -117,10 +117,10 @@ static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_fron
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
- u32 freq;
- u32 sym_rate;
- u32 band;
- u32 lnb_voltage;
+ __be32 freq;
+ __be32 sym_rate;
+ __be32 band;
+ __be32 lnb_voltage;
freq = htonl(p->frequency +
(state->hi_band ? LOF_HI : LOF_LO));
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 89d8d37838a3..5ccb0aeca8cc 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -793,6 +793,14 @@ menuconfig V4L_USB_DRIVERS
if V4L_USB_DRIVERS && USB
+config USB_VIDEO_CLASS
+ tristate "USB Video Class (UVC)"
+ ---help---
+ Support for the USB Video Class (UVC). Currently only video
+ input devices, such as webcams, are supported.
+
+ For more information see: <http://linux-uvc.berlios.de/>
+
source "drivers/media/video/pvrusb2/Kconfig"
source "drivers/media/video/em28xx/Kconfig"
@@ -901,7 +909,7 @@ endif # V4L_USB_DRIVERS
config SOC_CAMERA
tristate "SoC camera support"
- depends on VIDEO_V4L2
+ depends on VIDEO_V4L2 && HAS_DMA
select VIDEOBUF_DMA_SG
help
SoC Camera is a common API to several cameras, not connecting
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index dff0d6abe917..ecbbfaab24d5 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -136,6 +136,8 @@ obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
obj-$(CONFIG_VIDEO_AU0828) += au0828/
+obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/
+
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig
index def10d086373..52b2491581a8 100644
--- a/drivers/media/video/au0828/Kconfig
+++ b/drivers/media/video/au0828/Kconfig
@@ -1,7 +1,7 @@
config VIDEO_AU0828
tristate "Auvitek AU0828 support"
- depends on VIDEO_DEV && I2C && INPUT && DVB_CORE && USB
+ depends on I2C && INPUT && DVB_CORE && USB
select I2C_ALGOBIT
select VIDEO_TVEEPROM
select DVB_AU8522 if !DVB_FE_CUSTOMIZE
diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
index a2a6983444fa..898e12395e7c 100644
--- a/drivers/media/video/au0828/au0828-cards.c
+++ b/drivers/media/video/au0828/au0828-cards.c
@@ -77,8 +77,14 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
/* Make sure we support the board model */
switch (tv.model) {
+ case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */
case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */
+ case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
+ case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
+ case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and basic analog video */
+ case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and basic analog video */
case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and basic analog video */
+ case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
break;
default:
printk(KERN_WARNING "%s: warning: "
@@ -175,6 +181,18 @@ struct usb_device_id au0828_usb_id_table [] = {
.driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 },
{ USB_DEVICE(0x0fe9, 0xd620),
.driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 },
+ { USB_DEVICE(0x2040, 0x7210),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x7217),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x721b),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x721f),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x7280),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x0fd9, 0x0008),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
{ },
};
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
index c86a5f17eca8..c6d470590380 100644
--- a/drivers/media/video/au0828/au0828-dvb.c
+++ b/drivers/media/video/au0828/au0828-dvb.c
@@ -353,12 +353,6 @@ int au0828_dvb_register(struct au0828_dev *dev)
return -1;
}
- /* Put the analog decoder in standby to keep it quiet */
- au0828_call_i2c_clients(dev, TUNER_SET_STANDBY, NULL);
-
- if (dvb->frontend->ops.analog_ops.standby)
- dvb->frontend->ops.analog_ops.standby(dvb->frontend);
-
/* register everything */
ret = dvb_register(dev);
if (ret < 0) {
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index f20a01cfc73e..8ef0424c26c4 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -34,6 +34,7 @@
#include <linux/firmware.h>
#include <net/checksum.h>
+#include <asm/unaligned.h>
#include <asm/io.h>
#include "bttvp.h"
@@ -3858,7 +3859,7 @@ static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256])
ee += i;
/* found a valid descriptor */
- type = be16_to_cpup((u16*)(ee+4));
+ type = get_unaligned_be16((__be16 *)(ee+4));
switch(type) {
/* 848 based */
@@ -3918,7 +3919,7 @@ static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256])
btv->c.nr, type);
break;
}
- serial = be32_to_cpup((u32*)(ee+6));
+ serial = get_unaligned_be32((__be32 *)(ee+6));
}
printk(KERN_INFO "bttv%d: osprey eeprom: card=%d '%s' serial=%u\n",
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 2ca3e9cfb2bb..0165aac533bf 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -2613,7 +2613,7 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
struct bttv_fh *fh = priv;
mutex_lock(&fh->cap.vb_lock);
- retval = videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize,
+ retval = __videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize,
V4L2_MEMORY_MMAP);
if (retval < 0) {
mutex_unlock(&fh->cap.vb_lock);
diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
index e5979f77504c..0af586876e72 100644
--- a/drivers/media/video/bt8xx/bttv-risc.c
+++ b/drivers/media/video/bt8xx/bttv-risc.c
@@ -48,7 +48,7 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
{
u32 instructions,line,todo;
struct scatterlist *sg;
- u32 *rp;
+ __le32 *rp;
int rc;
/* estimate risc mem: worst case is one write per page border +
@@ -128,7 +128,8 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
unsigned int cpadding)
{
unsigned int instructions,line,todo,ylen,chroma;
- u32 *rp,ri;
+ __le32 *rp;
+ u32 ri;
struct scatterlist *ysg;
struct scatterlist *usg;
struct scatterlist *vsg;
@@ -244,7 +245,8 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
{
int dwords,rc,line,maxy,start,end,skip,nskips;
struct btcx_skiplist *skips;
- u32 *rp,ri,ra;
+ __le32 *rp;
+ u32 ri,ra;
u32 addr;
/* skip list for window clipping */
diff --git a/drivers/media/video/btcx-risc.c b/drivers/media/video/btcx-risc.c
index ce0840ccd594..f42701f82e7f 100644
--- a/drivers/media/video/btcx-risc.c
+++ b/drivers/media/video/btcx-risc.c
@@ -63,7 +63,7 @@ int btcx_riscmem_alloc(struct pci_dev *pci,
struct btcx_riscmem *risc,
unsigned int size)
{
- u32 *cpu;
+ __le32 *cpu;
dma_addr_t dma;
if (NULL != risc->cpu && risc->size < size)
diff --git a/drivers/media/video/btcx-risc.h b/drivers/media/video/btcx-risc.h
index 503e6c6d7b69..861bc8112824 100644
--- a/drivers/media/video/btcx-risc.h
+++ b/drivers/media/video/btcx-risc.h
@@ -2,8 +2,8 @@
*/
struct btcx_riscmem {
unsigned int size;
- u32 *cpu;
- u32 *jmp;
+ __le32 *cpu;
+ __le32 *jmp;
dma_addr_t dma;
};
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig
index 5f942690570c..9aefdc5ea79a 100644
--- a/drivers/media/video/cx18/Kconfig
+++ b/drivers/media/video/cx18/Kconfig
@@ -10,8 +10,8 @@ config VIDEO_CX18
select VIDEO_TVEEPROM
select VIDEO_CX2341X
select VIDEO_CS5345
- select DVB_S5H1409
- select MEDIA_TUNER_MXL5005S
+ select DVB_S5H1409 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
---help---
This is a video4linux driver for Conexant cx23418 based
PCI combo video recorder devices.
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c
index 66864904c99b..faca43eb940f 100644
--- a/drivers/media/video/cx18/cx18-av-core.c
+++ b/drivers/media/video/cx18/cx18-av-core.c
@@ -69,6 +69,58 @@ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
or_value);
}
+int cx18_av_write_no_acfg(struct cx18 *cx, u16 addr, u8 value, int no_acfg_mask)
+{
+ int retval;
+ u32 saved_reg[8] = {0};
+
+ if (no_acfg_mask & CXADEC_NO_ACFG_AFE) {
+ saved_reg[0] = cx18_av_read4(cx, CXADEC_CHIP_CTRL);
+ saved_reg[1] = cx18_av_read4(cx, CXADEC_AFE_CTRL);
+ }
+
+ if (no_acfg_mask & CXADEC_NO_ACFG_PLL) {
+ saved_reg[2] = cx18_av_read4(cx, CXADEC_PLL_CTRL1);
+ saved_reg[3] = cx18_av_read4(cx, CXADEC_VID_PLL_FRAC);
+ }
+
+ if (no_acfg_mask & CXADEC_NO_ACFG_VID) {
+ saved_reg[4] = cx18_av_read4(cx, CXADEC_HORIZ_TIM_CTRL);
+ saved_reg[5] = cx18_av_read4(cx, CXADEC_VERT_TIM_CTRL);
+ saved_reg[6] = cx18_av_read4(cx, CXADEC_SRC_COMB_CFG);
+ saved_reg[7] = cx18_av_read4(cx, CXADEC_CHROMA_VBIOFF_CFG);
+ }
+
+ retval = cx18_av_write(cx, addr, value);
+
+ if (no_acfg_mask & CXADEC_NO_ACFG_AFE) {
+ cx18_av_write4(cx, CXADEC_CHIP_CTRL, saved_reg[0]);
+ cx18_av_write4(cx, CXADEC_AFE_CTRL, saved_reg[1]);
+ }
+
+ if (no_acfg_mask & CXADEC_NO_ACFG_PLL) {
+ cx18_av_write4(cx, CXADEC_PLL_CTRL1, saved_reg[2]);
+ cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, saved_reg[3]);
+ }
+
+ if (no_acfg_mask & CXADEC_NO_ACFG_VID) {
+ cx18_av_write4(cx, CXADEC_HORIZ_TIM_CTRL, saved_reg[4]);
+ cx18_av_write4(cx, CXADEC_VERT_TIM_CTRL, saved_reg[5]);
+ cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, saved_reg[6]);
+ cx18_av_write4(cx, CXADEC_CHROMA_VBIOFF_CFG, saved_reg[7]);
+ }
+
+ return retval;
+}
+
+int cx18_av_and_or_no_acfg(struct cx18 *cx, u16 addr, unsigned and_mask,
+ u8 or_value, int no_acfg_mask)
+{
+ return cx18_av_write_no_acfg(cx, addr,
+ (cx18_av_read(cx, addr) & and_mask) |
+ or_value, no_acfg_mask);
+}
+
/* ----------------------------------------------------------------------- */
static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
@@ -170,26 +222,30 @@ static void input_change(struct cx18 *cx)
/* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */
if (std & V4L2_STD_SECAM)
- cx18_av_write(cx, 0x402, 0);
+ cx18_av_write_no_acfg(cx, 0x402, 0, CXADEC_NO_ACFG_ALL);
else {
- cx18_av_write(cx, 0x402, 0x04);
+ cx18_av_write_no_acfg(cx, 0x402, 0x04, CXADEC_NO_ACFG_ALL);
cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
}
- cx18_av_and_or(cx, 0x401, ~0x60, 0);
- cx18_av_and_or(cx, 0x401, ~0x60, 0x60);
+ cx18_av_and_or_no_acfg(cx, 0x401, ~0x60, 0,
+ CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
+ cx18_av_and_or_no_acfg(cx, 0x401, ~0x60, 0x60,
+ CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
if (std & V4L2_STD_525_60) {
if (std == V4L2_STD_NTSC_M_JP) {
/* Japan uses EIAJ audio standard */
cx18_av_write(cx, 0x808, 0xf7);
+ cx18_av_write(cx, 0x80b, 0x02);
} else if (std == V4L2_STD_NTSC_M_KR) {
/* South Korea uses A2 audio standard */
cx18_av_write(cx, 0x808, 0xf8);
+ cx18_av_write(cx, 0x80b, 0x03);
} else {
/* Others use the BTSC audio standard */
cx18_av_write(cx, 0x808, 0xf6);
+ cx18_av_write(cx, 0x80b, 0x01);
}
- cx18_av_write(cx, 0x80b, 0x00);
} else if (std & V4L2_STD_PAL) {
/* Follow tuner change procedure for PAL */
cx18_av_write(cx, 0x808, 0xff);
@@ -226,7 +282,7 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
if ((vid_input & ~0xff0) ||
luma < CX18_AV_SVIDEO_LUMA1 ||
- luma > CX18_AV_SVIDEO_LUMA4 ||
+ luma > CX18_AV_SVIDEO_LUMA8 ||
chroma < CX18_AV_SVIDEO_CHROMA4 ||
chroma > CX18_AV_SVIDEO_CHROMA8) {
CX18_ERR("0x%04x is not a valid video input!\n",
@@ -260,7 +316,8 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
cx18_av_write(cx, 0x103, reg);
/* Set INPUT_MODE to Composite (0) or S-Video (1) */
- cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02);
+ cx18_av_and_or_no_acfg(cx, 0x401, ~0x6, is_composite ? 0 : 0x02,
+ CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID);
/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
@@ -316,12 +373,12 @@ static int set_v4lstd(struct cx18 *cx)
This happens for example with the Yuan MPC622. */
if (fmt >= 4 && fmt < 8) {
/* Set format to NTSC-M */
- cx18_av_and_or(cx, 0x400, ~0xf, 1);
+ cx18_av_and_or_no_acfg(cx, 0x400, ~0xf, 1, CXADEC_NO_ACFG_AFE);
/* Turn off LCOMB */
cx18_av_and_or(cx, 0x47b, ~6, 0);
}
- cx18_av_and_or(cx, 0x400, ~0xf, fmt);
- cx18_av_and_or(cx, 0x403, ~0x3, pal_m);
+ cx18_av_and_or_no_acfg(cx, 0x400, ~0xf, fmt, CXADEC_NO_ACFG_AFE);
+ cx18_av_and_or_no_acfg(cx, 0x403, ~0x3, pal_m, CXADEC_NO_ACFG_ALL);
cx18_av_vbi_setup(cx);
input_change(cx);
return 0;
@@ -741,8 +798,8 @@ static void log_audio_status(struct cx18 *cx)
{
struct cx18_av_state *state = &cx->av_state;
u8 download_ctl = cx18_av_read(cx, 0x803);
- u8 mod_det_stat0 = cx18_av_read(cx, 0x805);
- u8 mod_det_stat1 = cx18_av_read(cx, 0x804);
+ u8 mod_det_stat0 = cx18_av_read(cx, 0x804);
+ u8 mod_det_stat1 = cx18_av_read(cx, 0x805);
u8 audio_config = cx18_av_read(cx, 0x808);
u8 pref_mode = cx18_av_read(cx, 0x809);
u8 afc0 = cx18_av_read(cx, 0x80b);
@@ -760,12 +817,12 @@ static void log_audio_status(struct cx18 *cx)
case 0x12: p = "dual with SAP"; break;
case 0x14: p = "tri with SAP"; break;
case 0xfe: p = "forced mode"; break;
- default: p = "not defined";
+ default: p = "not defined"; break;
}
CX18_INFO("Detected audio mode: %s\n", p);
switch (mod_det_stat1) {
- case 0x00: p = "BTSC"; break;
+ case 0x00: p = "not defined"; break;
case 0x01: p = "EIAJ"; break;
case 0x02: p = "A2-M"; break;
case 0x03: p = "A2-BG"; break;
@@ -779,8 +836,13 @@ static void log_audio_status(struct cx18 *cx)
case 0x0b: p = "NICAM-I"; break;
case 0x0c: p = "NICAM-L"; break;
case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
+ case 0x0e: p = "IF FM Radio"; break;
+ case 0x0f: p = "BTSC"; break;
+ case 0x10: p = "detected chrominance"; break;
+ case 0xfd: p = "unknown audio standard"; break;
+ case 0xfe: p = "forced audio standard"; break;
case 0xff: p = "no detected audio standard"; break;
- default: p = "not defined";
+ default: p = "not defined"; break;
}
CX18_INFO("Detected audio standard: %s\n", p);
CX18_INFO("Audio muted: %s\n",
@@ -789,22 +851,23 @@ static void log_audio_status(struct cx18 *cx)
(download_ctl & 0x10) ? "running" : "stopped");
switch (audio_config >> 4) {
- case 0x00: p = "BTSC"; break;
- case 0x01: p = "EIAJ"; break;
- case 0x02: p = "A2-M"; break;
- case 0x03: p = "A2-BG"; break;
- case 0x04: p = "A2-DK1"; break;
- case 0x05: p = "A2-DK2"; break;
- case 0x06: p = "A2-DK3"; break;
- case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
- case 0x08: p = "AM-L"; break;
- case 0x09: p = "NICAM-BG"; break;
- case 0x0a: p = "NICAM-DK"; break;
- case 0x0b: p = "NICAM-I"; break;
- case 0x0c: p = "NICAM-L"; break;
- case 0x0d: p = "FM radio"; break;
+ case 0x00: p = "undefined"; break;
+ case 0x01: p = "BTSC"; break;
+ case 0x02: p = "EIAJ"; break;
+ case 0x03: p = "A2-M"; break;
+ case 0x04: p = "A2-BG"; break;
+ case 0x05: p = "A2-DK1"; break;
+ case 0x06: p = "A2-DK2"; break;
+ case 0x07: p = "A2-DK3"; break;
+ case 0x08: p = "A1 (6.0 MHz FM Mono)"; break;
+ case 0x09: p = "AM-L"; break;
+ case 0x0a: p = "NICAM-BG"; break;
+ case 0x0b: p = "NICAM-DK"; break;
+ case 0x0c: p = "NICAM-I"; break;
+ case 0x0d: p = "NICAM-L"; break;
+ case 0x0e: p = "FM radio"; break;
case 0x0f: p = "automatic detection"; break;
- default: p = "undefined";
+ default: p = "undefined"; break;
}
CX18_INFO("Configured audio standard: %s\n", p);
@@ -815,12 +878,9 @@ static void log_audio_status(struct cx18 *cx)
case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
case 0x04: p = "STEREO"; break;
- case 0x05: p = "DUAL1 (AB)"; break;
- case 0x06: p = "DUAL2 (AC) (FM)"; break;
- case 0x07: p = "DUAL3 (BC) (FM)"; break;
- case 0x08: p = "DUAL4 (AC) (AM)"; break;
- case 0x09: p = "DUAL5 (BC) (AM)"; break;
- case 0x0a: p = "SAP"; break;
+ case 0x05: p = "DUAL1 (AC)"; break;
+ case 0x06: p = "DUAL2 (BC)"; break;
+ case 0x07: p = "DUAL3 (AB)"; break;
default: p = "undefined";
}
CX18_INFO("Configured audio mode: %s\n", p);
@@ -835,9 +895,11 @@ static void log_audio_status(struct cx18 *cx)
case 0x06: p = "BTSC"; break;
case 0x07: p = "EIAJ"; break;
case 0x08: p = "A2-M"; break;
- case 0x09: p = "FM Radio"; break;
+ case 0x09: p = "FM Radio (4.5 MHz)"; break;
+ case 0x0a: p = "FM Radio (5.5 MHz)"; break;
+ case 0x0b: p = "S-Video"; break;
case 0x0f: p = "automatic standard and mode detection"; break;
- default: p = "undefined";
+ default: p = "undefined"; break;
}
CX18_INFO("Configured audio system: %s\n", p);
}
@@ -857,22 +919,24 @@ static void log_audio_status(struct cx18 *cx)
case 5: p = "language AC"; break;
case 6: p = "language BC"; break;
case 7: p = "language AB"; break;
- default: p = "undefined";
+ default: p = "undefined"; break;
}
CX18_INFO("Preferred audio mode: %s\n", p);
if ((audio_config & 0xf) == 0xf) {
- switch ((afc0 >> 2) & 0x1) {
+ switch ((afc0 >> 3) & 0x1) {
case 0: p = "system DK"; break;
case 1: p = "system L"; break;
}
CX18_INFO("Selected 65 MHz format: %s\n", p);
- switch (afc0 & 0x3) {
- case 0: p = "BTSC"; break;
- case 1: p = "EIAJ"; break;
- case 2: p = "A2-M"; break;
- default: p = "undefined";
+ switch (afc0 & 0x7) {
+ case 0: p = "Chroma"; break;
+ case 1: p = "BTSC"; break;
+ case 2: p = "EIAJ"; break;
+ case 3: p = "A2-M"; break;
+ case 4: p = "autodetect"; break;
+ default: p = "undefined"; break;
}
CX18_INFO("Selected 45 MHz format: %s\n", p);
}
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h
index 786901d72e9a..c172823ce1d8 100644
--- a/drivers/media/video/cx18/cx18-av-core.h
+++ b/drivers/media/video/cx18/cx18-av-core.h
@@ -37,12 +37,16 @@ enum cx18_av_video_input {
CX18_AV_COMPOSITE7,
CX18_AV_COMPOSITE8,
- /* S-Video inputs consist of one luma input (In1-In4) ORed with one
+ /* S-Video inputs consist of one luma input (In1-In8) ORed with one
chroma input (In5-In8) */
CX18_AV_SVIDEO_LUMA1 = 0x10,
CX18_AV_SVIDEO_LUMA2 = 0x20,
CX18_AV_SVIDEO_LUMA3 = 0x30,
CX18_AV_SVIDEO_LUMA4 = 0x40,
+ CX18_AV_SVIDEO_LUMA5 = 0x50,
+ CX18_AV_SVIDEO_LUMA6 = 0x60,
+ CX18_AV_SVIDEO_LUMA7 = 0x70,
+ CX18_AV_SVIDEO_LUMA8 = 0x80,
CX18_AV_SVIDEO_CHROMA4 = 0x400,
CX18_AV_SVIDEO_CHROMA5 = 0x500,
CX18_AV_SVIDEO_CHROMA6 = 0x600,
@@ -291,14 +295,24 @@ struct cx18_av_state {
#define CXADEC_SELECT_AUDIO_STANDARD_FM 0xF9 /* FM radio */
#define CXADEC_SELECT_AUDIO_STANDARD_AUTO 0xFF /* Auto detect */
+/* Flags on what to preserve on write to 0x400-0x403 with cx18_av_.*_no_acfg()*/
+#define CXADEC_NO_ACFG_AFE 0x01 /* Preserve 0x100-0x107 */
+#define CXADEC_NO_ACFG_PLL 0x02 /* Preserve 0x108-0x10f */
+#define CXADEC_NO_ACFG_VID 0x04 /* Preserve 0x470-0x47f */
+#define CXADEC_NO_ACFG_ALL 0x07
+
/* ----------------------------------------------------------------------- */
/* cx18_av-core.c */
int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value);
+int cx18_av_write_no_acfg(struct cx18 *cx, u16 addr, u8 value,
+ int no_acfg_mask);
u8 cx18_av_read(struct cx18 *cx, u16 addr);
u32 cx18_av_read4(struct cx18 *cx, u16 addr);
int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
+int cx18_av_and_or_no_acfg(struct cx18 *cx, u16 addr, unsigned mask, u8 value,
+ int no_acfg_mask);
int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index 553adbf2cd44..c26e0ef5b075 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -23,6 +23,7 @@
#include "cx18-driver.h"
#include "cx18-cards.h"
+#include "cx18-av-core.h"
#include "cx18-i2c.h"
#include <media/cs5345.h>
@@ -54,22 +55,22 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
.hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER |
CX18_HW_CS5345 | CX18_HW_DVB,
.video_inputs = {
- { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 },
- { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 },
- { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
- { CX18_CARD_INPUT_SVIDEO2, 2, CX23418_SVIDEO2 },
- { CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 },
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 },
+ { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 },
+ { CX18_CARD_INPUT_SVIDEO2, 2, CX18_AV_SVIDEO2 },
+ { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 },
},
.audio_inputs = {
{ CX18_CARD_INPUT_AUD_TUNER,
- CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
+ CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
{ CX18_CARD_INPUT_LINE_IN1,
- CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+ CX18_AV_AUDIO_SERIAL, CS5345_IN_2 },
{ CX18_CARD_INPUT_LINE_IN2,
- CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+ CX18_AV_AUDIO_SERIAL, CS5345_IN_3 },
},
.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
- CX23418_AUDIO_SERIAL, 0 },
+ CX18_AV_AUDIO_SERIAL, CS5345_IN_4 },
.ddr = {
/* ESMT M13S128324A-5B memory */
.chip_config = 0x003,
@@ -81,6 +82,11 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
},
.gpio_init.initial_value = 0x3001,
.gpio_init.direction = 0x3001,
+ .gpio_i2c_slave_reset = {
+ .active_lo_mask = 0x3001,
+ .msecs_asserted = 10,
+ .msecs_recovery = 40,
+ },
.i2c = &cx18_i2c_std,
};
@@ -94,22 +100,22 @@ static const struct cx18_card cx18_card_hvr1600_samsung = {
.hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER |
CX18_HW_CS5345 | CX18_HW_DVB,
.video_inputs = {
- { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 },
- { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 },
- { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
- { CX18_CARD_INPUT_SVIDEO2, 2, CX23418_SVIDEO2 },
- { CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 },
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 },
+ { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 },
+ { CX18_CARD_INPUT_SVIDEO2, 2, CX18_AV_SVIDEO2 },
+ { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 },
},
.audio_inputs = {
{ CX18_CARD_INPUT_AUD_TUNER,
- CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
+ CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
{ CX18_CARD_INPUT_LINE_IN1,
- CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+ CX18_AV_AUDIO_SERIAL, CS5345_IN_2 },
{ CX18_CARD_INPUT_LINE_IN2,
- CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+ CX18_AV_AUDIO_SERIAL, CS5345_IN_3 },
},
.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
- CX23418_AUDIO_SERIAL, 0 },
+ CX18_AV_AUDIO_SERIAL, CS5345_IN_4 },
.ddr = {
/* Samsung K4D263238G-VC33 memory */
.chip_config = 0x003,
@@ -121,12 +127,17 @@ static const struct cx18_card cx18_card_hvr1600_samsung = {
},
.gpio_init.initial_value = 0x3001,
.gpio_init.direction = 0x3001,
+ .gpio_i2c_slave_reset = {
+ .active_lo_mask = 0x3001,
+ .msecs_asserted = 10,
+ .msecs_recovery = 40,
+ },
.i2c = &cx18_i2c_std,
};
/* ------------------------------------------------------------------------- */
-/* Compro VideoMate H900: not working at the moment! */
+/* Compro VideoMate H900: note that this card is analog only! */
static const struct cx18_card_pci_info cx18_pci_h900[] = {
{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_COMPRO, 0xe100 },
@@ -136,24 +147,24 @@ static const struct cx18_card_pci_info cx18_pci_h900[] = {
static const struct cx18_card cx18_card_h900 = {
.type = CX18_CARD_COMPRO_H900,
.name = "Compro VideoMate H900",
- .comment = "DVB & VBI are not yet supported\n",
+ .comment = "VBI is not yet supported\n",
.v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_CX23418,
.hw_all = CX18_HW_TUNER,
.video_inputs = {
- { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE2 },
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
{ CX18_CARD_INPUT_SVIDEO1, 1,
- CX23418_SVIDEO_LUMA3 | CX23418_SVIDEO_CHROMA4 },
- { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE1 },
+ CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
},
.audio_inputs = {
{ CX18_CARD_INPUT_AUD_TUNER,
- CX23418_AUDIO8, 0 },
+ CX18_AV_AUDIO8, 0 },
{ CX18_CARD_INPUT_LINE_IN1,
- CX23418_AUDIO_SERIAL, 0 },
+ CX18_AV_AUDIO_SERIAL, 0 },
},
.radio_input = { CX18_CARD_INPUT_AUD_TUNER,
- CX23418_AUDIO_SERIAL, 0 },
+ CX18_AV_AUDIO_SERIAL, 0 },
.tuners = {
{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
},
@@ -183,23 +194,26 @@ static const struct cx18_card_pci_info cx18_pci_mpc718[] = {
static const struct cx18_card cx18_card_mpc718 = {
.type = CX18_CARD_YUAN_MPC718,
.name = "Yuan MPC718",
- .comment = "Not yet supported!\n",
- .v4l2_capabilities = 0,
+ .comment = "Some Composite and S-Video inputs are currently working.\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_CX23418,
.hw_all = CX18_HW_TUNER,
.video_inputs = {
- { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 },
- { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 },
- { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
+ { CX18_CARD_INPUT_SVIDEO1, 1,
+ CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
+ { CX18_CARD_INPUT_SVIDEO2, 2,
+ CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 },
+ { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 },
+ { CX18_CARD_INPUT_COMPOSITE3, 2, CX18_AV_COMPOSITE3 },
},
.audio_inputs = {
- { CX18_CARD_INPUT_AUD_TUNER,
- CX23418_AUDIO8, 0 },
- { CX18_CARD_INPUT_LINE_IN1,
- CX23418_AUDIO_SERIAL, 0 },
+ { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 },
+ { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL, 0 },
+ { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL, 0 },
},
- .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
- CX23418_AUDIO_SERIAL, 0 },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL, 0 },
.tuners = {
/* XC3028 tuner */
{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
index bccb67f0db16..dc2dd945d4c3 100644
--- a/drivers/media/video/cx18/cx18-cards.h
+++ b/drivers/media/video/cx18/cx18-cards.h
@@ -36,36 +36,6 @@
#define CX18_CARD_INPUT_COMPOSITE2 5
#define CX18_CARD_INPUT_COMPOSITE3 6
-enum cx34180_video_input {
- /* Composite video inputs In1-In8 */
- CX23418_COMPOSITE1 = 1,
- CX23418_COMPOSITE2,
- CX23418_COMPOSITE3,
- CX23418_COMPOSITE4,
- CX23418_COMPOSITE5,
- CX23418_COMPOSITE6,
- CX23418_COMPOSITE7,
- CX23418_COMPOSITE8,
-
- /* S-Video inputs consist of one luma input (In1-In4) ORed with one
- chroma input (In5-In8) */
- CX23418_SVIDEO_LUMA1 = 0x10,
- CX23418_SVIDEO_LUMA2 = 0x20,
- CX23418_SVIDEO_LUMA3 = 0x30,
- CX23418_SVIDEO_LUMA4 = 0x40,
- CX23418_SVIDEO_CHROMA4 = 0x400,
- CX23418_SVIDEO_CHROMA5 = 0x500,
- CX23418_SVIDEO_CHROMA6 = 0x600,
- CX23418_SVIDEO_CHROMA7 = 0x700,
- CX23418_SVIDEO_CHROMA8 = 0x800,
-
- /* S-Video aliases for common luma/chroma combinations */
- CX23418_SVIDEO1 = 0x510,
- CX23418_SVIDEO2 = 0x620,
- CX23418_SVIDEO3 = 0x730,
- CX23418_SVIDEO4 = 0x840,
-};
-
/* audio inputs */
#define CX18_CARD_INPUT_AUD_TUNER 1
#define CX18_CARD_INPUT_LINE_IN1 2
@@ -75,16 +45,6 @@ enum cx34180_video_input {
#define CX18_CARD_MAX_AUDIO_INPUTS 3
#define CX18_CARD_MAX_TUNERS 2
-enum cx23418_audio_input {
- /* Audio inputs: serial or In4-In8 */
- CX23418_AUDIO_SERIAL,
- CX23418_AUDIO4 = 4,
- CX23418_AUDIO5,
- CX23418_AUDIO6,
- CX23418_AUDIO7,
- CX23418_AUDIO8,
-};
-
/* V4L2 capability aliases */
#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
V4L2_CAP_AUDIO | V4L2_CAP_READWRITE)
@@ -118,6 +78,13 @@ struct cx18_gpio_init { /* set initial GPIO DIR and OUT values */
u32 initial_value;
};
+struct cx18_gpio_i2c_slave_reset {
+ u32 active_lo_mask; /* GPIO outputs that reset i2c chips when low */
+ u32 active_hi_mask; /* GPIO outputs that reset i2c chips when high */
+ int msecs_asserted; /* time period reset must remain asserted */
+ int msecs_recovery; /* time after deassert for chips to be ready */
+};
+
struct cx18_card_tuner {
v4l2_std_id std; /* standard for which the tuner is suitable */
int tuner; /* tuner ID (from tuner.h) */
@@ -154,7 +121,8 @@ struct cx18_card {
/* GPIO card-specific settings */
u8 xceive_pin; /* XCeive tuner GPIO reset pin */
- struct cx18_gpio_init gpio_init;
+ struct cx18_gpio_init gpio_init;
+ struct cx18_gpio_i2c_slave_reset gpio_i2c_slave_reset;
struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS];
struct cx18_card_tuner_i2c *i2c;
diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c
index 2bdac5ebbb0d..87cf41021665 100644
--- a/drivers/media/video/cx18/cx18-controls.c
+++ b/drivers/media/video/cx18/cx18-controls.c
@@ -159,7 +159,7 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt
{
if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
return -EINVAL;
- if (atomic_read(&cx->capturing) > 0)
+ if (atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
/* First try to allocate sliced VBI buffers if needed. */
@@ -235,7 +235,7 @@ int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg)
CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
struct cx2341x_mpeg_params p = cx->params;
- int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->capturing), arg, cmd);
+ int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), arg, cmd);
if (err)
return err;
@@ -295,7 +295,7 @@ int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg)
CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
return cx2341x_ext_ctrls(&cx->params,
- atomic_read(&cx->capturing), arg, cmd);
+ atomic_read(&cx->ana_capturing), arg, cmd);
return -EINVAL;
}
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 0dd4e0529970..2b810bb2a4c7 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -670,7 +670,7 @@ static int __devinit cx18_probe(struct pci_dev *dev,
cx18_init_power(cx, 1);
cx18_init_memory(cx);
- cx->scb = (struct cx18_scb *)(cx->enc_mem + SCB_OFFSET);
+ cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET);
cx18_init_scb(cx);
cx18_gpio_init(cx);
@@ -751,17 +751,6 @@ static int __devinit cx18_probe(struct pci_dev *dev,
if (cx->options.radio > 0)
cx->v4l2_cap |= V4L2_CAP_RADIO;
- retval = cx18_streams_setup(cx);
- if (retval) {
- CX18_ERR("Error %d setting up streams\n", retval);
- goto free_irq;
- }
- retval = cx18_streams_register(cx);
- if (retval) {
- CX18_ERR("Error %d registering devices\n", retval);
- goto free_streams;
- }
-
if (cx->options.tuner > -1) {
struct tuner_setup setup;
@@ -788,7 +777,16 @@ static int __devinit cx18_probe(struct pci_dev *dev,
are not. */
cx->tuner_std = cx->std;
- cx18_init_on_first_open(cx);
+ retval = cx18_streams_setup(cx);
+ if (retval) {
+ CX18_ERR("Error %d setting up streams\n", retval);
+ goto free_irq;
+ }
+ retval = cx18_streams_register(cx);
+ if (retval) {
+ CX18_ERR("Error %d registering devices\n", retval);
+ goto free_streams;
+ }
CX18_INFO("Initialized card #%d: %s\n", cx->num, cx->card_name);
@@ -889,7 +887,7 @@ static void cx18_remove(struct pci_dev *pci_dev)
/* Stop all captures */
CX18_DEBUG_INFO("Stopping all streams\n");
- if (atomic_read(&cx->capturing) > 0)
+ if (atomic_read(&cx->tot_capturing) > 0)
cx18_stop_all_captures(cx);
/* Interrupts */
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index a2a6c58d12fe..de14ab59a206 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -358,7 +358,7 @@ struct cx18 {
u32 v4l2_cap; /* V4L2 capabilities of card */
u32 hw_flags; /* Hardware description of the board */
unsigned mdl_offset;
- struct cx18_scb *scb; /* pointer to SCB */
+ struct cx18_scb __iomem *scb; /* pointer to SCB */
struct cx18_av_state av_state;
@@ -380,7 +380,8 @@ struct cx18 {
int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */
struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */
unsigned long i_flags; /* global cx18 flags */
- atomic_t capturing; /* count number of active capture streams */
+ atomic_t ana_capturing; /* count number of active analog capture streams */
+ atomic_t tot_capturing; /* total count number of active capture streams */
spinlock_t lock; /* lock access to this struct */
int search_pack_header;
@@ -423,6 +424,10 @@ struct cx18 {
struct mutex i2c_bus_lock[2];
struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];
+ /* gpio */
+ u32 gpio_dir;
+ u32 gpio_val;
+
/* v4l2 and User settings */
/* codec settings */
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
index c9744173f969..cae38985b131 100644
--- a/drivers/media/video/cx18/cx18-dvb.c
+++ b/drivers/media/video/cx18/cx18-dvb.c
@@ -69,11 +69,21 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
struct dvb_demux *demux = feed->demux;
struct cx18_stream *stream = (struct cx18_stream *) demux->priv;
struct cx18 *cx = stream->cx;
- int ret = -EINVAL;
+ int ret;
u32 v;
CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n",
feed->pid, feed->index);
+
+ mutex_lock(&cx->serialize_lock);
+ ret = cx18_init_on_first_open(cx);
+ mutex_unlock(&cx->serialize_lock);
+ if (ret) {
+ CX18_ERR("Failed to initialize firmware starting DVB feed\n");
+ return ret;
+ }
+ ret = -EINVAL;
+
switch (cx->card->type) {
case CX18_CARD_HVR_1600_ESMT:
case CX18_CARD_HVR_1600_SAMSUNG:
@@ -101,6 +111,11 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
if (stream->dvb.feeding++ == 0) {
CX18_DEBUG_INFO("Starting Transport DMA\n");
ret = cx18_start_v4l2_encode_stream(stream);
+ if (ret < 0) {
+ CX18_DEBUG_INFO(
+ "Failed to start Transport DMA\n");
+ stream->dvb.feeding--;
+ }
} else
ret = 0;
mutex_unlock(&stream->dvb.feedlock);
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
index 0b3141db174b..1e537fe04a23 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -318,7 +318,7 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
size_t tot_written = 0;
int single_frame = 0;
- if (atomic_read(&cx->capturing) == 0 && s->id == -1) {
+ if (atomic_read(&cx->ana_capturing) == 0 && s->id == -1) {
/* shouldn't happen */
CX18_DEBUG_WARN("Stream %s not initialized before read\n",
s->name);
@@ -361,7 +361,8 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
cx18_enqueue(s, buf, &s->q_free);
cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5,
s->handle,
- (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
+ (void __iomem *)&cx->scb->cpu_mdl[buf->id] -
+ cx->enc_mem,
1, buf->id, s->buf_size);
} else
cx18_enqueue(s, buf, &s->q_io);
@@ -581,7 +582,7 @@ int cx18_v4l2_close(struct inode *inode, struct file *filp)
cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
/* Select correct audio input (i.e. TV tuner or Line in) */
cx18_audio_set_io(cx);
- if (atomic_read(&cx->capturing) > 0) {
+ if (atomic_read(&cx->ana_capturing) > 0) {
/* Undo video mute */
cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
cx->params.video_mute |
@@ -627,7 +628,7 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
}
if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
- if (atomic_read(&cx->capturing) > 0) {
+ if (atomic_read(&cx->ana_capturing) > 0) {
/* switching to radio while capture is
in progress is not polite */
cx18_release_stream(s);
@@ -694,7 +695,7 @@ int cx18_v4l2_open(struct inode *inode, struct file *filp)
void cx18_mute(struct cx18 *cx)
{
- if (atomic_read(&cx->capturing))
+ if (atomic_read(&cx->ana_capturing))
cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
cx18_find_handle(cx), 1);
CX18_DEBUG_INFO("Mute\n");
@@ -702,7 +703,7 @@ void cx18_mute(struct cx18 *cx)
void cx18_unmute(struct cx18 *cx)
{
- if (atomic_read(&cx->capturing)) {
+ if (atomic_read(&cx->ana_capturing)) {
cx18_msleep_timeout(100, 0);
cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2,
cx18_find_handle(cx), 12);
diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c
index bb8bc86086d0..b302833f6f9d 100644
--- a/drivers/media/video/cx18/cx18-gpio.c
+++ b/drivers/media/video/cx18/cx18-gpio.c
@@ -35,9 +35,6 @@
#define CX18_REG_GPIO_OUT2 0xc78104
#define CX18_REG_GPIO_DIR2 0xc7810c
-static u32 gpio_dir;
-static u32 gpio_val;
-
/*
* HVR-1600 GPIO pins, courtesy of Hauppauge:
*
@@ -49,24 +46,53 @@ static u32 gpio_val;
static void gpio_write(struct cx18 *cx)
{
- write_reg((gpio_dir & 0xffff) << 16, CX18_REG_GPIO_DIR1);
- write_reg(((gpio_dir & 0xffff) << 16) | (gpio_val & 0xffff),
+ u32 dir = cx->gpio_dir;
+ u32 val = cx->gpio_val;
+
+ write_reg((dir & 0xffff) << 16, CX18_REG_GPIO_DIR1);
+ write_reg(((dir & 0xffff) << 16) | (val & 0xffff),
CX18_REG_GPIO_OUT1);
- write_reg(gpio_dir & 0xffff0000, CX18_REG_GPIO_DIR2);
- write_reg((gpio_dir & 0xffff0000) | ((gpio_val & 0xffff0000) >> 16),
+ write_reg(dir & 0xffff0000, CX18_REG_GPIO_DIR2);
+ write_reg_sync((dir & 0xffff0000) | ((val & 0xffff0000) >> 16),
CX18_REG_GPIO_OUT2);
}
-void cx18_gpio_init(struct cx18 *cx)
+void cx18_reset_i2c_slaves_gpio(struct cx18 *cx)
{
- gpio_dir = cx->card->gpio_init.direction;
- gpio_val = cx->card->gpio_init.initial_value;
+ const struct cx18_gpio_i2c_slave_reset *p;
+
+ p = &cx->card->gpio_i2c_slave_reset;
- if (gpio_dir == 0)
+ if ((p->active_lo_mask | p->active_hi_mask) == 0)
return;
- gpio_dir |= 1 << cx->card->xceive_pin;
- gpio_val |= 1 << cx->card->xceive_pin;
+ /* Assuming that the masks are a subset of the bits in gpio_dir */
+
+ /* Assert */
+ cx->gpio_val =
+ (cx->gpio_val | p->active_hi_mask) & ~(p->active_lo_mask);
+ gpio_write(cx);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_asserted));
+
+ /* Deassert */
+ cx->gpio_val =
+ (cx->gpio_val | p->active_lo_mask) & ~(p->active_hi_mask);
+ gpio_write(cx);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(p->msecs_recovery));
+}
+
+void cx18_gpio_init(struct cx18 *cx)
+{
+ cx->gpio_dir = cx->card->gpio_init.direction;
+ cx->gpio_val = cx->card->gpio_init.initial_value;
+
+ if (cx->card->tuners[0].tuner == TUNER_XC2028) {
+ cx->gpio_dir |= 1 << cx->card->xceive_pin;
+ cx->gpio_val |= 1 << cx->card->xceive_pin;
+ }
+
+ if (cx->gpio_dir == 0)
+ return;
CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n",
read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_DIR2),
@@ -86,13 +112,12 @@ int cx18_reset_tuner_gpio(void *dev, int cmd, int value)
return 0;
CX18_DEBUG_INFO("Resetting tuner\n");
- gpio_dir |= 1 << cx->card->xceive_pin;
- gpio_val &= ~(1 << cx->card->xceive_pin);
+ cx->gpio_val &= ~(1 << cx->card->xceive_pin);
gpio_write(cx);
schedule_timeout_interruptible(msecs_to_jiffies(1));
- gpio_val |= 1 << cx->card->xceive_pin;
+ cx->gpio_val |= 1 << cx->card->xceive_pin;
gpio_write(cx);
schedule_timeout_interruptible(msecs_to_jiffies(1));
return 0;
diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h
index 41bac8856b50..525c328f748a 100644
--- a/drivers/media/video/cx18/cx18-gpio.h
+++ b/drivers/media/video/cx18/cx18-gpio.h
@@ -21,4 +21,5 @@
*/
void cx18_gpio_init(struct cx18 *cx);
+void cx18_reset_i2c_slaves_gpio(struct cx18 *cx);
int cx18_reset_tuner_gpio(void *dev, int cmd, int value);
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index 1d6c51a75313..680bc4e35b79 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -405,6 +405,8 @@ int init_cx18_i2c(struct cx18 *cx)
cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
+ cx18_reset_i2c_slaves_gpio(cx);
+
return i2c_bit_add_bus(&cx->i2c_adap[0]) ||
i2c_bit_add_bus(&cx->i2c_adap[1]);
}
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index dbdcb86ec5aa..4151f1e5493f 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -247,7 +247,7 @@ static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype,
if (!set_fmt || (cx->params.width == w && cx->params.height == h))
return 0;
- if (atomic_read(&cx->capturing) > 0)
+ if (atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
cx->params.width = w;
@@ -264,7 +264,7 @@ static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype,
if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI &&
cx->vbi.sliced_in->service_set &&
- atomic_read(&cx->capturing) > 0)
+ atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
if (set_fmt) {
cx->vbi.sliced_in->service_set = 0;
@@ -293,7 +293,7 @@ static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype,
return 0;
if (set == 0)
return -EINVAL;
- if (atomic_read(&cx->capturing) > 0 && cx->vbi.sliced_in->service_set == 0)
+ if (atomic_read(&cx->ana_capturing) > 0 && cx->vbi.sliced_in->service_set == 0)
return -EBUSY;
cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
@@ -581,7 +581,7 @@ int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg
break;
if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
- atomic_read(&cx->capturing) > 0) {
+ atomic_read(&cx->ana_capturing) > 0) {
/* Switching standard would turn off the radio or mess
with already running streams, prevent that by
returning EBUSY. */
@@ -677,7 +677,7 @@ int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg
enc->flags = 0;
if (try)
return 0;
- if (!atomic_read(&cx->capturing))
+ if (!atomic_read(&cx->ana_capturing))
return -EPERM;
if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
return 0;
@@ -689,7 +689,7 @@ int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg
enc->flags = 0;
if (try)
return 0;
- if (!atomic_read(&cx->capturing))
+ if (!atomic_read(&cx->ana_capturing))
return -EPERM;
if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
return 0;
diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c
index 6e14f8bda559..25114a5cbd57 100644
--- a/drivers/media/video/cx18/cx18-irq.c
+++ b/drivers/media/video/cx18/cx18-irq.c
@@ -75,7 +75,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
cx18_buf_sync_for_device(s, buf);
cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
- (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
+ (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
1, buf->id, s->buf_size);
} else
set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
@@ -161,13 +161,15 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id)
*/
if (sw2) {
- if (sw2 & (cx->scb->cpu2hpu_irq_ack | cx->scb->cpu2epu_irq_ack))
+ if (sw2 & (readl(&cx->scb->cpu2hpu_irq_ack) |
+ readl(&cx->scb->cpu2epu_irq_ack)))
wake_up(&cx->mb_cpu_waitq);
- if (sw2 & (cx->scb->apu2hpu_irq_ack | cx->scb->apu2epu_irq_ack))
+ if (sw2 & (readl(&cx->scb->apu2hpu_irq_ack) |
+ readl(&cx->scb->apu2epu_irq_ack)))
wake_up(&cx->mb_apu_waitq);
- if (sw2 & cx->scb->epu2hpu_irq_ack)
+ if (sw2 & readl(&cx->scb->epu2hpu_irq_ack))
wake_up(&cx->mb_epu_waitq);
- if (sw2 & cx->scb->hpu2epu_irq_ack)
+ if (sw2 & readl(&cx->scb->hpu2epu_irq_ack))
wake_up(&cx->mb_hpu_waitq);
}
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index 0c5f328bca54..2a5ccef9185b 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -94,10 +94,10 @@ static const struct cx18_api_info *find_api_info(u32 cmd)
return NULL;
}
-static struct cx18_mailbox *cx18_mb_is_complete(struct cx18 *cx, int rpu,
+static struct cx18_mailbox __iomem *cx18_mb_is_complete(struct cx18 *cx, int rpu,
u32 *state, u32 *irq, u32 *req)
{
- struct cx18_mailbox *mb = NULL;
+ struct cx18_mailbox __iomem *mb = NULL;
int wait_count = 0;
u32 ack;
@@ -142,7 +142,7 @@ static struct cx18_mailbox *cx18_mb_is_complete(struct cx18 *cx, int rpu,
long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb)
{
const struct cx18_api_info *info = find_api_info(mb->cmd);
- struct cx18_mailbox *ack_mb;
+ struct cx18_mailbox __iomem *ack_mb;
u32 ack_irq;
u8 rpu = CPU;
@@ -182,7 +182,7 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
{
const struct cx18_api_info *info = find_api_info(cmd);
u32 state = 0, irq = 0, req, oldreq, err;
- struct cx18_mailbox *mb;
+ struct cx18_mailbox __iomem *mb;
wait_queue_head_t *waitq;
int timeout = 100;
int cnt = 0;
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 4ca9d847f1b1..1b921a336092 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -36,12 +36,13 @@
#define CX18_DSP0_INTERRUPT_MASK 0xd0004C
static struct file_operations cx18_v4l2_enc_fops = {
- .owner = THIS_MODULE,
- .read = cx18_v4l2_read,
- .open = cx18_v4l2_open,
- .ioctl = cx18_v4l2_ioctl,
- .release = cx18_v4l2_close,
- .poll = cx18_v4l2_enc_poll,
+ .owner = THIS_MODULE,
+ .read = cx18_v4l2_read,
+ .open = cx18_v4l2_open,
+ .ioctl = cx18_v4l2_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
+ .release = cx18_v4l2_close,
+ .poll = cx18_v4l2_enc_poll,
};
/* offset from 0 to register ts v4l2 minors on */
@@ -443,7 +444,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
s->handle = data[0];
cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype);
- if (atomic_read(&cx->capturing) == 0 && !ts) {
+ if (atomic_read(&cx->ana_capturing) == 0 && !ts) {
/* Stuff from Windows, we don't know what it is */
cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0);
cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1);
@@ -466,14 +467,14 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
cx2341x_update(cx, cx18_api_func, NULL, &cx->params);
}
- if (atomic_read(&cx->capturing) == 0) {
+ if (atomic_read(&cx->tot_capturing) == 0) {
clear_bit(CX18_F_I_EOS, &cx->i_flags);
write_reg(7, CX18_DSP0_INTERRUPT_MASK);
}
cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle,
- (void *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem,
- (void *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem);
+ (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem,
+ (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem);
list_for_each(p, &s->q_free.list) {
struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list);
@@ -481,8 +482,8 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
writel(buf->dma_handle, &cx->scb->cpu_mdl[buf->id].paddr);
writel(s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
- (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, 1,
- buf->id, s->buf_size);
+ (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
+ 1, buf->id, s->buf_size);
}
/* begin_capture */
if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
@@ -492,7 +493,9 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
}
/* you're live! sit back and await interrupts :) */
- atomic_inc(&cx->capturing);
+ if (!ts)
+ atomic_inc(&cx->ana_capturing);
+ atomic_inc(&cx->tot_capturing);
return 0;
}
@@ -523,7 +526,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
CX18_DEBUG_INFO("Stop Capture\n");
- if (atomic_read(&cx->capturing) == 0)
+ if (atomic_read(&cx->tot_capturing) == 0)
return 0;
if (s->type == CX18_ENC_STREAM_TYPE_MPG)
@@ -537,7 +540,9 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
}
- atomic_dec(&cx->capturing);
+ if (s->type != CX18_ENC_STREAM_TYPE_TS)
+ atomic_dec(&cx->ana_capturing);
+ atomic_dec(&cx->tot_capturing);
/* Clear capture and no-read bits */
clear_bit(CX18_F_S_STREAMING, &s->s_flags);
@@ -545,7 +550,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
s->handle = 0xffffffff;
- if (atomic_read(&cx->capturing) > 0)
+ if (atomic_read(&cx->tot_capturing) > 0)
return 0;
write_reg(5, CX18_DSP0_INTERRUPT_MASK);
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index f24abcd06dea..c4cc2f3b8876 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -823,7 +823,7 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev)
iounmap(dev->lmmio);
}
-static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist,
+static __le32* cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
unsigned int offset, u32 sync_line,
unsigned int bpl, unsigned int padding,
unsigned int lines)
@@ -883,7 +883,7 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
unsigned int padding, unsigned int lines)
{
u32 instructions, fields;
- u32 *rp;
+ __le32 *rp;
int rc;
fields = 0;
@@ -924,7 +924,7 @@ static int cx23885_risc_databuffer(struct pci_dev *pci,
unsigned int lines)
{
u32 instructions;
- u32 *rp;
+ __le32 *rp;
int rc;
/* estimate risc mem: worst case is one write per page border +
@@ -951,7 +951,7 @@ static int cx23885_risc_databuffer(struct pci_dev *pci,
int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
u32 reg, u32 mask, u32 value)
{
- u32 *rp;
+ __le32 *rp;
int rc;
if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 607efdcd22f8..1da6f134888d 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -433,7 +433,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
int chroma = vid_input & 0xf00;
if ((vid_input & ~0xff0) ||
- luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 ||
+ luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA8 ||
chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) {
v4l_err(client, "0x%04x is not a valid video input!\n",
vid_input);
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index e976fc6bef7c..80c8883e54b5 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -332,6 +332,12 @@ static int snd_cx88_pcm_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
int err;
+ if (!chip) {
+ printk(KERN_ERR "BUG: cx88 can't find device struct."
+ " Can't proceed with open\n");
+ return -ENODEV;
+ }
+
err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS);
if (err < 0)
goto _error;
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index aeba26dc0a37..fa6d398e97b9 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -1493,10 +1493,16 @@ static const struct cx88_board cx88_boards[] = {
},
},
[CX88_BOARD_POWERCOLOR_REAL_ANGEL] = {
- .name = "PowerColor Real Angel 330",
+ .name = "PowerColor RA330", /* Long names may confuse LIRC. */
.tuner_type = TUNER_XC2028,
.tuner_addr = 0x61,
.input = { {
+ .type = CX88_VMUX_DEBUG,
+ .vmux = 3, /* Due to the way the cx88 driver is written, */
+ .gpio0 = 0x00ff, /* there is no way to deactivate audio pass- */
+ .gpio1 = 0xf39d, /* through without this entry. Furthermore, if */
+ .gpio3 = 0x0000, /* the TV mux entry is first, you get audio */
+ }, { /* from the tuner on boot for a little while. */
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x00ff,
@@ -2424,8 +2430,9 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl)
switch (core->boardnr) {
case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
- /* Doesn't work with firmware version 2.7 */
- ctl->fname = "xc3028-v25.fw";
+ /* Now works with firmware version 2.7 */
+ if (core->i2c_algo.udelay < 16)
+ core->i2c_algo.udelay = 16;
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
ctl->scode_table = XC3028_FE_ZARLINK456;
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index c4d1aff1fdb4..60eeda3057e9 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -70,7 +70,7 @@ static DEFINE_MUTEX(devlist);
/* @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be
generated _after_ lpi lines are transferred. */
-static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
+static __le32* cx88_risc_field(__le32 *rp, struct scatterlist *sglist,
unsigned int offset, u32 sync_line,
unsigned int bpl, unsigned int padding,
unsigned int lines, unsigned int lpi)
@@ -130,7 +130,7 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
unsigned int bpl, unsigned int padding, unsigned int lines)
{
u32 instructions,fields;
- u32 *rp;
+ __le32 *rp;
int rc;
fields = 0;
@@ -168,7 +168,7 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
unsigned int lines, unsigned int lpi)
{
u32 instructions;
- u32 *rp;
+ __le32 *rp;
int rc;
/* estimate risc mem: worst case is one write per page border +
@@ -193,7 +193,7 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
u32 reg, u32 mask, u32 value)
{
- u32 *rp;
+ __le32 *rp;
int rc;
if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
index 92b2a6db4fdc..3c006103c1eb 100644
--- a/drivers/media/video/em28xx/em28xx-audio.c
+++ b/drivers/media/video/em28xx/em28xx-audio.c
@@ -268,6 +268,12 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
dprintk("opening device and trying to acquire exclusive lock\n");
+ if (!dev) {
+ printk(KERN_ERR "BUG: em28xx can't find device struct."
+ " Can't proceed with open\n");
+ return -ENODEV;
+ }
+
/* Sets volume, mute, etc */
dev->mute = 0;
@@ -415,6 +421,12 @@ static int em28xx_audio_init(struct em28xx *dev)
static int devnr;
int ret, err;
+ if (dev->has_audio_class) {
+ /* This device does not support the extension (in this case
+ the device is expecting the snd-usb-audio module */
+ return 0;
+ }
+
printk(KERN_INFO "em28xx-audio.c: probing for em28x1 "
"non standard usbaudio\n");
printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
@@ -458,6 +470,12 @@ static int em28xx_audio_fini(struct em28xx *dev)
if (dev == NULL)
return 0;
+ if (dev->has_audio_class) {
+ /* This device does not support the extension (in this case
+ the device is expecting the snd-usb-audio module */
+ return 0;
+ }
+
if (dev->adev) {
snd_card_free(dev->adev->sndcard);
kfree(dev->adev);
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 3e4f3c7e92e7..8cbda43727c3 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -157,6 +157,7 @@ struct em28xx_board em28xx_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.tuner_type = TUNER_XC2028,
.mts_firmware = 1,
+ .has_dvb = 1,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -524,6 +525,9 @@ void em28xx_pre_card_setup(struct em28xx *dev)
rc = em28xx_read_reg(dev, EM28XX_R0A_CHIPID);
if (rc > 0) {
switch (rc) {
+ case CHIP_ID_EM2860:
+ em28xx_info("chip ID is em2860\n");
+ break;
case CHIP_ID_EM2883:
em28xx_info("chip ID is em2882/em2883\n");
dev->wait_after_write = 0;
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index 8cf4983f0039..0b2333ee07f8 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -382,6 +382,11 @@ static int dvb_init(struct em28xx *dev)
int result = 0;
struct em28xx_dvb *dvb;
+ if (!dev->has_dvb) {
+ /* This device does not support the extension */
+ return 0;
+ }
+
dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
if (dvb == NULL) {
@@ -444,6 +449,11 @@ out_free:
static int dvb_fini(struct em28xx *dev)
{
+ if (!dev->has_dvb) {
+ /* This device does not support the extension */
+ return 0;
+ }
+
if (dev->dvb) {
unregister_dvb(dev->dvb);
dev->dvb = NULL;
diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h
index 9058bed07953..fac1ab23f621 100644
--- a/drivers/media/video/em28xx/em28xx-reg.h
+++ b/drivers/media/video/em28xx/em28xx-reg.h
@@ -84,5 +84,6 @@
/* FIXME: Need to be populated with the other chip ID's */
enum em28xx_chip_id {
+ CHIP_ID_EM2860 = 34,
CHIP_ID_EM2883 = 36,
};
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 8996175cc950..285bc62bbe46 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -1166,13 +1166,13 @@ static int vidioc_g_register(struct file *file, void *priv,
reg->val = ret;
} else {
- u64 val = 0;
+ __le64 val = 0;
ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
reg->reg, (char *)&val, 2);
if (ret < 0)
return ret;
- reg->val = cpu_to_le64((__u64)val);
+ reg->val = le64_to_cpu(val);
}
return 0;
@@ -1183,9 +1183,9 @@ static int vidioc_s_register(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- u64 buf;
+ __le64 buf;
- buf = le64_to_cpu((__u64)reg->val);
+ buf = cpu_to_le64(reg->val);
return em28xx_write_regs(dev, reg->reg, (char *)&buf,
em28xx_reg_len(reg->reg));
@@ -1848,32 +1848,28 @@ static DEFINE_MUTEX(em28xx_extension_devlist_lock);
int em28xx_register_extension(struct em28xx_ops *ops)
{
- struct em28xx *h, *dev = NULL;
-
- list_for_each_entry(h, &em28xx_devlist, devlist)
- dev = h;
+ struct em28xx *dev = NULL;
mutex_lock(&em28xx_extension_devlist_lock);
list_add_tail(&ops->next, &em28xx_extension_devlist);
- if (dev)
- ops->init(dev);
-
+ list_for_each_entry(dev, &em28xx_devlist, devlist) {
+ if (dev)
+ ops->init(dev);
+ }
printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
mutex_unlock(&em28xx_extension_devlist_lock);
-
return 0;
}
EXPORT_SYMBOL(em28xx_register_extension);
void em28xx_unregister_extension(struct em28xx_ops *ops)
{
- struct em28xx *h, *dev = NULL;
-
- list_for_each_entry(h, &em28xx_devlist, devlist)
- dev = h;
+ struct em28xx *dev = NULL;
- if (dev)
- ops->fini(dev);
+ list_for_each_entry(dev, &em28xx_devlist, devlist) {
+ if (dev)
+ ops->fini(dev);
+ }
mutex_lock(&em28xx_extension_devlist_lock);
printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index ba06e813c58c..9d23b1efd36d 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -259,6 +259,12 @@ struct ivtv_mailbox_data {
/* Scatter-Gather array element, used in DMA transfers */
struct ivtv_sg_element {
+ __le32 src;
+ __le32 dst;
+ __le32 size;
+};
+
+struct ivtv_sg_host_element {
u32 src;
u32 dst;
u32 size;
@@ -349,8 +355,8 @@ struct ivtv_stream {
u16 dma_xfer_cnt;
/* Base Dev SG Array for cx23415/6 */
- struct ivtv_sg_element *sg_pending;
- struct ivtv_sg_element *sg_processing;
+ struct ivtv_sg_host_element *sg_pending;
+ struct ivtv_sg_host_element *sg_processing;
struct ivtv_sg_element *sg_dma;
dma_addr_t sg_handle;
int sg_pending_size;
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index f2fa434b677b..db813e071ce6 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -587,7 +587,7 @@ retry:
since we may get here before the stream has been fully set-up */
if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) {
while (count >= itv->dma_data_req_size) {
- if (!ivtv_yuv_udma_stream_frame (itv, (void *)user_buf)) {
+ if (!ivtv_yuv_udma_stream_frame (itv, (void __user *)user_buf)) {
bytes_written += itv->dma_data_req_size;
user_buf += itv->dma_data_req_size;
count -= itv->dma_data_req_size;
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index d8ba3a4a8761..fba150a6cd23 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -231,14 +231,14 @@ static void dma_post(struct ivtv_stream *s)
struct ivtv_buffer *buf = NULL;
struct list_head *p;
u32 offset;
- u32 *u32buf;
+ __le32 *u32buf;
int x = 0;
IVTV_DEBUG_HI_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
s->name, s->dma_offset);
list_for_each(p, &s->q_dma.list) {
buf = list_entry(p, struct ivtv_buffer, list);
- u32buf = (u32 *)buf->buf;
+ u32buf = (__le32 *)buf->buf;
/* Sync Buffer */
ivtv_buf_sync_for_cpu(s, buf);
@@ -444,7 +444,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
}
s->dma_xfer_cnt++;
- memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size);
+ memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size);
s->sg_processing_size = s->sg_pending_size;
s->sg_pending_size = 0;
s->sg_processed = 0;
@@ -473,7 +473,7 @@ static void ivtv_dma_dec_start(struct ivtv_stream *s)
if (s->q_predma.bytesused)
ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
s->dma_xfer_cnt++;
- memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size);
+ memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_host_element) * s->sg_pending_size);
s->sg_processing_size = s->sg_pending_size;
s->sg_pending_size = 0;
s->sg_processed = 0;
diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c
index fc8b1eaa333b..71bd13e22e2e 100644
--- a/drivers/media/video/ivtv/ivtv-queue.c
+++ b/drivers/media/video/ivtv/ivtv-queue.c
@@ -193,7 +193,7 @@ void ivtv_flush_queues(struct ivtv_stream *s)
int ivtv_stream_alloc(struct ivtv_stream *s)
{
struct ivtv *itv = s->itv;
- int SGsize = sizeof(struct ivtv_sg_element) * s->buffers;
+ int SGsize = sizeof(struct ivtv_sg_host_element) * s->buffers;
int i;
if (s->buffers == 0)
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index c47c2b945147..c854285a4371 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -44,23 +44,25 @@
#include "ivtv-streams.h"
static const struct file_operations ivtv_v4l2_enc_fops = {
- .owner = THIS_MODULE,
- .read = ivtv_v4l2_read,
- .write = ivtv_v4l2_write,
- .open = ivtv_v4l2_open,
- .ioctl = ivtv_v4l2_ioctl,
- .release = ivtv_v4l2_close,
- .poll = ivtv_v4l2_enc_poll,
+ .owner = THIS_MODULE,
+ .read = ivtv_v4l2_read,
+ .write = ivtv_v4l2_write,
+ .open = ivtv_v4l2_open,
+ .ioctl = ivtv_v4l2_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
+ .release = ivtv_v4l2_close,
+ .poll = ivtv_v4l2_enc_poll,
};
static const struct file_operations ivtv_v4l2_dec_fops = {
- .owner = THIS_MODULE,
- .read = ivtv_v4l2_read,
- .write = ivtv_v4l2_write,
- .open = ivtv_v4l2_open,
- .ioctl = ivtv_v4l2_ioctl,
- .release = ivtv_v4l2_close,
- .poll = ivtv_v4l2_dec_poll,
+ .owner = THIS_MODULE,
+ .read = ivtv_v4l2_read,
+ .write = ivtv_v4l2_write,
+ .open = ivtv_v4l2_open,
+ .ioctl = ivtv_v4l2_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
+ .release = ivtv_v4l2_close,
+ .poll = ivtv_v4l2_dec_poll,
};
#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */
diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h
index 02c5ab071d1b..442f43f11b73 100644
--- a/drivers/media/video/ivtv/ivtv-version.h
+++ b/drivers/media/video/ivtv/ivtv-version.h
@@ -22,8 +22,8 @@
#define IVTV_DRIVER_NAME "ivtv"
#define IVTV_DRIVER_VERSION_MAJOR 1
-#define IVTV_DRIVER_VERSION_MINOR 2
-#define IVTV_DRIVER_VERSION_PATCHLEVEL 1
+#define IVTV_DRIVER_VERSION_MINOR 3
+#define IVTV_DRIVER_VERSION_PATCHLEVEL 0
#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
#define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL)
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
index a9417f6e4087..3092ff1d00a0 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/drivers/media/video/ivtv/ivtv-yuv.c
@@ -1116,7 +1116,7 @@ void ivtv_yuv_setup_stream_frame(struct ivtv *itv)
}
/* Attempt to dma a frame from a user buffer */
-int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src)
+int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src)
{
struct yuv_playback_info *yi = &itv->yuv_info;
struct ivtv_dma_frame dma_args;
diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h
index 2fe5f1250762..ca5173fbf006 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.h
+++ b/drivers/media/video/ivtv/ivtv-yuv.h
@@ -35,7 +35,7 @@ extern const u32 yuv_offset[IVTV_YUV_BUFFERS];
int ivtv_yuv_filter_check(struct ivtv *itv);
void ivtv_yuv_setup_stream_frame(struct ivtv *itv);
-int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src);
+int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void __user *src);
void ivtv_yuv_frame_complete(struct ivtv *itv);
int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args);
void ivtv_yuv_close(struct ivtv *itv);
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
index 2bc6bdc9c1f2..d7bfd30f74a9 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/video/ov7670.c
@@ -406,8 +406,10 @@ static int ov7670_read(struct i2c_client *c, unsigned char reg,
int ret;
ret = i2c_smbus_read_byte_data(c, reg);
- if (ret >= 0)
+ if (ret >= 0) {
*value = (unsigned char) ret;
+ ret = 0;
+ }
return ret;
}
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 7cc8e9b19fb7..5ec5bb9a94d2 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -1019,12 +1019,12 @@ static int pxa_camera_probe(struct platform_device *pdev)
struct pxa_camera_dev *pcdev;
struct resource *res;
void __iomem *base;
- unsigned int irq;
+ int irq;
int err = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
- if (!res || !irq) {
+ if (!res || irq < 0) {
err = -ENODEV;
goto exit;
}
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index ba3082422a01..f118de6e3672 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -613,9 +613,15 @@ static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream)
struct snd_pcm_runtime *runtime = substream->runtime;
snd_card_saa7134_pcm_t *pcm;
snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
- struct saa7134_dev *dev = saa7134->dev;
+ struct saa7134_dev *dev;
int amux, err;
+ if (!saa7134) {
+ printk(KERN_ERR "BUG: saa7134 can't find device struct."
+ " Can't proceed with open\n");
+ return -ENODEV;
+ }
+ dev = saa7134->dev;
mutex_lock(&dev->dmasound.lock);
dev->dmasound.read_count = 0;
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index b111903aa322..2618cfa592e7 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -4114,11 +4114,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- /*
- TODO:
.mpeg = SAA7134_MPEG_DVB,
- */
-
.inputs = {{
.name = name_tv,
.vmux = 1,
@@ -4157,7 +4153,7 @@ struct saa7134_board saa7134_boards[] = {
} },
.radio = {
.name = name_radio,
- .amux = LINE1,
+ .amux = TV,
},
},
[SAA7134_BOARD_AVERMEDIA_M115] = {
@@ -4167,6 +4163,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
.inputs = {{
.name = name_tv,
.vmux = 1,
@@ -5351,22 +5348,21 @@ static int saa7134_xc2028_callback(struct saa7134_dev *dev,
{
switch (command) {
case XC2028_TUNER_RESET:
- saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0x06e20000);
- saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0x06a20000);
- mdelay(250);
- saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0);
- saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0);
- mdelay(250);
- saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0x06e20000);
- saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0x06a20000);
- mdelay(250);
- saa_andorl(SAA7133_ANALOG_IO_SELECT >> 2, 0x02, 0x02);
- saa_andorl(SAA7134_ANALOG_IN_CTRL1 >> 2, 0x81, 0x81);
- saa_andorl(SAA7134_AUDIO_CLOCK0 >> 2, 0x03187de7, 0x03187de7);
- saa_andorl(SAA7134_AUDIO_PLL_CTRL >> 2, 0x03, 0x03);
- saa_andorl(SAA7134_AUDIO_CLOCKS_PER_FIELD0 >> 2,
- 0x0001e000, 0x0001e000);
- return 0;
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00000000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000);
+ switch (dev->board) {
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+ saa7134_set_gpio(dev, 23, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 23, 1);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ saa7134_set_gpio(dev, 21, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 21, 1);
+ break;
+ }
+ return 0;
}
return -EINVAL;
}
@@ -5553,9 +5549,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000);
break;
case SAA7134_BOARD_AVERMEDIA_CARDBUS:
- case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
case SAA7134_BOARD_AVERMEDIA_M115:
- case SAA7134_BOARD_AVERMEDIA_A16D:
/* power-down tuner chip */
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0);
@@ -5565,6 +5559,18 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
msleep(10);
break;
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+ saa7134_set_gpio(dev, 23, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 23, 1);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ saa7134_set_gpio(dev, 21, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 21, 1);
+ msleep(1);
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ break;
case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
/* power-down tuner chip */
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x000A8004, 0x000A8004);
@@ -5615,7 +5621,8 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x80040100, 0x80040100);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
printk("%s: %s: hybrid analog/dvb card\n"
- "%s: Sorry, only the analog inputs are supported for now.\n",
+ "%s: Sorry, only analog s-video and composite input "
+ "are supported for now.\n",
dev->name, card(dev).name, dev->name);
break;
}
@@ -5675,6 +5682,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev)
switch (dev->board) {
case SAA7134_BOARD_AVERMEDIA_A16D:
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
ctl.demod = XC3028_FE_ZARLINK456;
break;
default:
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 469f93aac008..341b101b0357 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -153,12 +153,12 @@ static int mt352_aver777_init(struct dvb_frontend* fe)
return 0;
}
-static int mt352_aver_a16d_init(struct dvb_frontend *fe)
+static int mt352_avermedia_xc3028_init(struct dvb_frontend *fe)
{
- static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x2d };
- static u8 reset [] = { RESET, 0x80 };
- static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
- static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0xa0 };
+ static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x2d };
+ static u8 reset [] = { RESET, 0x80 };
+ static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+ static u8 agc_cfg [] = { AGC_TARGET, 0xe };
static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 };
mt352_write(fe, clock_config, sizeof(clock_config));
@@ -167,12 +167,9 @@ static int mt352_aver_a16d_init(struct dvb_frontend *fe)
mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
mt352_write(fe, agc_cfg, sizeof(agc_cfg));
mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
-
return 0;
}
-
-
static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
struct dvb_frontend_parameters* params)
{
@@ -215,14 +212,10 @@ static struct mt352_config avermedia_777 = {
.demod_init = mt352_aver777_init,
};
-static struct mt352_config avermedia_16d = {
- .demod_address = 0xf,
- .demod_init = mt352_aver_a16d_init,
-};
-
-static struct mt352_config avermedia_e506r_mt352_dev = {
+static struct mt352_config avermedia_xc3028_mt352_dev = {
.demod_address = (0x1e >> 1),
.no_tuner = 1,
+ .demod_init = mt352_avermedia_xc3028_init,
};
/* ==================================================================
@@ -975,9 +968,10 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_AVERMEDIA_A16D:
- dprintk("avertv A16D dvb setup\n");
- dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_16d,
- &dev->i2c_adap);
+ dprintk("AverMedia A16D dvb setup\n");
+ dev->dvb.frontend = dvb_attach(mt352_attach,
+ &avermedia_xc3028_mt352_dev,
+ &dev->i2c_adap);
attach_xc3028 = 1;
break;
case SAA7134_BOARD_MD7134:
@@ -1091,7 +1085,8 @@ static int dvb_init(struct saa7134_dev *dev)
ads_tech_duo_config.tuner_address);
goto dettach_frontend;
}
- }
+ } else
+ wprintk("failed to attach tda10046\n");
break;
case SAA7134_BOARD_TEVION_DVBT_220RF:
if (configure_tda827x_fe(dev, &tevion_dvbt220rf_config,
@@ -1260,11 +1255,14 @@ static int dvb_init(struct saa7134_dev *dev)
goto dettach_frontend;
break;
case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+ dprintk("AverMedia E506R dvb setup\n");
+ saa7134_set_gpio(dev, 25, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 25, 1);
dev->dvb.frontend = dvb_attach(mt352_attach,
- &avermedia_e506r_mt352_dev,
- &dev->i2c_adap);
+ &avermedia_xc3028_mt352_dev,
+ &dev->i2c_adap);
attach_xc3028 = 1;
- break;
case SAA7134_BOARD_MD7134_BRIDGE_2:
dev->dvb.frontend = dvb_attach(tda10086_attach,
&sd1878_4m, &dev->i2c_adap);
@@ -1338,7 +1336,8 @@ static int dvb_init(struct saa7134_dev *dev)
return ret;
dettach_frontend:
- dvb_frontend_detach(dev->dvb.frontend);
+ if (dev->dvb.frontend)
+ dvb_frontend_detach(dev->dvb.frontend);
dev->dvb.frontend = NULL;
return -1;
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index 1314522a8130..3ae71a340822 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -110,9 +110,10 @@ static int ts_release(struct inode *inode, struct file *file)
{
struct saa7134_dev *dev = file->private_data;
+ mutex_lock(&dev->empress_tsq.vb_lock);
+
videobuf_stop(&dev->empress_tsq);
videobuf_mmap_free(&dev->empress_tsq);
- dev->empress_users--;
/* stop the encoder */
ts_reset_encoder(dev);
@@ -121,6 +122,10 @@ static int ts_release(struct inode *inode, struct file *file)
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
+ dev->empress_users--;
+
+ mutex_unlock(&dev->empress_tsq.vb_lock);
+
return 0;
}
@@ -163,8 +168,7 @@ ts_mmap(struct file *file, struct vm_area_struct * vma)
static int empress_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
strcpy(cap->driver, "saa7134");
strlcpy(cap->card, saa7134_boards[dev->board].name,
@@ -219,8 +223,7 @@ static int empress_enum_fmt_cap(struct file *file, void *priv,
static int empress_g_fmt_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
saa7134_i2c_call_clients(dev, VIDIOC_G_FMT, f);
@@ -233,8 +236,7 @@ static int empress_g_fmt_cap(struct file *file, void *priv,
static int empress_s_fmt_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
saa7134_i2c_call_clients(dev, VIDIOC_S_FMT, f);
@@ -248,8 +250,7 @@ static int empress_s_fmt_cap(struct file *file, void *priv,
static int empress_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
return videobuf_reqbufs(&dev->empress_tsq, p);
}
@@ -257,24 +258,21 @@ static int empress_reqbufs(struct file *file, void *priv,
static int empress_querybuf(struct file *file, void *priv,
struct v4l2_buffer *b)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
return videobuf_querybuf(&dev->empress_tsq, b);
}
static int empress_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
return videobuf_qbuf(&dev->empress_tsq, b);
}
static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
return videobuf_dqbuf(&dev->empress_tsq, b,
file->f_flags & O_NONBLOCK);
@@ -283,8 +281,7 @@ static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
static int empress_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
return videobuf_streamon(&dev->empress_tsq);
}
@@ -292,8 +289,7 @@ static int empress_streamon(struct file *file, void *priv,
static int empress_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
return videobuf_streamoff(&dev->empress_tsq);
}
@@ -301,8 +297,7 @@ static int empress_streamoff(struct file *file, void *priv,
static int empress_s_ext_ctrls(struct file *file, void *priv,
struct v4l2_ext_controls *ctrls)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
/* count == 0 is abused in saa6752hs.c, so that special
case is handled here explicitly. */
@@ -321,8 +316,7 @@ static int empress_s_ext_ctrls(struct file *file, void *priv,
static int empress_g_ext_ctrls(struct file *file, void *priv,
struct v4l2_ext_controls *ctrls)
{
- struct saa7134_fh *fh = priv;
- struct saa7134_dev *dev = fh->dev;
+ struct saa7134_dev *dev = file->private_data;
if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
return -EINVAL;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 919632b10aae..76e6501d238d 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -323,6 +323,15 @@ int saa7134_input_init1(struct saa7134_dev *dev)
saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
break;
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ ir_codes = ir_codes_avermedia_a16d;
+ mask_keycode = 0x02F200;
+ mask_keydown = 0x000400;
+ polling = 50; /* ms */
+ /* Without this we won't receive key up events */
+ saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
+ saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
+ break;
case SAA7134_BOARD_KWORLD_TERMINATOR:
ir_codes = ir_codes_pixelview;
mask_keycode = 0x00001f;
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index a1b92446c8b4..d015bfe00950 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -763,15 +763,6 @@ static struct device_driver ic_drv = {
.owner = THIS_MODULE,
};
-/*
- * Image capture host - this is a host device, not a bus device, so,
- * no bus reference, no probing.
- */
-static struct class soc_camera_host_class = {
- .owner = THIS_MODULE,
- .name = "camera_host",
-};
-
static void dummy_release(struct device *dev)
{
}
@@ -801,7 +792,6 @@ int soc_camera_host_register(struct soc_camera_host *ici)
/* Number might be equal to the platform device ID */
sprintf(ici->dev.bus_id, "camera_host%d", ici->nr);
- ici->dev.class = &soc_camera_host_class;
mutex_lock(&list_lock);
list_for_each_entry(ix, &hosts, list) {
@@ -1003,14 +993,9 @@ static int __init soc_camera_init(void)
ret = driver_register(&ic_drv);
if (ret)
goto edrvr;
- ret = class_register(&soc_camera_host_class);
- if (ret)
- goto eclr;
return 0;
-eclr:
- driver_unregister(&ic_drv);
edrvr:
bus_unregister(&soc_camera_bus_type);
return ret;
@@ -1018,7 +1003,6 @@ edrvr:
static void __exit soc_camera_exit(void)
{
- class_unregister(&soc_camera_host_class);
driver_unregister(&ic_drv);
bus_unregister(&soc_camera_bus_type);
}
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 198f0afb812e..0d12ace61665 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -92,6 +92,7 @@ struct tuner {
unsigned int type; /* chip type id */
unsigned int config;
int (*tuner_callback) (void *dev, int command, int arg);
+ const char *name;
};
/* standard i2c insmod options */
@@ -330,13 +331,13 @@ static void tuner_i2c_address_check(struct tuner *t)
tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
tuner_warn("will soon be dropped. This message indicates that your\n");
tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
- t->i2c->name, t->i2c->addr);
+ t->name, t->i2c->addr);
tuner_warn("To ensure continued support for your device, please\n");
tuner_warn("send a copy of this message, along with full dmesg\n");
tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
- t->i2c->adapter->name, t->i2c->addr, t->type, t->i2c->name);
+ t->i2c->adapter->name, t->i2c->addr, t->type, t->name);
tuner_warn("====================== WARNING! ======================\n");
}
@@ -470,19 +471,17 @@ static void set_type(struct i2c_client *c, unsigned int type,
if ((NULL == analog_ops->set_params) &&
(fe_tuner_ops->set_analog_params)) {
- strlcpy(t->i2c->name, fe_tuner_ops->info.name,
- sizeof(t->i2c->name));
+ t->name = fe_tuner_ops->info.name;
t->fe.analog_demod_priv = t;
memcpy(analog_ops, &tuner_core_ops,
sizeof(struct analog_demod_ops));
} else {
- strlcpy(t->i2c->name, analog_ops->info.name,
- sizeof(t->i2c->name));
+ t->name = analog_ops->info.name;
}
- tuner_dbg("type set to %s\n", t->i2c->name);
+ tuner_dbg("type set to %s\n", t->name);
if (t->mode_mask == T_UNINITIALIZED)
t->mode_mask = new_mode_mask;
@@ -537,7 +536,7 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
static inline int check_mode(struct tuner *t, char *cmd)
{
if ((1 << t->mode & t->mode_mask) == 0) {
- return EINVAL;
+ return -EINVAL;
}
switch (t->mode) {
@@ -731,11 +730,11 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode,
t->mode = mode;
- if (check_mode(t, cmd) == EINVAL) {
+ if (check_mode(t, cmd) == -EINVAL) {
t->mode = T_STANDBY;
if (analog_ops->standby)
analog_ops->standby(&t->fe);
- return EINVAL;
+ return -EINVAL;
}
return 0;
}
@@ -777,13 +776,13 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
case AUDC_SET_RADIO:
if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
- == EINVAL)
+ == -EINVAL)
return 0;
if (t->radio_freq)
set_freq(client, t->radio_freq);
break;
case TUNER_SET_STANDBY:
- if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
+ if (check_mode(t, "TUNER_SET_STANDBY") == -EINVAL)
return 0;
t->mode = T_STANDBY;
if (analog_ops->standby)
@@ -791,9 +790,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
#ifdef CONFIG_VIDEO_ALLOW_V4L1
case VIDIOCSAUDIO:
- if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
+ if (check_mode(t, "VIDIOCSAUDIO") == -EINVAL)
return 0;
- if (check_v4l2(t) == EINVAL)
+ if (check_v4l2(t) == -EINVAL)
return 0;
/* Should be implemented, since bttv calls it */
@@ -811,10 +810,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
};
struct video_channel *vc = arg;
- if (check_v4l2(t) == EINVAL)
+ if (check_v4l2(t) == -EINVAL)
return 0;
- if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==EINVAL)
+ if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==-EINVAL)
return 0;
if (vc->norm < ARRAY_SIZE(map))
@@ -828,9 +827,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
unsigned long *v = arg;
- if (check_mode(t, "VIDIOCSFREQ") == EINVAL)
+ if (check_mode(t, "VIDIOCSFREQ") == -EINVAL)
return 0;
- if (check_v4l2(t) == EINVAL)
+ if (check_v4l2(t) == -EINVAL)
return 0;
set_freq(client, *v);
@@ -840,9 +839,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct video_tuner *vt = arg;
- if (check_mode(t, "VIDIOCGTUNER") == EINVAL)
+ if (check_mode(t, "VIDIOCGTUNER") == -EINVAL)
return 0;
- if (check_v4l2(t) == EINVAL)
+ if (check_v4l2(t) == -EINVAL)
return 0;
if (V4L2_TUNER_RADIO == t->mode) {
@@ -884,9 +883,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct video_audio *va = arg;
- if (check_mode(t, "VIDIOCGAUDIO") == EINVAL)
+ if (check_mode(t, "VIDIOCGAUDIO") == -EINVAL)
return 0;
- if (check_v4l2(t) == EINVAL)
+ if (check_v4l2(t) == -EINVAL)
return 0;
if (V4L2_TUNER_RADIO == t->mode) {
@@ -926,7 +925,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
v4l2_std_id *id = arg;
if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
- == EINVAL)
+ == -EINVAL)
return 0;
switch_v4l2();
@@ -942,7 +941,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
struct v4l2_frequency *f = arg;
if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
- == EINVAL)
+ == -EINVAL)
return 0;
switch_v4l2();
set_freq(client,f->frequency);
@@ -953,7 +952,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct v4l2_frequency *f = arg;
- if (check_mode(t, "VIDIOC_G_FREQUENCY") == EINVAL)
+ if (check_mode(t, "VIDIOC_G_FREQUENCY") == -EINVAL)
return 0;
switch_v4l2();
f->type = t->mode;
@@ -974,7 +973,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct v4l2_tuner *tuner = arg;
- if (check_mode(t, "VIDIOC_G_TUNER") == EINVAL)
+ if (check_mode(t, "VIDIOC_G_TUNER") == -EINVAL)
return 0;
switch_v4l2();
@@ -1021,7 +1020,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct v4l2_tuner *tuner = arg;
- if (check_mode(t, "VIDIOC_S_TUNER") == EINVAL)
+ if (check_mode(t, "VIDIOC_S_TUNER") == -EINVAL)
return 0;
switch_v4l2();
@@ -1115,6 +1114,7 @@ static int tuner_probe(struct i2c_client *client,
if (NULL == t)
return -ENOMEM;
t->i2c = client;
+ t->name = "(tuner unset)";
i2c_set_clientdata(client, t);
t->type = UNSET;
t->audmode = V4L2_TUNER_MODE_STEREO;
@@ -1272,12 +1272,6 @@ static int tuner_remove(struct i2c_client *client)
list_del(&t->list);
kfree(t);
-
- /* The probing code has overwritten the device name, restore it so
- that reloading the driver will work. Ideally the device name
- should not be overwritten in the first place, but for now that
- will do. */
- strlcpy(client->name, "tuner", I2C_NAME_SIZE);
return 0;
}
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
index 32e536edf09d..3d26a30abe1e 100644
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -210,7 +210,7 @@ static int qcm_stv_setb(struct usb_device *dev, u16 reg, u8 val)
return ret;
}
-static int qcm_stv_setw(struct usb_device *dev, u16 reg, u16 val)
+static int qcm_stv_setw(struct usb_device *dev, u16 reg, __le16 val)
{
int ret;
diff --git a/drivers/media/video/uvc/Makefile b/drivers/media/video/uvc/Makefile
new file mode 100644
index 000000000000..968c1994eda0
--- /dev/null
+++ b/drivers/media/video/uvc/Makefile
@@ -0,0 +1,3 @@
+uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
+ uvc_status.o uvc_isight.o
+obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
new file mode 100644
index 000000000000..f0ee46d15540
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -0,0 +1,1256 @@
+/*
+ * uvc_ctrl.c -- USB Video Class driver - Controls
+ *
+ * Copyright (C) 2005-2008
+ * Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include "uvcvideo.h"
+
+#define UVC_CTRL_NDATA 2
+#define UVC_CTRL_DATA_CURRENT 0
+#define UVC_CTRL_DATA_BACKUP 1
+
+/* ------------------------------------------------------------------------
+ * Control, formats, ...
+ */
+
+static struct uvc_control_info uvc_ctrls[] = {
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_BRIGHTNESS_CONTROL,
+ .index = 0,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_CONTRAST_CONTROL,
+ .index = 1,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_HUE_CONTROL,
+ .index = 2,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_SATURATION_CONTROL,
+ .index = 3,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_SHARPNESS_CONTROL,
+ .index = 4,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_GAMMA_CONTROL,
+ .index = 5,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_BACKLIGHT_COMPENSATION_CONTROL,
+ .index = 8,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_GAIN_CONTROL,
+ .index = 9,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_POWER_LINE_FREQUENCY_CONTROL,
+ .index = 10,
+ .size = 1,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_HUE_AUTO_CONTROL,
+ .index = 11,
+ .size = 1,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+ | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_AE_MODE_CONTROL,
+ .index = 1,
+ .size = 1,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+ | UVC_CONTROL_GET_DEF | UVC_CONTROL_GET_RES
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_AE_PRIORITY_CONTROL,
+ .index = 2,
+ .size = 1,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
+ .index = 3,
+ .size = 4,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_FOCUS_ABSOLUTE_CONTROL,
+ .index = 5,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ },
+ {
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_FOCUS_AUTO_CONTROL,
+ .index = 17,
+ .size = 1,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+ | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
+ .index = 12,
+ .size = 1,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+ | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
+ .index = 6,
+ .size = 2,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
+ .index = 13,
+ .size = 1,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+ | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ },
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_COMPONENT_CONTROL,
+ .index = 7,
+ .size = 4,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+ | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ },
+};
+
+static struct uvc_menu_info power_line_frequency_controls[] = {
+ { 0, "Disabled" },
+ { 1, "50 Hz" },
+ { 2, "60 Hz" },
+};
+
+static struct uvc_menu_info exposure_auto_controls[] = {
+ { 1, "Manual Mode" },
+ { 2, "Auto Mode" },
+ { 4, "Shutter Priority Mode" },
+ { 8, "Aperture Priority Mode" },
+};
+
+static struct uvc_control_mapping uvc_ctrl_mappings[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .name = "Brightness",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_BRIGHTNESS_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
+ },
+ {
+ .id = V4L2_CID_CONTRAST,
+ .name = "Contrast",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_CONTRAST_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_HUE,
+ .name = "Hue",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_HUE_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
+ },
+ {
+ .id = V4L2_CID_SATURATION,
+ .name = "Saturation",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_SATURATION_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_SHARPNESS,
+ .name = "Sharpness",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_SHARPNESS_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_GAMMA,
+ .name = "Gamma",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_GAMMA_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_BACKLIGHT_COMPENSATION,
+ .name = "Backlight Compensation",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_BACKLIGHT_COMPENSATION_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_GAIN,
+ .name = "Gain",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_GAIN_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .name = "Power Line Frequency",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_POWER_LINE_FREQUENCY_CONTROL,
+ .size = 2,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_MENU,
+ .data_type = UVC_CTRL_DATA_TYPE_ENUM,
+ .menu_info = power_line_frequency_controls,
+ .menu_count = ARRAY_SIZE(power_line_frequency_controls),
+ },
+ {
+ .id = V4L2_CID_HUE_AUTO,
+ .name = "Hue, Auto",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_HUE_AUTO_CONTROL,
+ .size = 1,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
+ .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
+ },
+ {
+ .id = V4L2_CID_EXPOSURE_AUTO,
+ .name = "Exposure, Auto",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_AE_MODE_CONTROL,
+ .size = 4,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_MENU,
+ .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
+ .menu_info = exposure_auto_controls,
+ .menu_count = ARRAY_SIZE(exposure_auto_controls),
+ },
+ {
+ .id = V4L2_CID_EXPOSURE_AUTO_PRIORITY,
+ .name = "Exposure, Auto Priority",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_AE_PRIORITY_CONTROL,
+ .size = 1,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
+ .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
+ },
+ {
+ .id = V4L2_CID_EXPOSURE_ABSOLUTE,
+ .name = "Exposure (Absolute)",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
+ .size = 32,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .name = "White Balance Temperature, Auto",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
+ .size = 1,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
+ .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
+ },
+ {
+ .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+ .name = "White Balance Temperature",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .name = "White Balance Component, Auto",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
+ .size = 1,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
+ .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
+ },
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .name = "White Balance Blue Component",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_COMPONENT_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
+ },
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .name = "White Balance Red Component",
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = PU_WHITE_BALANCE_COMPONENT_CONTROL,
+ .size = 16,
+ .offset = 16,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
+ },
+ {
+ .id = V4L2_CID_FOCUS_ABSOLUTE,
+ .name = "Focus (absolute)",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_FOCUS_ABSOLUTE_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_FOCUS_AUTO,
+ .name = "Focus, Auto",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_FOCUS_AUTO_CONTROL,
+ .size = 1,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
+ .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
+ },
+};
+
+/* ------------------------------------------------------------------------
+ * Utility functions
+ */
+
+static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
+{
+ return ctrl->data + id * ctrl->info->size;
+}
+
+static inline int uvc_get_bit(const __u8 *data, int bit)
+{
+ return (data[bit >> 3] >> (bit & 7)) & 1;
+}
+
+/* Extract the bit string specified by mapping->offset and mapping->size
+ * from the little-endian data stored at 'data' and return the result as
+ * a signed 32bit integer. Sign extension will be performed if the mapping
+ * references a signed data type.
+ */
+static __s32 uvc_get_le_value(const __u8 *data,
+ struct uvc_control_mapping *mapping)
+{
+ int bits = mapping->size;
+ int offset = mapping->offset;
+ __s32 value = 0;
+ __u8 mask;
+
+ data += offset / 8;
+ offset &= 7;
+ mask = ((1LL << bits) - 1) << offset;
+
+ for (; bits > 0; data++) {
+ __u8 byte = *data & mask;
+ value |= offset > 0 ? (byte >> offset) : (byte << (-offset));
+ bits -= 8 - (offset > 0 ? offset : 0);
+ offset -= 8;
+ mask = (1 << bits) - 1;
+ }
+
+ /* Sign-extend the value if needed */
+ if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED)
+ value |= -(value & (1 << (mapping->size - 1)));
+
+ return value;
+}
+
+/* Set the bit string specified by mapping->offset and mapping->size
+ * in the little-endian data stored at 'data' to the value 'value'.
+ */
+static void uvc_set_le_value(__s32 value, __u8 *data,
+ struct uvc_control_mapping *mapping)
+{
+ int bits = mapping->size;
+ int offset = mapping->offset;
+ __u8 mask;
+
+ data += offset / 8;
+ offset &= 7;
+
+ for (; bits > 0; data++) {
+ mask = ((1LL << bits) - 1) << offset;
+ *data = (*data & ~mask) | ((value << offset) & mask);
+ value >>= offset ? offset : 8;
+ bits -= 8 - offset;
+ offset = 0;
+ }
+}
+
+/* ------------------------------------------------------------------------
+ * Terminal and unit management
+ */
+
+static const __u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;
+static const __u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA;
+static const __u8 uvc_media_transport_input_guid[16] =
+ UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;
+
+static int uvc_entity_match_guid(struct uvc_entity *entity, __u8 guid[16])
+{
+ switch (UVC_ENTITY_TYPE(entity)) {
+ case ITT_CAMERA:
+ return memcmp(uvc_camera_guid, guid, 16) == 0;
+
+ case ITT_MEDIA_TRANSPORT_INPUT:
+ return memcmp(uvc_media_transport_input_guid, guid, 16) == 0;
+
+ case VC_PROCESSING_UNIT:
+ return memcmp(uvc_processing_guid, guid, 16) == 0;
+
+ case VC_EXTENSION_UNIT:
+ return memcmp(entity->extension.guidExtensionCode,
+ guid, 16) == 0;
+
+ default:
+ return 0;
+ }
+}
+
+/* ------------------------------------------------------------------------
+ * UVC Controls
+ */
+
+static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
+ struct uvc_control_mapping **mapping, struct uvc_control **control,
+ int next)
+{
+ struct uvc_control *ctrl;
+ struct uvc_control_mapping *map;
+ unsigned int i;
+
+ if (entity == NULL)
+ return;
+
+ for (i = 0; i < entity->ncontrols; ++i) {
+ ctrl = &entity->controls[i];
+ if (ctrl->info == NULL)
+ continue;
+
+ list_for_each_entry(map, &ctrl->info->mappings, list) {
+ if ((map->id == v4l2_id) && !next) {
+ *control = ctrl;
+ *mapping = map;
+ return;
+ }
+
+ if ((*mapping == NULL || (*mapping)->id > map->id) &&
+ (map->id > v4l2_id) && next) {
+ *control = ctrl;
+ *mapping = map;
+ }
+ }
+ }
+}
+
+struct uvc_control *uvc_find_control(struct uvc_video_device *video,
+ __u32 v4l2_id, struct uvc_control_mapping **mapping)
+{
+ struct uvc_control *ctrl = NULL;
+ struct uvc_entity *entity;
+ int next = v4l2_id & V4L2_CTRL_FLAG_NEXT_CTRL;
+
+ *mapping = NULL;
+
+ /* Mask the query flags. */
+ v4l2_id &= V4L2_CTRL_ID_MASK;
+
+ /* Find the control. */
+ __uvc_find_control(video->processing, v4l2_id, mapping, &ctrl, next);
+ if (ctrl && !next)
+ return ctrl;
+
+ list_for_each_entry(entity, &video->iterms, chain) {
+ __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
+ if (ctrl && !next)
+ return ctrl;
+ }
+
+ list_for_each_entry(entity, &video->extensions, chain) {
+ __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
+ if (ctrl && !next)
+ return ctrl;
+ }
+
+ if (ctrl == NULL && !next)
+ uvc_trace(UVC_TRACE_CONTROL, "Control 0x%08x not found.\n",
+ v4l2_id);
+
+ return ctrl;
+}
+
+int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
+ struct v4l2_queryctrl *v4l2_ctrl)
+{
+ struct uvc_control *ctrl;
+ struct uvc_control_mapping *mapping;
+ struct uvc_menu_info *menu;
+ unsigned int i;
+ __u8 data[8];
+ int ret;
+
+ ctrl = uvc_find_control(video, v4l2_ctrl->id, &mapping);
+ if (ctrl == NULL)
+ return -EINVAL;
+
+ v4l2_ctrl->id = mapping->id;
+ v4l2_ctrl->type = mapping->v4l2_type;
+ strncpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
+ v4l2_ctrl->flags = 0;
+
+ if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR))
+ v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
+ if ((ret = uvc_query_ctrl(video->dev, GET_DEF, ctrl->entity->id,
+ video->dev->intfnum, ctrl->info->selector,
+ &data, ctrl->info->size)) < 0)
+ return ret;
+ v4l2_ctrl->default_value = uvc_get_le_value(data, mapping);
+ }
+
+ if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
+ v4l2_ctrl->minimum = 0;
+ v4l2_ctrl->maximum = mapping->menu_count - 1;
+ v4l2_ctrl->step = 1;
+
+ menu = mapping->menu_info;
+ for (i = 0; i < mapping->menu_count; ++i, ++menu) {
+ if (menu->value == v4l2_ctrl->default_value) {
+ v4l2_ctrl->default_value = i;
+ break;
+ }
+ }
+
+ return 0;
+ }
+
+ if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
+ if ((ret = uvc_query_ctrl(video->dev, GET_MIN, ctrl->entity->id,
+ video->dev->intfnum, ctrl->info->selector,
+ &data, ctrl->info->size)) < 0)
+ return ret;
+ v4l2_ctrl->minimum = uvc_get_le_value(data, mapping);
+ }
+ if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
+ if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id,
+ video->dev->intfnum, ctrl->info->selector,
+ &data, ctrl->info->size)) < 0)
+ return ret;
+ v4l2_ctrl->maximum = uvc_get_le_value(data, mapping);
+ }
+ if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
+ if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id,
+ video->dev->intfnum, ctrl->info->selector,
+ &data, ctrl->info->size)) < 0)
+ return ret;
+ v4l2_ctrl->step = uvc_get_le_value(data, mapping);
+ }
+
+ return 0;
+}
+
+
+/* --------------------------------------------------------------------------
+ * Control transactions
+ *
+ * To make extended set operations as atomic as the hardware allows, controls
+ * are handled using begin/commit/rollback operations.
+ *
+ * At the beginning of a set request, uvc_ctrl_begin should be called to
+ * initialize the request. This function acquires the control lock.
+ *
+ * When setting a control, the new value is stored in the control data field
+ * at position UVC_CTRL_DATA_CURRENT. The control is then marked as dirty for
+ * later processing. If the UVC and V4L2 control sizes differ, the current
+ * value is loaded from the hardware before storing the new value in the data
+ * field.
+ *
+ * After processing all controls in the transaction, uvc_ctrl_commit or
+ * uvc_ctrl_rollback must be called to apply the pending changes to the
+ * hardware or revert them. When applying changes, all controls marked as
+ * dirty will be modified in the UVC device, and the dirty flag will be
+ * cleared. When reverting controls, the control data field
+ * UVC_CTRL_DATA_CURRENT is reverted to its previous value
+ * (UVC_CTRL_DATA_BACKUP) for all dirty controls. Both functions release the
+ * control lock.
+ */
+int uvc_ctrl_begin(struct uvc_video_device *video)
+{
+ return mutex_lock_interruptible(&video->ctrl_mutex) ? -ERESTARTSYS : 0;
+}
+
+static int uvc_ctrl_commit_entity(struct uvc_device *dev,
+ struct uvc_entity *entity, int rollback)
+{
+ struct uvc_control *ctrl;
+ unsigned int i;
+ int ret;
+
+ if (entity == NULL)
+ return 0;
+
+ for (i = 0; i < entity->ncontrols; ++i) {
+ ctrl = &entity->controls[i];
+ if (ctrl->info == NULL || !ctrl->dirty)
+ continue;
+
+ if (!rollback)
+ ret = uvc_query_ctrl(dev, SET_CUR, ctrl->entity->id,
+ dev->intfnum, ctrl->info->selector,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ ctrl->info->size);
+ else
+ ret = 0;
+
+ if (rollback || ret < 0)
+ memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
+ ctrl->info->size);
+
+ if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)
+ ctrl->loaded = 0;
+
+ ctrl->dirty = 0;
+
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback)
+{
+ struct uvc_entity *entity;
+ int ret = 0;
+
+ /* Find the control. */
+ ret = uvc_ctrl_commit_entity(video->dev, video->processing, rollback);
+ if (ret < 0)
+ goto done;
+
+ list_for_each_entry(entity, &video->iterms, chain) {
+ ret = uvc_ctrl_commit_entity(video->dev, entity, rollback);
+ if (ret < 0)
+ goto done;
+ }
+
+ list_for_each_entry(entity, &video->extensions, chain) {
+ ret = uvc_ctrl_commit_entity(video->dev, entity, rollback);
+ if (ret < 0)
+ goto done;
+ }
+
+done:
+ mutex_unlock(&video->ctrl_mutex);
+ return ret;
+}
+
+int uvc_ctrl_get(struct uvc_video_device *video,
+ struct v4l2_ext_control *xctrl)
+{
+ struct uvc_control *ctrl;
+ struct uvc_control_mapping *mapping;
+ struct uvc_menu_info *menu;
+ unsigned int i;
+ int ret;
+
+ ctrl = uvc_find_control(video, xctrl->id, &mapping);
+ if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)
+ return -EINVAL;
+
+ if (!ctrl->loaded) {
+ ret = uvc_query_ctrl(video->dev, GET_CUR, ctrl->entity->id,
+ video->dev->intfnum, ctrl->info->selector,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ ctrl->info->size);
+ if (ret < 0)
+ return ret;
+
+ if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0)
+ ctrl->loaded = 1;
+ }
+
+ xctrl->value = uvc_get_le_value(
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);
+
+ if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
+ menu = mapping->menu_info;
+ for (i = 0; i < mapping->menu_count; ++i, ++menu) {
+ if (menu->value == xctrl->value) {
+ xctrl->value = i;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int uvc_ctrl_set(struct uvc_video_device *video,
+ struct v4l2_ext_control *xctrl)
+{
+ struct uvc_control *ctrl;
+ struct uvc_control_mapping *mapping;
+ s32 value = xctrl->value;
+ int ret;
+
+ ctrl = uvc_find_control(video, xctrl->id, &mapping);
+ if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0)
+ return -EINVAL;
+
+ if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
+ if (value < 0 || value >= mapping->menu_count)
+ return -EINVAL;
+ value = mapping->menu_info[value].value;
+ }
+
+ if (!ctrl->loaded && (ctrl->info->size * 8) != mapping->size) {
+ if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) {
+ memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ 0, ctrl->info->size);
+ } else {
+ ret = uvc_query_ctrl(video->dev, GET_CUR,
+ ctrl->entity->id, video->dev->intfnum,
+ ctrl->info->selector,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ ctrl->info->size);
+ if (ret < 0)
+ return ret;
+ }
+
+ if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0)
+ ctrl->loaded = 1;
+ }
+
+ if (!ctrl->dirty) {
+ memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ ctrl->info->size);
+ }
+
+ uvc_set_le_value(value,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);
+
+ ctrl->dirty = 1;
+ ctrl->modified = 1;
+ return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * Dynamic controls
+ */
+
+int uvc_xu_ctrl_query(struct uvc_video_device *video,
+ struct uvc_xu_control *xctrl, int set)
+{
+ struct uvc_entity *entity;
+ struct uvc_control *ctrl = NULL;
+ unsigned int i, found = 0;
+ __u8 *data;
+ int ret;
+
+ /* Find the extension unit. */
+ list_for_each_entry(entity, &video->extensions, chain) {
+ if (entity->id == xctrl->unit)
+ break;
+ }
+
+ if (entity->id != xctrl->unit) {
+ uvc_trace(UVC_TRACE_CONTROL, "Extension unit %u not found.\n",
+ xctrl->unit);
+ return -EINVAL;
+ }
+
+ /* Find the control. */
+ for (i = 0; i < entity->ncontrols; ++i) {
+ ctrl = &entity->controls[i];
+ if (ctrl->info == NULL)
+ continue;
+
+ if (ctrl->info->selector == xctrl->selector) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ uvc_trace(UVC_TRACE_CONTROL,
+ "Control " UVC_GUID_FORMAT "/%u not found.\n",
+ UVC_GUID_ARGS(entity->extension.guidExtensionCode),
+ xctrl->selector);
+ return -EINVAL;
+ }
+
+ /* Validate control data size. */
+ if (ctrl->info->size != xctrl->size)
+ return -EINVAL;
+
+ if ((set && !(ctrl->info->flags & UVC_CONTROL_SET_CUR)) ||
+ (!set && !(ctrl->info->flags & UVC_CONTROL_GET_CUR)))
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&video->ctrl_mutex))
+ return -ERESTARTSYS;
+
+ memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ xctrl->size);
+ data = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT);
+
+ if (set && copy_from_user(data, xctrl->data, xctrl->size)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ret = uvc_query_ctrl(video->dev, set ? SET_CUR : GET_CUR, xctrl->unit,
+ video->dev->intfnum, xctrl->selector, data,
+ xctrl->size);
+ if (ret < 0)
+ goto out;
+
+ if (!set && copy_to_user(xctrl->data, data, xctrl->size)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+out:
+ if (ret)
+ memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
+ xctrl->size);
+
+ mutex_unlock(&video->ctrl_mutex);
+ return ret;
+}
+
+/* --------------------------------------------------------------------------
+ * Suspend/resume
+ */
+
+/*
+ * Restore control values after resume, skipping controls that haven't been
+ * changed.
+ *
+ * TODO
+ * - Don't restore modified controls that are back to their default value.
+ * - Handle restore order (Auto-Exposure Mode should be restored before
+ * Exposure Time).
+ */
+int uvc_ctrl_resume_device(struct uvc_device *dev)
+{
+ struct uvc_control *ctrl;
+ struct uvc_entity *entity;
+ unsigned int i;
+ int ret;
+
+ /* Walk the entities list and restore controls when possible. */
+ list_for_each_entry(entity, &dev->entities, list) {
+
+ for (i = 0; i < entity->ncontrols; ++i) {
+ ctrl = &entity->controls[i];
+
+ if (ctrl->info == NULL || !ctrl->modified ||
+ (ctrl->info->flags & UVC_CONTROL_RESTORE) == 0)
+ continue;
+
+ printk(KERN_INFO "restoring control " UVC_GUID_FORMAT
+ "/%u/%u\n", UVC_GUID_ARGS(ctrl->info->entity),
+ ctrl->info->index, ctrl->info->selector);
+ ctrl->dirty = 1;
+ }
+
+ ret = uvc_ctrl_commit_entity(dev, entity, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * Control and mapping handling
+ */
+
+static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
+ struct uvc_control_info *info)
+{
+ struct uvc_entity *entity;
+ struct uvc_control *ctrl = NULL;
+ int ret, found = 0;
+ unsigned int i;
+
+ list_for_each_entry(entity, &dev->entities, list) {
+ if (!uvc_entity_match_guid(entity, info->entity))
+ continue;
+
+ for (i = 0; i < entity->ncontrols; ++i) {
+ ctrl = &entity->controls[i];
+ if (ctrl->index == info->index) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found)
+ break;
+ }
+
+ if (!found)
+ return;
+
+ if (UVC_ENTITY_TYPE(entity) == VC_EXTENSION_UNIT) {
+ /* Check if the device control information and length match
+ * the user supplied information.
+ */
+ __u32 flags;
+ __le16 size;
+ __u8 inf;
+
+ if ((ret = uvc_query_ctrl(dev, GET_LEN, ctrl->entity->id,
+ dev->intfnum, info->selector, (__u8 *)&size, 2)) < 0) {
+ uvc_trace(UVC_TRACE_CONTROL, "GET_LEN failed on "
+ "control " UVC_GUID_FORMAT "/%u (%d).\n",
+ UVC_GUID_ARGS(info->entity), info->selector,
+ ret);
+ return;
+ }
+
+ if (info->size != le16_to_cpu(size)) {
+ uvc_trace(UVC_TRACE_CONTROL, "Control " UVC_GUID_FORMAT
+ "/%u size doesn't match user supplied "
+ "value.\n", UVC_GUID_ARGS(info->entity),
+ info->selector);
+ return;
+ }
+
+ if ((ret = uvc_query_ctrl(dev, GET_INFO, ctrl->entity->id,
+ dev->intfnum, info->selector, &inf, 1)) < 0) {
+ uvc_trace(UVC_TRACE_CONTROL, "GET_INFO failed on "
+ "control " UVC_GUID_FORMAT "/%u (%d).\n",
+ UVC_GUID_ARGS(info->entity), info->selector,
+ ret);
+ return;
+ }
+
+ flags = info->flags;
+ if (((flags & UVC_CONTROL_GET_CUR) && !(inf & (1 << 0))) ||
+ ((flags & UVC_CONTROL_SET_CUR) && !(inf & (1 << 1)))) {
+ uvc_trace(UVC_TRACE_CONTROL, "Control "
+ UVC_GUID_FORMAT "/%u flags don't match "
+ "supported operations.\n",
+ UVC_GUID_ARGS(info->entity), info->selector);
+ return;
+ }
+ }
+
+ ctrl->info = info;
+ ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_NDATA, GFP_KERNEL);
+ uvc_trace(UVC_TRACE_CONTROL, "Added control " UVC_GUID_FORMAT "/%u "
+ "to device %s entity %u\n", UVC_GUID_ARGS(ctrl->info->entity),
+ ctrl->info->selector, dev->udev->devpath, entity->id);
+}
+
+/*
+ * Add an item to the UVC control information list, and instantiate a control
+ * structure for each device that supports the control.
+ */
+int uvc_ctrl_add_info(struct uvc_control_info *info)
+{
+ struct uvc_control_info *ctrl;
+ struct uvc_device *dev;
+ int ret = 0;
+
+ /* Find matching controls by walking the devices, entities and
+ * controls list.
+ */
+ mutex_lock(&uvc_driver.ctrl_mutex);
+
+ /* First check if the list contains a control matching the new one.
+ * Bail out if it does.
+ */
+ list_for_each_entry(ctrl, &uvc_driver.controls, list) {
+ if (memcmp(ctrl->entity, info->entity, 16))
+ continue;
+
+ if (ctrl->selector == info->selector) {
+ uvc_trace(UVC_TRACE_CONTROL, "Control "
+ UVC_GUID_FORMAT "/%u is already defined.\n",
+ UVC_GUID_ARGS(info->entity), info->selector);
+ ret = -EEXIST;
+ goto end;
+ }
+ if (ctrl->index == info->index) {
+ uvc_trace(UVC_TRACE_CONTROL, "Control "
+ UVC_GUID_FORMAT "/%u would overwrite index "
+ "%d.\n", UVC_GUID_ARGS(info->entity),
+ info->selector, info->index);
+ ret = -EEXIST;
+ goto end;
+ }
+ }
+
+ list_for_each_entry(dev, &uvc_driver.devices, list)
+ uvc_ctrl_add_ctrl(dev, info);
+
+ INIT_LIST_HEAD(&info->mappings);
+ list_add_tail(&info->list, &uvc_driver.controls);
+end:
+ mutex_unlock(&uvc_driver.ctrl_mutex);
+ return ret;
+}
+
+int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping)
+{
+ struct uvc_control_info *info;
+ struct uvc_control_mapping *map;
+ int ret = -EINVAL;
+
+ if (mapping->id & ~V4L2_CTRL_ID_MASK) {
+ uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s' with "
+ "invalid control id 0x%08x\n", mapping->name,
+ mapping->id);
+ return -EINVAL;
+ }
+
+ mutex_lock(&uvc_driver.ctrl_mutex);
+ list_for_each_entry(info, &uvc_driver.controls, list) {
+ if (memcmp(info->entity, mapping->entity, 16) ||
+ info->selector != mapping->selector)
+ continue;
+
+ if (info->size * 8 < mapping->size + mapping->offset) {
+ uvc_trace(UVC_TRACE_CONTROL, "Mapping '%s' would "
+ "overflow control " UVC_GUID_FORMAT "/%u\n",
+ mapping->name, UVC_GUID_ARGS(info->entity),
+ info->selector);
+ ret = -EOVERFLOW;
+ goto end;
+ }
+
+ /* Check if the list contains a mapping matching the new one.
+ * Bail out if it does.
+ */
+ list_for_each_entry(map, &info->mappings, list) {
+ if (map->id == mapping->id) {
+ uvc_trace(UVC_TRACE_CONTROL, "Mapping '%s' is "
+ "already defined.\n", mapping->name);
+ ret = -EEXIST;
+ goto end;
+ }
+ }
+
+ mapping->ctrl = info;
+ list_add_tail(&mapping->list, &info->mappings);
+ uvc_trace(UVC_TRACE_CONTROL, "Adding mapping %s to control "
+ UVC_GUID_FORMAT "/%u.\n", mapping->name,
+ UVC_GUID_ARGS(info->entity), info->selector);
+
+ ret = 0;
+ break;
+ }
+end:
+ mutex_unlock(&uvc_driver.ctrl_mutex);
+ return ret;
+}
+
+/*
+ * Initialize device controls.
+ */
+int uvc_ctrl_init_device(struct uvc_device *dev)
+{
+ struct uvc_control_info *info;
+ struct uvc_control *ctrl;
+ struct uvc_entity *entity;
+ unsigned int i;
+
+ /* Walk the entities list and instantiate controls */
+ list_for_each_entry(entity, &dev->entities, list) {
+ unsigned int bControlSize = 0, ncontrols = 0;
+ __u8 *bmControls = NULL;
+
+ if (UVC_ENTITY_TYPE(entity) == VC_EXTENSION_UNIT) {
+ bmControls = entity->extension.bmControls;
+ bControlSize = entity->extension.bControlSize;
+ } else if (UVC_ENTITY_TYPE(entity) == VC_PROCESSING_UNIT) {
+ bmControls = entity->processing.bmControls;
+ bControlSize = entity->processing.bControlSize;
+ } else if (UVC_ENTITY_TYPE(entity) == ITT_CAMERA) {
+ bmControls = entity->camera.bmControls;
+ bControlSize = entity->camera.bControlSize;
+ }
+
+ for (i = 0; i < bControlSize; ++i)
+ ncontrols += hweight8(bmControls[i]);
+
+ if (ncontrols == 0)
+ continue;
+
+ entity->controls = kzalloc(ncontrols*sizeof *ctrl, GFP_KERNEL);
+ if (entity->controls == NULL)
+ return -ENOMEM;
+
+ entity->ncontrols = ncontrols;
+
+ ctrl = entity->controls;
+ for (i = 0; i < bControlSize * 8; ++i) {
+ if (uvc_get_bit(bmControls, i) == 0)
+ continue;
+
+ ctrl->entity = entity;
+ ctrl->index = i;
+ ctrl++;
+ }
+ }
+
+ /* Walk the controls info list and associate them with the device
+ * controls, then add the device to the global device list. This has
+ * to be done while holding the controls lock, to make sure
+ * uvc_ctrl_add_info() will not get called in-between.
+ */
+ mutex_lock(&uvc_driver.ctrl_mutex);
+ list_for_each_entry(info, &uvc_driver.controls, list)
+ uvc_ctrl_add_ctrl(dev, info);
+
+ list_add_tail(&dev->list, &uvc_driver.devices);
+ mutex_unlock(&uvc_driver.ctrl_mutex);
+
+ return 0;
+}
+
+/*
+ * Cleanup device controls.
+ */
+void uvc_ctrl_cleanup_device(struct uvc_device *dev)
+{
+ struct uvc_entity *entity;
+ unsigned int i;
+
+ /* Remove the device from the global devices list */
+ mutex_lock(&uvc_driver.ctrl_mutex);
+ if (dev->list.next != NULL)
+ list_del(&dev->list);
+ mutex_unlock(&uvc_driver.ctrl_mutex);
+
+ list_for_each_entry(entity, &dev->entities, list) {
+ for (i = 0; i < entity->ncontrols; ++i)
+ kfree(entity->controls[i].data);
+
+ kfree(entity->controls);
+ }
+}
+
+void uvc_ctrl_init(void)
+{
+ struct uvc_control_info *ctrl = uvc_ctrls;
+ struct uvc_control_info *cend = ctrl + ARRAY_SIZE(uvc_ctrls);
+ struct uvc_control_mapping *mapping = uvc_ctrl_mappings;
+ struct uvc_control_mapping *mend =
+ mapping + ARRAY_SIZE(uvc_ctrl_mappings);
+
+ for (; ctrl < cend; ++ctrl)
+ uvc_ctrl_add_info(ctrl);
+
+ for (; mapping < mend; ++mapping)
+ uvc_ctrl_add_mapping(mapping);
+}
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
new file mode 100644
index 000000000000..60ced589f898
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -0,0 +1,1955 @@
+/*
+ * uvc_driver.c -- USB Video Class driver
+ *
+ * Copyright (C) 2005-2008
+ * Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ * 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 driver aims to support video input devices compliant with the 'USB
+ * Video Class' specification.
+ *
+ * The driver doesn't support the deprecated v4l1 interface. It implements the
+ * mmap capture method only, and doesn't do any image format conversion in
+ * software. If your user-space application doesn't support YUYV or MJPEG, fix
+ * it :-). Please note that the MJPEG data have been stripped from their
+ * Huffman tables (DHT marker), you will need to add it back if your JPEG
+ * codec can't handle MJPEG data.
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include <media/v4l2-common.h>
+
+#include "uvcvideo.h"
+
+#define DRIVER_AUTHOR "Laurent Pinchart <laurent.pinchart@skynet.be>"
+#define DRIVER_DESC "USB Video Class driver"
+#ifndef DRIVER_VERSION
+#define DRIVER_VERSION "v0.1.0"
+#endif
+
+static unsigned int uvc_quirks_param;
+unsigned int uvc_trace_param;
+
+/* ------------------------------------------------------------------------
+ * Control, formats, ...
+ */
+
+static struct uvc_format_desc uvc_fmts[] = {
+ {
+ .name = "YUV 4:2:2 (YUYV)",
+ .guid = UVC_GUID_FORMAT_YUY2,
+ .fcc = V4L2_PIX_FMT_YUYV,
+ },
+ {
+ .name = "YUV 4:2:0 (NV12)",
+ .guid = UVC_GUID_FORMAT_NV12,
+ .fcc = V4L2_PIX_FMT_NV12,
+ },
+ {
+ .name = "MJPEG",
+ .guid = UVC_GUID_FORMAT_MJPEG,
+ .fcc = V4L2_PIX_FMT_MJPEG,
+ },
+ {
+ .name = "YVU 4:2:0 (YV12)",
+ .guid = UVC_GUID_FORMAT_YV12,
+ .fcc = V4L2_PIX_FMT_YVU420,
+ },
+ {
+ .name = "YUV 4:2:0 (I420)",
+ .guid = UVC_GUID_FORMAT_I420,
+ .fcc = V4L2_PIX_FMT_YUV420,
+ },
+ {
+ .name = "YUV 4:2:2 (UYVY)",
+ .guid = UVC_GUID_FORMAT_UYVY,
+ .fcc = V4L2_PIX_FMT_UYVY,
+ },
+ {
+ .name = "Greyscale",
+ .guid = UVC_GUID_FORMAT_Y800,
+ .fcc = V4L2_PIX_FMT_GREY,
+ },
+ {
+ .name = "RGB Bayer",
+ .guid = UVC_GUID_FORMAT_BY8,
+ .fcc = V4L2_PIX_FMT_SBGGR8,
+ },
+};
+
+/* ------------------------------------------------------------------------
+ * Utility functions
+ */
+
+struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
+ __u8 epaddr)
+{
+ struct usb_host_endpoint *ep;
+ unsigned int i;
+
+ for (i = 0; i < alts->desc.bNumEndpoints; ++i) {
+ ep = &alts->endpoint[i];
+ if (ep->desc.bEndpointAddress == epaddr)
+ return ep;
+ }
+
+ return NULL;
+}
+
+static struct uvc_format_desc *uvc_format_by_guid(const __u8 guid[16])
+{
+ unsigned int len = ARRAY_SIZE(uvc_fmts);
+ unsigned int i;
+
+ for (i = 0; i < len; ++i) {
+ if (memcmp(guid, uvc_fmts[i].guid, 16) == 0)
+ return &uvc_fmts[i];
+ }
+
+ return NULL;
+}
+
+static __u32 uvc_colorspace(const __u8 primaries)
+{
+ static const __u8 colorprimaries[] = {
+ 0,
+ V4L2_COLORSPACE_SRGB,
+ V4L2_COLORSPACE_470_SYSTEM_M,
+ V4L2_COLORSPACE_470_SYSTEM_BG,
+ V4L2_COLORSPACE_SMPTE170M,
+ V4L2_COLORSPACE_SMPTE240M,
+ };
+
+ if (primaries < ARRAY_SIZE(colorprimaries))
+ return colorprimaries[primaries];
+
+ return 0;
+}
+
+/* Simplify a fraction using a simple continued fraction decomposition. The
+ * idea here is to convert fractions such as 333333/10000000 to 1/30 using
+ * 32 bit arithmetic only. The algorithm is not perfect and relies upon two
+ * arbitrary parameters to remove non-significative terms from the simple
+ * continued fraction decomposition. Using 8 and 333 for n_terms and threshold
+ * respectively seems to give nice results.
+ */
+void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
+ unsigned int n_terms, unsigned int threshold)
+{
+ uint32_t *an;
+ uint32_t x, y, r;
+ unsigned int i, n;
+
+ an = kmalloc(n_terms * sizeof *an, GFP_KERNEL);
+ if (an == NULL)
+ return;
+
+ /* Convert the fraction to a simple continued fraction. See
+ * http://mathforum.org/dr.math/faq/faq.fractions.html
+ * Stop if the current term is bigger than or equal to the given
+ * threshold.
+ */
+ x = *numerator;
+ y = *denominator;
+
+ for (n = 0; n < n_terms && y != 0; ++n) {
+ an[n] = x / y;
+ if (an[n] >= threshold) {
+ if (n < 2)
+ n++;
+ break;
+ }
+
+ r = x - an[n] * y;
+ x = y;
+ y = r;
+ }
+
+ /* Expand the simple continued fraction back to an integer fraction. */
+ x = 0;
+ y = 1;
+
+ for (i = n; i > 0; --i) {
+ r = y;
+ y = an[i-1] * y + x;
+ x = r;
+ }
+
+ *numerator = y;
+ *denominator = x;
+ kfree(an);
+}
+
+/* Convert a fraction to a frame interval in 100ns multiples. The idea here is
+ * to compute numerator / denominator * 10000000 using 32 bit fixed point
+ * arithmetic only.
+ */
+uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator)
+{
+ uint32_t multiplier;
+
+ /* Saturate the result if the operation would overflow. */
+ if (denominator == 0 ||
+ numerator/denominator >= ((uint32_t)-1)/10000000)
+ return (uint32_t)-1;
+
+ /* Divide both the denominator and the multiplier by two until
+ * numerator * multiplier doesn't overflow. If anyone knows a better
+ * algorithm please let me know.
+ */
+ multiplier = 10000000;
+ while (numerator > ((uint32_t)-1)/multiplier) {
+ multiplier /= 2;
+ denominator /= 2;
+ }
+
+ return denominator ? numerator * multiplier / denominator : 0;
+}
+
+/* ------------------------------------------------------------------------
+ * Terminal and unit management
+ */
+
+static struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id)
+{
+ struct uvc_entity *entity;
+
+ list_for_each_entry(entity, &dev->entities, list) {
+ if (entity->id == id)
+ return entity;
+ }
+
+ return NULL;
+}
+
+static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev,
+ int id, struct uvc_entity *entity)
+{
+ unsigned int i;
+
+ if (entity == NULL)
+ entity = list_entry(&dev->entities, struct uvc_entity, list);
+
+ list_for_each_entry_continue(entity, &dev->entities, list) {
+ switch (UVC_ENTITY_TYPE(entity)) {
+ case TT_STREAMING:
+ if (entity->output.bSourceID == id)
+ return entity;
+ break;
+
+ case VC_PROCESSING_UNIT:
+ if (entity->processing.bSourceID == id)
+ return entity;
+ break;
+
+ case VC_SELECTOR_UNIT:
+ for (i = 0; i < entity->selector.bNrInPins; ++i)
+ if (entity->selector.baSourceID[i] == id)
+ return entity;
+ break;
+
+ case VC_EXTENSION_UNIT:
+ for (i = 0; i < entity->extension.bNrInPins; ++i)
+ if (entity->extension.baSourceID[i] == id)
+ return entity;
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+/* ------------------------------------------------------------------------
+ * Descriptors handling
+ */
+
+static int uvc_parse_format(struct uvc_device *dev,
+ struct uvc_streaming *streaming, struct uvc_format *format,
+ __u32 **intervals, unsigned char *buffer, int buflen)
+{
+ struct usb_interface *intf = streaming->intf;
+ struct usb_host_interface *alts = intf->cur_altsetting;
+ struct uvc_format_desc *fmtdesc;
+ struct uvc_frame *frame;
+ const unsigned char *start = buffer;
+ unsigned int interval;
+ unsigned int i, n;
+ __u8 ftype;
+
+ format->type = buffer[2];
+ format->index = buffer[3];
+
+ switch (buffer[2]) {
+ case VS_FORMAT_UNCOMPRESSED:
+ case VS_FORMAT_FRAME_BASED:
+ if (buflen < 27) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ "interface %d FORMAT error\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ /* Find the format descriptor from its GUID. */
+ fmtdesc = uvc_format_by_guid(&buffer[5]);
+
+ if (fmtdesc != NULL) {
+ strncpy(format->name, fmtdesc->name,
+ sizeof format->name);
+ format->fcc = fmtdesc->fcc;
+ } else {
+ uvc_printk(KERN_INFO, "Unknown video format "
+ UVC_GUID_FORMAT "\n",
+ UVC_GUID_ARGS(&buffer[5]));
+ snprintf(format->name, sizeof format->name,
+ UVC_GUID_FORMAT, UVC_GUID_ARGS(&buffer[5]));
+ format->fcc = 0;
+ }
+
+ format->bpp = buffer[21];
+ if (buffer[2] == VS_FORMAT_UNCOMPRESSED) {
+ ftype = VS_FRAME_UNCOMPRESSED;
+ } else {
+ ftype = VS_FRAME_FRAME_BASED;
+ if (buffer[27])
+ format->flags = UVC_FMT_FLAG_COMPRESSED;
+ }
+ break;
+
+ case VS_FORMAT_MJPEG:
+ if (buflen < 11) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ "interface %d FORMAT error\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ strncpy(format->name, "MJPEG", sizeof format->name);
+ format->fcc = V4L2_PIX_FMT_MJPEG;
+ format->flags = UVC_FMT_FLAG_COMPRESSED;
+ format->bpp = 0;
+ ftype = VS_FRAME_MJPEG;
+ break;
+
+ case VS_FORMAT_DV:
+ if (buflen < 9) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ "interface %d FORMAT error\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ switch (buffer[8] & 0x7f) {
+ case 0:
+ strncpy(format->name, "SD-DV", sizeof format->name);
+ break;
+ case 1:
+ strncpy(format->name, "SDL-DV", sizeof format->name);
+ break;
+ case 2:
+ strncpy(format->name, "HD-DV", sizeof format->name);
+ break;
+ default:
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ "interface %d: unknown DV format %u\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber, buffer[8]);
+ return -EINVAL;
+ }
+
+ strncat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz",
+ sizeof format->name);
+
+ format->fcc = V4L2_PIX_FMT_DV;
+ format->flags = UVC_FMT_FLAG_COMPRESSED | UVC_FMT_FLAG_STREAM;
+ format->bpp = 0;
+ ftype = 0;
+
+ /* Create a dummy frame descriptor. */
+ frame = &format->frame[0];
+ memset(&format->frame[0], 0, sizeof format->frame[0]);
+ frame->bFrameIntervalType = 1;
+ frame->dwDefaultFrameInterval = 1;
+ frame->dwFrameInterval = *intervals;
+ *(*intervals)++ = 1;
+ format->nframes = 1;
+ break;
+
+ case VS_FORMAT_MPEG2TS:
+ case VS_FORMAT_STREAM_BASED:
+ /* Not supported yet. */
+ default:
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ "interface %d unsupported format %u\n",
+ dev->udev->devnum, alts->desc.bInterfaceNumber,
+ buffer[2]);
+ return -EINVAL;
+ }
+
+ uvc_trace(UVC_TRACE_DESCR, "Found format %s.\n", format->name);
+
+ buflen -= buffer[0];
+ buffer += buffer[0];
+
+ /* Parse the frame descriptors. Only uncompressed, MJPEG and frame
+ * based formats have frame descriptors.
+ */
+ while (buflen > 2 && buffer[2] == ftype) {
+ frame = &format->frame[format->nframes];
+
+ if (ftype != VS_FRAME_FRAME_BASED)
+ n = buflen > 25 ? buffer[25] : 0;
+ else
+ n = buflen > 21 ? buffer[21] : 0;
+
+ n = n ? n : 3;
+
+ if (buflen < 26 + 4*n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ "interface %d FRAME error\n", dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ frame->bFrameIndex = buffer[3];
+ frame->bmCapabilities = buffer[4];
+ frame->wWidth = le16_to_cpup((__le16 *)&buffer[5]);
+ frame->wHeight = le16_to_cpup((__le16 *)&buffer[7]);
+ frame->dwMinBitRate = le32_to_cpup((__le32 *)&buffer[9]);
+ frame->dwMaxBitRate = le32_to_cpup((__le32 *)&buffer[13]);
+ if (ftype != VS_FRAME_FRAME_BASED) {
+ frame->dwMaxVideoFrameBufferSize =
+ le32_to_cpup((__le32 *)&buffer[17]);
+ frame->dwDefaultFrameInterval =
+ le32_to_cpup((__le32 *)&buffer[21]);
+ frame->bFrameIntervalType = buffer[25];
+ } else {
+ frame->dwMaxVideoFrameBufferSize = 0;
+ frame->dwDefaultFrameInterval =
+ le32_to_cpup((__le32 *)&buffer[17]);
+ frame->bFrameIntervalType = buffer[21];
+ }
+ frame->dwFrameInterval = *intervals;
+
+ /* Several UVC chipsets screw up dwMaxVideoFrameBufferSize
+ * completely. Observed behaviours range from setting the
+ * value to 1.1x the actual frame size of hardwiring the
+ * 16 low bits to 0. This results in a higher than necessary
+ * memory usage as well as a wrong image size information. For
+ * uncompressed formats this can be fixed by computing the
+ * value from the frame size.
+ */
+ if (!(format->flags & UVC_FMT_FLAG_COMPRESSED))
+ frame->dwMaxVideoFrameBufferSize = format->bpp
+ * frame->wWidth * frame->wHeight / 8;
+
+ /* Some bogus devices report dwMinFrameInterval equal to
+ * dwMaxFrameInterval and have dwFrameIntervalStep set to
+ * zero. Setting all null intervals to 1 fixes the problem and
+ * some other divisions by zero which could happen.
+ */
+ for (i = 0; i < n; ++i) {
+ interval = le32_to_cpup((__le32 *)&buffer[26+4*i]);
+ *(*intervals)++ = interval ? interval : 1;
+ }
+
+ /* Make sure that the default frame interval stays between
+ * the boundaries.
+ */
+ n -= frame->bFrameIntervalType ? 1 : 2;
+ frame->dwDefaultFrameInterval =
+ min(frame->dwFrameInterval[n],
+ max(frame->dwFrameInterval[0],
+ frame->dwDefaultFrameInterval));
+
+ uvc_trace(UVC_TRACE_DESCR, "- %ux%u (%u.%u fps)\n",
+ frame->wWidth, frame->wHeight,
+ 10000000/frame->dwDefaultFrameInterval,
+ (100000000/frame->dwDefaultFrameInterval)%10);
+
+ format->nframes++;
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ if (buflen > 2 && buffer[2] == VS_STILL_IMAGE_FRAME) {
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ if (buflen > 2 && buffer[2] == VS_COLORFORMAT) {
+ if (buflen < 6) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ "interface %d COLORFORMAT error\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ format->colorspace = uvc_colorspace(buffer[3]);
+
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ return buffer - start;
+}
+
+static int uvc_parse_streaming(struct uvc_device *dev,
+ struct usb_interface *intf)
+{
+ struct uvc_streaming *streaming = NULL;
+ struct uvc_format *format;
+ struct uvc_frame *frame;
+ struct usb_host_interface *alts = &intf->altsetting[0];
+ unsigned char *_buffer, *buffer = alts->extra;
+ int _buflen, buflen = alts->extralen;
+ unsigned int nformats = 0, nframes = 0, nintervals = 0;
+ unsigned int size, i, n, p;
+ __u32 *interval;
+ __u16 psize;
+ int ret = -EINVAL;
+
+ if (intf->cur_altsetting->desc.bInterfaceSubClass
+ != SC_VIDEOSTREAMING) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d interface %d isn't a "
+ "video streaming interface\n", dev->udev->devnum,
+ intf->altsetting[0].desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ if (usb_driver_claim_interface(&uvc_driver.driver, intf, dev)) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d interface %d is already "
+ "claimed\n", dev->udev->devnum,
+ intf->altsetting[0].desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ streaming = kzalloc(sizeof *streaming, GFP_KERNEL);
+ if (streaming == NULL) {
+ usb_driver_release_interface(&uvc_driver.driver, intf);
+ return -EINVAL;
+ }
+
+ mutex_init(&streaming->mutex);
+ streaming->intf = usb_get_intf(intf);
+ streaming->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
+
+ /* The Pico iMage webcam has its class-specific interface descriptors
+ * after the endpoint descriptors.
+ */
+ if (buflen == 0) {
+ for (i = 0; i < alts->desc.bNumEndpoints; ++i) {
+ struct usb_host_endpoint *ep = &alts->endpoint[i];
+
+ if (ep->extralen == 0)
+ continue;
+
+ if (ep->extralen > 2 &&
+ ep->extra[1] == USB_DT_CS_INTERFACE) {
+ uvc_trace(UVC_TRACE_DESCR, "trying extra data "
+ "from endpoint %u.\n", i);
+ buffer = alts->endpoint[i].extra;
+ buflen = alts->endpoint[i].extralen;
+ break;
+ }
+ }
+ }
+
+ /* Skip the standard interface descriptors. */
+ while (buflen > 2 && buffer[1] != USB_DT_CS_INTERFACE) {
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ if (buflen <= 2) {
+ uvc_trace(UVC_TRACE_DESCR, "no class-specific streaming "
+ "interface descriptors found.\n");
+ goto error;
+ }
+
+ /* Parse the header descriptor. */
+ if (buffer[2] == VS_OUTPUT_HEADER) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
+ "%d OUTPUT HEADER descriptor is not supported.\n",
+ dev->udev->devnum, alts->desc.bInterfaceNumber);
+ goto error;
+ } else if (buffer[2] == VS_INPUT_HEADER) {
+ p = buflen >= 5 ? buffer[3] : 0;
+ n = buflen >= 12 ? buffer[12] : 0;
+
+ if (buflen < 13 + p*n || buffer[2] != VS_INPUT_HEADER) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+ "interface %d INPUT HEADER descriptor is "
+ "invalid.\n", dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ goto error;
+ }
+
+ streaming->header.bNumFormats = p;
+ streaming->header.bEndpointAddress = buffer[6];
+ streaming->header.bmInfo = buffer[7];
+ streaming->header.bTerminalLink = buffer[8];
+ streaming->header.bStillCaptureMethod = buffer[9];
+ streaming->header.bTriggerSupport = buffer[10];
+ streaming->header.bTriggerUsage = buffer[11];
+ streaming->header.bControlSize = n;
+
+ streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL);
+ if (streaming->header.bmaControls == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ memcpy(streaming->header.bmaControls, &buffer[13], p*n);
+ } else {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
+ "%d HEADER descriptor not found.\n", dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
+ goto error;
+ }
+
+ buflen -= buffer[0];
+ buffer += buffer[0];
+
+ _buffer = buffer;
+ _buflen = buflen;
+
+ /* Count the format and frame descriptors. */
+ while (_buflen > 2) {
+ switch (_buffer[2]) {
+ case VS_FORMAT_UNCOMPRESSED:
+ case VS_FORMAT_MJPEG:
+ case VS_FORMAT_FRAME_BASED:
+ nformats++;
+ break;
+
+ case VS_FORMAT_DV:
+ /* DV format has no frame descriptor. We will create a
+ * dummy frame descriptor with a dummy frame interval.
+ */
+ nformats++;
+ nframes++;
+ nintervals++;
+ break;
+
+ case VS_FORMAT_MPEG2TS:
+ case VS_FORMAT_STREAM_BASED:
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+ "interface %d FORMAT %u is not supported.\n",
+ dev->udev->devnum,
+ alts->desc.bInterfaceNumber, _buffer[2]);
+ break;
+
+ case VS_FRAME_UNCOMPRESSED:
+ case VS_FRAME_MJPEG:
+ nframes++;
+ if (_buflen > 25)
+ nintervals += _buffer[25] ? _buffer[25] : 3;
+ break;
+
+ case VS_FRAME_FRAME_BASED:
+ nframes++;
+ if (_buflen > 21)
+ nintervals += _buffer[21] ? _buffer[21] : 3;
+ break;
+ }
+
+ _buflen -= _buffer[0];
+ _buffer += _buffer[0];
+ }
+
+ if (nformats == 0) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
+ "%d has no supported formats defined.\n",
+ dev->udev->devnum, alts->desc.bInterfaceNumber);
+ goto error;
+ }
+
+ size = nformats * sizeof *format + nframes * sizeof *frame
+ + nintervals * sizeof *interval;
+ format = kzalloc(size, GFP_KERNEL);
+ if (format == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ frame = (struct uvc_frame *)&format[nformats];
+ interval = (__u32 *)&frame[nframes];
+
+ streaming->format = format;
+ streaming->nformats = nformats;
+
+ /* Parse the format descriptors. */
+ while (buflen > 2) {
+ switch (buffer[2]) {
+ case VS_FORMAT_UNCOMPRESSED:
+ case VS_FORMAT_MJPEG:
+ case VS_FORMAT_DV:
+ case VS_FORMAT_FRAME_BASED:
+ format->frame = frame;
+ ret = uvc_parse_format(dev, streaming, format,
+ &interval, buffer, buflen);
+ if (ret < 0)
+ goto error;
+
+ frame += format->nframes;
+ format++;
+
+ buflen -= ret;
+ buffer += ret;
+ continue;
+
+ default:
+ break;
+ }
+
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ /* Parse the alternate settings to find the maximum bandwidth. */
+ for (i = 0; i < intf->num_altsetting; ++i) {
+ struct usb_host_endpoint *ep;
+ alts = &intf->altsetting[i];
+ ep = uvc_find_endpoint(alts,
+ streaming->header.bEndpointAddress);
+ if (ep == NULL)
+ continue;
+
+ psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+ psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+ if (psize > streaming->maxpsize)
+ streaming->maxpsize = psize;
+ }
+
+ list_add_tail(&streaming->list, &dev->streaming);
+ return 0;
+
+error:
+ usb_driver_release_interface(&uvc_driver.driver, intf);
+ usb_put_intf(intf);
+ kfree(streaming->format);
+ kfree(streaming->header.bmaControls);
+ kfree(streaming);
+ return ret;
+}
+
+/* Parse vendor-specific extensions. */
+static int uvc_parse_vendor_control(struct uvc_device *dev,
+ const unsigned char *buffer, int buflen)
+{
+ struct usb_device *udev = dev->udev;
+ struct usb_host_interface *alts = dev->intf->cur_altsetting;
+ struct uvc_entity *unit;
+ unsigned int n, p;
+ int handled = 0;
+
+ switch (le16_to_cpu(dev->udev->descriptor.idVendor)) {
+ case 0x046d: /* Logitech */
+ if (buffer[1] != 0x41 || buffer[2] != 0x01)
+ break;
+
+ /* Logitech implements several vendor specific functions
+ * through vendor specific extension units (LXU).
+ *
+ * The LXU descriptors are similar to XU descriptors
+ * (see "USB Device Video Class for Video Devices", section
+ * 3.7.2.6 "Extension Unit Descriptor") with the following
+ * differences:
+ *
+ * ----------------------------------------------------------
+ * 0 bLength 1 Number
+ * Size of this descriptor, in bytes: 24+p+n*2
+ * ----------------------------------------------------------
+ * 23+p+n bmControlsType N Bitmap
+ * Individual bits in the set are defined:
+ * 0: Absolute
+ * 1: Relative
+ *
+ * This bitset is mapped exactly the same as bmControls.
+ * ----------------------------------------------------------
+ * 23+p+n*2 bReserved 1 Boolean
+ * ----------------------------------------------------------
+ * 24+p+n*2 iExtension 1 Index
+ * Index of a string descriptor that describes this
+ * extension unit.
+ * ----------------------------------------------------------
+ */
+ p = buflen >= 22 ? buffer[21] : 0;
+ n = buflen >= 25 + p ? buffer[22+p] : 0;
+
+ if (buflen < 25 + p + 2*n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d EXTENSION_UNIT error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ break;
+ }
+
+ unit = kzalloc(sizeof *unit + p + 2*n, GFP_KERNEL);
+ if (unit == NULL)
+ return -ENOMEM;
+
+ unit->id = buffer[3];
+ unit->type = VC_EXTENSION_UNIT;
+ memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
+ unit->extension.bNumControls = buffer[20];
+ unit->extension.bNrInPins =
+ le16_to_cpup((__le16 *)&buffer[21]);
+ unit->extension.baSourceID = (__u8 *)unit + sizeof *unit;
+ memcpy(unit->extension.baSourceID, &buffer[22], p);
+ unit->extension.bControlSize = buffer[22+p];
+ unit->extension.bmControls = (__u8 *)unit + sizeof *unit + p;
+ unit->extension.bmControlsType = (__u8 *)unit + sizeof *unit
+ + p + n;
+ memcpy(unit->extension.bmControls, &buffer[23+p], 2*n);
+
+ if (buffer[24+p+2*n] != 0)
+ usb_string(udev, buffer[24+p+2*n], unit->name,
+ sizeof unit->name);
+ else
+ sprintf(unit->name, "Extension %u", buffer[3]);
+
+ list_add_tail(&unit->list, &dev->entities);
+ handled = 1;
+ break;
+ }
+
+ return handled;
+}
+
+static int uvc_parse_standard_control(struct uvc_device *dev,
+ const unsigned char *buffer, int buflen)
+{
+ struct usb_device *udev = dev->udev;
+ struct uvc_entity *unit, *term;
+ struct usb_interface *intf;
+ struct usb_host_interface *alts = dev->intf->cur_altsetting;
+ unsigned int i, n, p, len;
+ __u16 type;
+
+ switch (buffer[2]) {
+ case VC_HEADER:
+ n = buflen >= 12 ? buffer[11] : 0;
+
+ if (buflen < 12 || buflen < 12 + n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d HEADER error\n", udev->devnum,
+ alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ dev->uvc_version = le16_to_cpup((__le16 *)&buffer[3]);
+ dev->clock_frequency = le32_to_cpup((__le32 *)&buffer[7]);
+
+ /* Parse all USB Video Streaming interfaces. */
+ for (i = 0; i < n; ++i) {
+ intf = usb_ifnum_to_if(udev, buffer[12+i]);
+ if (intf == NULL) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d "
+ "interface %d doesn't exists\n",
+ udev->devnum, i);
+ continue;
+ }
+
+ uvc_parse_streaming(dev, intf);
+ }
+ break;
+
+ case VC_INPUT_TERMINAL:
+ if (buflen < 8) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d INPUT_TERMINAL error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ /* Make sure the terminal type MSB is not null, otherwise it
+ * could be confused with a unit.
+ */
+ type = le16_to_cpup((__le16 *)&buffer[4]);
+ if ((type & 0xff00) == 0) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d INPUT_TERMINAL %d has invalid "
+ "type 0x%04x, skipping\n", udev->devnum,
+ alts->desc.bInterfaceNumber,
+ buffer[3], type);
+ return 0;
+ }
+
+ n = 0;
+ p = 0;
+ len = 8;
+
+ if (type == ITT_CAMERA) {
+ n = buflen >= 15 ? buffer[14] : 0;
+ len = 15;
+
+ } else if (type == ITT_MEDIA_TRANSPORT_INPUT) {
+ n = buflen >= 9 ? buffer[8] : 0;
+ p = buflen >= 10 + n ? buffer[9+n] : 0;
+ len = 10;
+ }
+
+ if (buflen < len + n + p) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d INPUT_TERMINAL error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ term = kzalloc(sizeof *term + n + p, GFP_KERNEL);
+ if (term == NULL)
+ return -ENOMEM;
+
+ term->id = buffer[3];
+ term->type = type | UVC_TERM_INPUT;
+
+ if (UVC_ENTITY_TYPE(term) == ITT_CAMERA) {
+ term->camera.bControlSize = n;
+ term->camera.bmControls = (__u8 *)term + sizeof *term;
+ term->camera.wObjectiveFocalLengthMin =
+ le16_to_cpup((__le16 *)&buffer[8]);
+ term->camera.wObjectiveFocalLengthMax =
+ le16_to_cpup((__le16 *)&buffer[10]);
+ term->camera.wOcularFocalLength =
+ le16_to_cpup((__le16 *)&buffer[12]);
+ memcpy(term->camera.bmControls, &buffer[15], n);
+ } else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT) {
+ term->media.bControlSize = n;
+ term->media.bmControls = (__u8 *)term + sizeof *term;
+ term->media.bTransportModeSize = p;
+ term->media.bmTransportModes = (__u8 *)term
+ + sizeof *term + n;
+ memcpy(term->media.bmControls, &buffer[9], n);
+ memcpy(term->media.bmTransportModes, &buffer[10+n], p);
+ }
+
+ if (buffer[7] != 0)
+ usb_string(udev, buffer[7], term->name,
+ sizeof term->name);
+ else if (UVC_ENTITY_TYPE(term) == ITT_CAMERA)
+ sprintf(term->name, "Camera %u", buffer[3]);
+ else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT)
+ sprintf(term->name, "Media %u", buffer[3]);
+ else
+ sprintf(term->name, "Input %u", buffer[3]);
+
+ list_add_tail(&term->list, &dev->entities);
+ break;
+
+ case VC_OUTPUT_TERMINAL:
+ if (buflen < 9) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d OUTPUT_TERMINAL error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ /* Make sure the terminal type MSB is not null, otherwise it
+ * could be confused with a unit.
+ */
+ type = le16_to_cpup((__le16 *)&buffer[4]);
+ if ((type & 0xff00) == 0) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d OUTPUT_TERMINAL %d has invalid "
+ "type 0x%04x, skipping\n", udev->devnum,
+ alts->desc.bInterfaceNumber, buffer[3], type);
+ return 0;
+ }
+
+ term = kzalloc(sizeof *term, GFP_KERNEL);
+ if (term == NULL)
+ return -ENOMEM;
+
+ term->id = buffer[3];
+ term->type = type | UVC_TERM_OUTPUT;
+ term->output.bSourceID = buffer[7];
+
+ if (buffer[8] != 0)
+ usb_string(udev, buffer[8], term->name,
+ sizeof term->name);
+ else
+ sprintf(term->name, "Output %u", buffer[3]);
+
+ list_add_tail(&term->list, &dev->entities);
+ break;
+
+ case VC_SELECTOR_UNIT:
+ p = buflen >= 5 ? buffer[4] : 0;
+
+ if (buflen < 5 || buflen < 6 + p) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d SELECTOR_UNIT error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ unit = kzalloc(sizeof *unit + p, GFP_KERNEL);
+ if (unit == NULL)
+ return -ENOMEM;
+
+ unit->id = buffer[3];
+ unit->type = buffer[2];
+ unit->selector.bNrInPins = buffer[4];
+ unit->selector.baSourceID = (__u8 *)unit + sizeof *unit;
+ memcpy(unit->selector.baSourceID, &buffer[5], p);
+
+ if (buffer[5+p] != 0)
+ usb_string(udev, buffer[5+p], unit->name,
+ sizeof unit->name);
+ else
+ sprintf(unit->name, "Selector %u", buffer[3]);
+
+ list_add_tail(&unit->list, &dev->entities);
+ break;
+
+ case VC_PROCESSING_UNIT:
+ n = buflen >= 8 ? buffer[7] : 0;
+ p = dev->uvc_version >= 0x0110 ? 10 : 9;
+
+ if (buflen < p + n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d PROCESSING_UNIT error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ unit = kzalloc(sizeof *unit + n, GFP_KERNEL);
+ if (unit == NULL)
+ return -ENOMEM;
+
+ unit->id = buffer[3];
+ unit->type = buffer[2];
+ unit->processing.bSourceID = buffer[4];
+ unit->processing.wMaxMultiplier =
+ le16_to_cpup((__le16 *)&buffer[5]);
+ unit->processing.bControlSize = buffer[7];
+ unit->processing.bmControls = (__u8 *)unit + sizeof *unit;
+ memcpy(unit->processing.bmControls, &buffer[8], n);
+ if (dev->uvc_version >= 0x0110)
+ unit->processing.bmVideoStandards = buffer[9+n];
+
+ if (buffer[8+n] != 0)
+ usb_string(udev, buffer[8+n], unit->name,
+ sizeof unit->name);
+ else
+ sprintf(unit->name, "Processing %u", buffer[3]);
+
+ list_add_tail(&unit->list, &dev->entities);
+ break;
+
+ case VC_EXTENSION_UNIT:
+ p = buflen >= 22 ? buffer[21] : 0;
+ n = buflen >= 24 + p ? buffer[22+p] : 0;
+
+ if (buflen < 24 + p + n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+ "interface %d EXTENSION_UNIT error\n",
+ udev->devnum, alts->desc.bInterfaceNumber);
+ return -EINVAL;
+ }
+
+ unit = kzalloc(sizeof *unit + p + n, GFP_KERNEL);
+ if (unit == NULL)
+ return -ENOMEM;
+
+ unit->id = buffer[3];
+ unit->type = buffer[2];
+ memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
+ unit->extension.bNumControls = buffer[20];
+ unit->extension.bNrInPins =
+ le16_to_cpup((__le16 *)&buffer[21]);
+ unit->extension.baSourceID = (__u8 *)unit + sizeof *unit;
+ memcpy(unit->extension.baSourceID, &buffer[22], p);
+ unit->extension.bControlSize = buffer[22+p];
+ unit->extension.bmControls = (__u8 *)unit + sizeof *unit + p;
+ memcpy(unit->extension.bmControls, &buffer[23+p], n);
+
+ if (buffer[23+p+n] != 0)
+ usb_string(udev, buffer[23+p+n], unit->name,
+ sizeof unit->name);
+ else
+ sprintf(unit->name, "Extension %u", buffer[3]);
+
+ list_add_tail(&unit->list, &dev->entities);
+ break;
+
+ default:
+ uvc_trace(UVC_TRACE_DESCR, "Found an unknown CS_INTERFACE "
+ "descriptor (%u)\n", buffer[2]);
+ break;
+ }
+
+ return 0;
+}
+
+static int uvc_parse_control(struct uvc_device *dev)
+{
+ struct usb_host_interface *alts = dev->intf->cur_altsetting;
+ unsigned char *buffer = alts->extra;
+ int buflen = alts->extralen;
+ int ret;
+
+ /* Parse the default alternate setting only, as the UVC specification
+ * defines a single alternate setting, the default alternate setting
+ * zero.
+ */
+
+ while (buflen > 2) {
+ if (uvc_parse_vendor_control(dev, buffer, buflen) ||
+ buffer[1] != USB_DT_CS_INTERFACE)
+ goto next_descriptor;
+
+ if ((ret = uvc_parse_standard_control(dev, buffer, buflen)) < 0)
+ return ret;
+
+next_descriptor:
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ /* Check if the optional status endpoint is present. */
+ if (alts->desc.bNumEndpoints == 1) {
+ struct usb_host_endpoint *ep = &alts->endpoint[0];
+ struct usb_endpoint_descriptor *desc = &ep->desc;
+
+ if (usb_endpoint_is_int_in(desc) &&
+ le16_to_cpu(desc->wMaxPacketSize) >= 8 &&
+ desc->bInterval != 0) {
+ uvc_trace(UVC_TRACE_DESCR, "Found a Status endpoint "
+ "(addr %02x).\n", desc->bEndpointAddress);
+ dev->int_ep = ep;
+ }
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * USB probe and disconnect
+ */
+
+/*
+ * Unregister the video devices.
+ */
+static void uvc_unregister_video(struct uvc_device *dev)
+{
+ if (dev->video.vdev) {
+ if (dev->video.vdev->minor == -1)
+ video_device_release(dev->video.vdev);
+ else
+ video_unregister_device(dev->video.vdev);
+ dev->video.vdev = NULL;
+ }
+}
+
+/*
+ * Scan the UVC descriptors to locate a chain starting at an Output Terminal
+ * and containing the following units:
+ *
+ * - a USB Streaming Output Terminal
+ * - zero or one Processing Unit
+ * - zero, one or mode single-input Selector Units
+ * - zero or one multiple-input Selector Units, provided all inputs are
+ * connected to input terminals
+ * - zero, one or mode single-input Extension Units
+ * - one Camera Input Terminal, or one or more External terminals.
+ *
+ * A side forward scan is made on each detected entity to check for additional
+ * extension units.
+ */
+static int uvc_scan_chain_entity(struct uvc_video_device *video,
+ struct uvc_entity *entity)
+{
+ switch (UVC_ENTITY_TYPE(entity)) {
+ case VC_EXTENSION_UNIT:
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- XU %d", entity->id);
+
+ if (entity->extension.bNrInPins != 1) {
+ uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more "
+ "than 1 input pin.\n", entity->id);
+ return -1;
+ }
+
+ list_add_tail(&entity->chain, &video->extensions);
+ break;
+
+ case VC_PROCESSING_UNIT:
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- PU %d", entity->id);
+
+ if (video->processing != NULL) {
+ uvc_trace(UVC_TRACE_DESCR, "Found multiple "
+ "Processing Units in chain.\n");
+ return -1;
+ }
+
+ video->processing = entity;
+ break;
+
+ case VC_SELECTOR_UNIT:
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- SU %d", entity->id);
+
+ /* Single-input selector units are ignored. */
+ if (entity->selector.bNrInPins == 1)
+ break;
+
+ if (video->selector != NULL) {
+ uvc_trace(UVC_TRACE_DESCR, "Found multiple Selector "
+ "Units in chain.\n");
+ return -1;
+ }
+
+ video->selector = entity;
+ break;
+
+ case ITT_VENDOR_SPECIFIC:
+ case ITT_CAMERA:
+ case ITT_MEDIA_TRANSPORT_INPUT:
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- IT %d\n", entity->id);
+
+ list_add_tail(&entity->chain, &video->iterms);
+ break;
+
+ default:
+ uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type "
+ "0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int uvc_scan_chain_forward(struct uvc_video_device *video,
+ struct uvc_entity *entity, struct uvc_entity *prev)
+{
+ struct uvc_entity *forward;
+ int found;
+
+ /* Forward scan */
+ forward = NULL;
+ found = 0;
+
+ while (1) {
+ forward = uvc_entity_by_reference(video->dev, entity->id,
+ forward);
+ if (forward == NULL)
+ break;
+
+ if (UVC_ENTITY_TYPE(forward) != VC_EXTENSION_UNIT ||
+ forward == prev)
+ continue;
+
+ if (forward->extension.bNrInPins != 1) {
+ uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has"
+ "more than 1 input pin.\n", entity->id);
+ return -1;
+ }
+
+ list_add_tail(&forward->chain, &video->extensions);
+ if (uvc_trace_param & UVC_TRACE_PROBE) {
+ if (!found)
+ printk(" (-> XU");
+
+ printk(" %d", forward->id);
+ found = 1;
+ }
+ }
+ if (found)
+ printk(")");
+
+ return 0;
+}
+
+static int uvc_scan_chain_backward(struct uvc_video_device *video,
+ struct uvc_entity *entity)
+{
+ struct uvc_entity *term;
+ int id = -1, i;
+
+ switch (UVC_ENTITY_TYPE(entity)) {
+ case VC_EXTENSION_UNIT:
+ id = entity->extension.baSourceID[0];
+ break;
+
+ case VC_PROCESSING_UNIT:
+ id = entity->processing.bSourceID;
+ break;
+
+ case VC_SELECTOR_UNIT:
+ /* Single-input selector units are ignored. */
+ if (entity->selector.bNrInPins == 1) {
+ id = entity->selector.baSourceID[0];
+ break;
+ }
+
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- IT");
+
+ video->selector = entity;
+ for (i = 0; i < entity->selector.bNrInPins; ++i) {
+ id = entity->selector.baSourceID[i];
+ term = uvc_entity_by_id(video->dev, id);
+ if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) {
+ uvc_trace(UVC_TRACE_DESCR, "Selector unit %d "
+ "input %d isn't connected to an "
+ "input terminal\n", entity->id, i);
+ return -1;
+ }
+
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" %d", term->id);
+
+ list_add_tail(&term->chain, &video->iterms);
+ uvc_scan_chain_forward(video, term, entity);
+ }
+
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk("\n");
+
+ id = 0;
+ break;
+ }
+
+ return id;
+}
+
+static int uvc_scan_chain(struct uvc_video_device *video)
+{
+ struct uvc_entity *entity, *prev;
+ int id;
+
+ entity = video->oterm;
+ uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id);
+ id = entity->output.bSourceID;
+ while (id != 0) {
+ prev = entity;
+ entity = uvc_entity_by_id(video->dev, id);
+ if (entity == NULL) {
+ uvc_trace(UVC_TRACE_DESCR, "Found reference to "
+ "unknown entity %d.\n", id);
+ return -1;
+ }
+
+ /* Process entity */
+ if (uvc_scan_chain_entity(video, entity) < 0)
+ return -1;
+
+ /* Forward scan */
+ if (uvc_scan_chain_forward(video, entity, prev) < 0)
+ return -1;
+
+ /* Stop when a terminal is found. */
+ if (!UVC_ENTITY_IS_UNIT(entity))
+ break;
+
+ /* Backward scan */
+ id = uvc_scan_chain_backward(video, entity);
+ if (id < 0)
+ return id;
+ }
+
+ /* Initialize the video buffers queue. */
+ uvc_queue_init(&video->queue);
+
+ return 0;
+}
+
+/*
+ * Register the video devices.
+ *
+ * The driver currently supports a single video device per control interface
+ * only. The terminal and units must match the following structure:
+ *
+ * ITT_CAMERA -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING
+ *
+ * The Extension Units, if present, must have a single input pin. The
+ * Processing Unit and Extension Units can be in any order. Additional
+ * Extension Units connected to the main chain as single-unit branches are
+ * also supported.
+ */
+static int uvc_register_video(struct uvc_device *dev)
+{
+ struct video_device *vdev;
+ struct uvc_entity *term;
+ int found = 0, ret;
+
+ /* Check if the control interface matches the structure we expect. */
+ list_for_each_entry(term, &dev->entities, list) {
+ struct uvc_streaming *streaming;
+
+ if (UVC_ENTITY_TYPE(term) != TT_STREAMING)
+ continue;
+
+ memset(&dev->video, 0, sizeof dev->video);
+ mutex_init(&dev->video.ctrl_mutex);
+ INIT_LIST_HEAD(&dev->video.iterms);
+ INIT_LIST_HEAD(&dev->video.extensions);
+ dev->video.oterm = term;
+ dev->video.dev = dev;
+ if (uvc_scan_chain(&dev->video) < 0)
+ continue;
+
+ list_for_each_entry(streaming, &dev->streaming, list) {
+ if (streaming->header.bTerminalLink == term->id) {
+ dev->video.streaming = streaming;
+ found = 1;
+ break;
+ }
+ }
+
+ if (found)
+ break;
+ }
+
+ if (!found) {
+ uvc_printk(KERN_INFO, "No valid video chain found.\n");
+ return -1;
+ }
+
+ if (uvc_trace_param & UVC_TRACE_PROBE) {
+ uvc_printk(KERN_INFO, "Found a valid video chain (");
+ list_for_each_entry(term, &dev->video.iterms, chain) {
+ printk("%d", term->id);
+ if (term->chain.next != &dev->video.iterms)
+ printk(",");
+ }
+ printk(" -> %d).\n", dev->video.oterm->id);
+ }
+
+ /* Initialize the streaming interface with default streaming
+ * parameters.
+ */
+ if ((ret = uvc_video_init(&dev->video)) < 0) {
+ uvc_printk(KERN_ERR, "Failed to initialize the device "
+ "(%d).\n", ret);
+ return ret;
+ }
+
+ /* Register the device with V4L. */
+ vdev = video_device_alloc();
+ if (vdev == NULL)
+ return -1;
+
+ /* We already hold a reference to dev->udev. The video device will be
+ * unregistered before the reference is released, so we don't need to
+ * get another one.
+ */
+ vdev->dev = &dev->intf->dev;
+ vdev->type = 0;
+ vdev->type2 = 0;
+ vdev->minor = -1;
+ vdev->fops = &uvc_fops;
+ vdev->release = video_device_release;
+ strncpy(vdev->name, dev->name, sizeof vdev->name);
+
+ /* Set the driver data before calling video_register_device, otherwise
+ * uvc_v4l2_open might race us.
+ *
+ * FIXME: usb_set_intfdata hasn't been called so far. Is that a
+ * problem ? Does any function which could be called here get
+ * a pointer to the usb_interface ?
+ */
+ dev->video.vdev = vdev;
+ video_set_drvdata(vdev, &dev->video);
+
+ if (video_register_device(vdev, VFL_TYPE_GRABBER, -1) < 0) {
+ dev->video.vdev = NULL;
+ video_device_release(vdev);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Delete the UVC device.
+ *
+ * Called by the kernel when the last reference to the uvc_device structure
+ * is released.
+ *
+ * Unregistering the video devices is done here because every opened instance
+ * must be closed before the device can be unregistered. An alternative would
+ * have been to use another reference count for uvc_v4l2_open/uvc_release, and
+ * unregister the video devices on disconnect when that reference count drops
+ * to zero.
+ *
+ * As this function is called after or during disconnect(), all URBs have
+ * already been canceled by the USB core. There is no need to kill the
+ * interrupt URB manually.
+ */
+void uvc_delete(struct kref *kref)
+{
+ struct uvc_device *dev = container_of(kref, struct uvc_device, kref);
+ struct list_head *p, *n;
+
+ /* Unregister the video device */
+ uvc_unregister_video(dev);
+ usb_put_intf(dev->intf);
+ usb_put_dev(dev->udev);
+
+ uvc_status_cleanup(dev);
+ uvc_ctrl_cleanup_device(dev);
+
+ list_for_each_safe(p, n, &dev->entities) {
+ struct uvc_entity *entity;
+ entity = list_entry(p, struct uvc_entity, list);
+ kfree(entity);
+ }
+
+ list_for_each_safe(p, n, &dev->streaming) {
+ struct uvc_streaming *streaming;
+ streaming = list_entry(p, struct uvc_streaming, list);
+ usb_driver_release_interface(&uvc_driver.driver,
+ streaming->intf);
+ usb_put_intf(streaming->intf);
+ kfree(streaming->format);
+ kfree(streaming->header.bmaControls);
+ kfree(streaming);
+ }
+
+ kfree(dev);
+}
+
+static int uvc_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct uvc_device *dev;
+ int ret;
+
+ if (id->idVendor && id->idProduct)
+ uvc_trace(UVC_TRACE_PROBE, "Probing known UVC device %s "
+ "(%04x:%04x)\n", udev->devpath, id->idVendor,
+ id->idProduct);
+ else
+ uvc_trace(UVC_TRACE_PROBE, "Probing generic UVC device %s\n",
+ udev->devpath);
+
+ /* Allocate memory for the device and initialize it */
+ if ((dev = kzalloc(sizeof *dev, GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&dev->entities);
+ INIT_LIST_HEAD(&dev->streaming);
+ kref_init(&dev->kref);
+
+ dev->udev = usb_get_dev(udev);
+ dev->intf = usb_get_intf(intf);
+ dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
+ dev->quirks = id->driver_info | uvc_quirks_param;
+
+ if (udev->product != NULL)
+ strncpy(dev->name, udev->product, sizeof dev->name);
+ else
+ snprintf(dev->name, sizeof dev->name,
+ "UVC Camera (%04x:%04x)",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
+
+ /* Parse the Video Class control descriptor */
+ if (uvc_parse_control(dev) < 0) {
+ uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC "
+ "descriptors.\n");
+ goto error;
+ }
+
+ uvc_printk(KERN_INFO, "Found UVC %u.%02u device %s (%04x:%04x)\n",
+ dev->uvc_version >> 8, dev->uvc_version & 0xff,
+ udev->product ? udev->product : "<unnamed>",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
+
+ if (uvc_quirks_param != 0) {
+ uvc_printk(KERN_INFO, "Forcing device quirks 0x%x by module "
+ "parameter for testing purpose.\n", uvc_quirks_param);
+ uvc_printk(KERN_INFO, "Please report required quirks to the "
+ "linux-uvc-devel mailing list.\n");
+ }
+
+ /* Initialize controls */
+ if (uvc_ctrl_init_device(dev) < 0)
+ goto error;
+
+ /* Register the video devices */
+ if (uvc_register_video(dev) < 0)
+ goto error;
+
+ /* Save our data pointer in the interface data */
+ usb_set_intfdata(intf, dev);
+
+ /* Initialize the interrupt URB */
+ if ((ret = uvc_status_init(dev)) < 0) {
+ uvc_printk(KERN_INFO, "Unable to initialize the status "
+ "endpoint (%d), status interrupt will not be "
+ "supported.\n", ret);
+ }
+
+ uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n");
+ return 0;
+
+error:
+ kref_put(&dev->kref, uvc_delete);
+ return -ENODEV;
+}
+
+static void uvc_disconnect(struct usb_interface *intf)
+{
+ struct uvc_device *dev = usb_get_intfdata(intf);
+
+ /* Set the USB interface data to NULL. This can be done outside the
+ * lock, as there's no other reader.
+ */
+ usb_set_intfdata(intf, NULL);
+
+ if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOSTREAMING)
+ return;
+
+ /* uvc_v4l2_open() might race uvc_disconnect(). A static driver-wide
+ * lock is needed to prevent uvc_disconnect from releasing its
+ * reference to the uvc_device instance after uvc_v4l2_open() received
+ * the pointer to the device (video_devdata) but before it got the
+ * chance to increase the reference count (kref_get).
+ */
+ mutex_lock(&uvc_driver.open_mutex);
+
+ dev->state |= UVC_DEV_DISCONNECTED;
+ kref_put(&dev->kref, uvc_delete);
+
+ mutex_unlock(&uvc_driver.open_mutex);
+}
+
+static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct uvc_device *dev = usb_get_intfdata(intf);
+
+ uvc_trace(UVC_TRACE_SUSPEND, "Suspending interface %u\n",
+ intf->cur_altsetting->desc.bInterfaceNumber);
+
+ /* Controls are cached on the fly so they don't need to be saved. */
+ if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL)
+ return uvc_status_suspend(dev);
+
+ if (dev->video.streaming->intf != intf) {
+ uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB "
+ "interface mismatch.\n");
+ return -EINVAL;
+ }
+
+ return uvc_video_suspend(&dev->video);
+}
+
+static int uvc_resume(struct usb_interface *intf)
+{
+ struct uvc_device *dev = usb_get_intfdata(intf);
+ int ret;
+
+ uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n",
+ intf->cur_altsetting->desc.bInterfaceNumber);
+
+ if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL) {
+ if ((ret = uvc_ctrl_resume_device(dev)) < 0)
+ return ret;
+
+ return uvc_status_resume(dev);
+ }
+
+ if (dev->video.streaming->intf != intf) {
+ uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB "
+ "interface mismatch.\n");
+ return -EINVAL;
+ }
+
+ return uvc_video_resume(&dev->video);
+}
+
+/* ------------------------------------------------------------------------
+ * Driver initialization and cleanup
+ */
+
+/*
+ * The Logitech cameras listed below have their interface class set to
+ * VENDOR_SPEC because they don't announce themselves as UVC devices, even
+ * though they are compliant.
+ */
+static struct usb_device_id uvc_ids[] = {
+ /* ALi M5606 (Clevo M540SR) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0402,
+ .idProduct = 0x5606,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Creative Live! Optia */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x041e,
+ .idProduct = 0x4057,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Microsoft Lifecam NX-6000 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x045e,
+ .idProduct = 0x00f8,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Microsoft Lifecam VX-7000 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x045e,
+ .idProduct = 0x0723,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Logitech Quickcam Fusion */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c1,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Logitech Quickcam Orbit MP */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c2,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Logitech Quickcam Pro for Notebook */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c3,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Logitech Quickcam Pro 5000 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c5,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Logitech Quickcam OEM Dell Notebook */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c6,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Logitech Quickcam OEM Cisco VT Camera II */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c7,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0 },
+ /* Apple Built-In iSight */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x05ac,
+ .idProduct = 0x8501,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX
+ | UVC_QUIRK_BUILTIN_ISIGHT },
+ /* Genesys Logic USB 2.0 PC Camera */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x05e3,
+ .idProduct = 0x0505,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Silicon Motion SM371 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x090c,
+ .idProduct = 0xb371,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* MT6227 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0e8d,
+ .idProduct = 0x0004,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Syntek (HP Spartan) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x174f,
+ .idProduct = 0x5212,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Syntek (Asus U3S) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x174f,
+ .idProduct = 0x8a33,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Ecamm Pico iMage */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x18cd,
+ .idProduct = 0xcafe,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS },
+ /* Bodelin ProScopeHR */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_DEV_HI
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x19ab,
+ .idProduct = 0x1000,
+ .bcdDevice_hi = 0x0126,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STATUS_INTERVAL },
+ /* SiGma Micro USB Web Camera */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x1c4f,
+ .idProduct = 0x3000,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX
+ | UVC_QUIRK_IGNORE_SELECTOR_UNIT},
+ /* Acer OEM Webcam - Unknown vendor */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x5986,
+ .idProduct = 0x0100,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Packard Bell OEM Webcam */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x5986,
+ .idProduct = 0x0101,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Acer Crystal Eye webcam */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x5986,
+ .idProduct = 0x0102,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Acer OrbiCam - Unknown vendor */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x5986,
+ .idProduct = 0x0200,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ /* Generic USB Video Class */
+ { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, uvc_ids);
+
+struct uvc_driver uvc_driver = {
+ .driver = {
+ .name = "uvcvideo",
+ .probe = uvc_probe,
+ .disconnect = uvc_disconnect,
+ .suspend = uvc_suspend,
+ .resume = uvc_resume,
+ .id_table = uvc_ids,
+ .supports_autosuspend = 1,
+ },
+};
+
+static int __init uvc_init(void)
+{
+ int result;
+
+ INIT_LIST_HEAD(&uvc_driver.devices);
+ INIT_LIST_HEAD(&uvc_driver.controls);
+ mutex_init(&uvc_driver.open_mutex);
+ mutex_init(&uvc_driver.ctrl_mutex);
+
+ uvc_ctrl_init();
+
+ result = usb_register(&uvc_driver.driver);
+ if (result == 0)
+ printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n");
+ return result;
+}
+
+static void __exit uvc_cleanup(void)
+{
+ usb_deregister(&uvc_driver.driver);
+}
+
+module_init(uvc_init);
+module_exit(uvc_cleanup);
+
+module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(quirks, "Forced device quirks");
+module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(trace, "Trace level bitmask");
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/media/video/uvc/uvc_isight.c b/drivers/media/video/uvc/uvc_isight.c
new file mode 100644
index 000000000000..37bdefdbead5
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_isight.c
@@ -0,0 +1,134 @@
+/*
+ * uvc_isight.c -- USB Video Class driver - iSight support
+ *
+ * Copyright (C) 2006-2007
+ * Ivan N. Zlatev <contact@i-nz.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+
+#include "uvcvideo.h"
+
+/* Built-in iSight webcams implements most of UVC 1.0 except a
+ * different packet format. Instead of sending a header at the
+ * beginning of each isochronous transfer payload, the webcam sends a
+ * single header per image (on its own in a packet), followed by
+ * packets containing data only.
+ *
+ * Offset Size (bytes) Description
+ * ------------------------------------------------------------------
+ * 0x00 1 Header length
+ * 0x01 1 Flags (UVC-compliant)
+ * 0x02 4 Always equal to '11223344'
+ * 0x06 8 Always equal to 'deadbeefdeadface'
+ * 0x0e 16 Unknown
+ *
+ * The header can be prefixed by an optional, unknown-purpose byte.
+ */
+
+static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf,
+ const __u8 *data, unsigned int len)
+{
+ static const __u8 hdr[] = {
+ 0x11, 0x22, 0x33, 0x44,
+ 0xde, 0xad, 0xbe, 0xef,
+ 0xde, 0xad, 0xfa, 0xce
+ };
+
+ unsigned int maxlen, nbytes;
+ __u8 *mem;
+ int is_header = 0;
+
+ if (buf == NULL)
+ return 0;
+
+ if ((len >= 14 && memcmp(&data[2], hdr, 12) == 0) ||
+ (len >= 15 && memcmp(&data[3], hdr, 12) == 0)) {
+ uvc_trace(UVC_TRACE_FRAME, "iSight header found\n");
+ is_header = 1;
+ }
+
+ /* Synchronize to the input stream by waiting for a header packet. */
+ if (buf->state != UVC_BUF_STATE_ACTIVE) {
+ if (!is_header) {
+ uvc_trace(UVC_TRACE_FRAME, "Dropping packet (out of "
+ "sync).\n");
+ return 0;
+ }
+
+ buf->state = UVC_BUF_STATE_ACTIVE;
+ }
+
+ /* Mark the buffer as done if we're at the beginning of a new frame.
+ *
+ * Empty buffers (bytesused == 0) don't trigger end of frame detection
+ * as it doesn't make sense to return an empty buffer.
+ */
+ if (is_header && buf->buf.bytesused != 0) {
+ buf->state = UVC_BUF_STATE_DONE;
+ return -EAGAIN;
+ }
+
+ /* Copy the video data to the buffer. Skip header packets, as they
+ * contain no data.
+ */
+ if (!is_header) {
+ maxlen = buf->buf.length - buf->buf.bytesused;
+ mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
+ nbytes = min(len, maxlen);
+ memcpy(mem, data, nbytes);
+ buf->buf.bytesused += nbytes;
+
+ if (len > maxlen || buf->buf.bytesused == buf->buf.length) {
+ uvc_trace(UVC_TRACE_FRAME, "Frame complete "
+ "(overflow).\n");
+ buf->state = UVC_BUF_STATE_DONE;
+ }
+ }
+
+ return 0;
+}
+
+void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
+ struct uvc_buffer *buf)
+{
+ int ret, i;
+
+ for (i = 0; i < urb->number_of_packets; ++i) {
+ if (urb->iso_frame_desc[i].status < 0) {
+ uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "
+ "lost (%d).\n",
+ urb->iso_frame_desc[i].status);
+ }
+
+ /* Decode the payload packet.
+ * uvc_video_decode is entered twice when a frame transition
+ * has been detected because the end of frame can only be
+ * reliably detected when the first packet of the new frame
+ * is processed. The first pass detects the transition and
+ * closes the previous frame's buffer, the second pass
+ * processes the data of the first payload of the new frame.
+ */
+ do {
+ ret = isight_decode(&video->queue, buf,
+ urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].actual_length);
+
+ if (buf == NULL)
+ break;
+
+ if (buf->state == UVC_BUF_STATE_DONE ||
+ buf->state == UVC_BUF_STATE_ERROR)
+ buf = uvc_queue_next_buffer(&video->queue, buf);
+ } while (ret == -EAGAIN);
+ }
+}
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
new file mode 100644
index 000000000000..0923f0e3b3d4
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -0,0 +1,477 @@
+/*
+ * uvc_queue.c -- USB Video Class driver - Buffers management
+ *
+ * Copyright (C) 2005-2008
+ * Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include "uvcvideo.h"
+
+/* ------------------------------------------------------------------------
+ * Video buffers queue management.
+ *
+ * Video queues is initialized by uvc_queue_init(). The function performs
+ * basic initialization of the uvc_video_queue struct and never fails.
+ *
+ * Video buffer allocation and freeing are performed by uvc_alloc_buffers and
+ * uvc_free_buffers respectively. The former acquires the video queue lock,
+ * while the later must be called with the lock held (so that allocation can
+ * free previously allocated buffers). Trying to free buffers that are mapped
+ * to user space will return -EBUSY.
+ *
+ * Video buffers are managed using two queues. However, unlike most USB video
+ * drivers which use an in queue and an out queue, we use a main queue which
+ * holds all queued buffers (both 'empty' and 'done' buffers), and an irq
+ * queue which holds empty buffers. This design (copied from video-buf)
+ * minimizes locking in interrupt, as only one queue is shared between
+ * interrupt and user contexts.
+ *
+ * Use cases
+ * ---------
+ *
+ * Unless stated otherwise, all operations which modify the irq buffers queue
+ * are protected by the irq spinlock.
+ *
+ * 1. The user queues the buffers, starts streaming and dequeues a buffer.
+ *
+ * The buffers are added to the main and irq queues. Both operations are
+ * protected by the queue lock, and the latert is protected by the irq
+ * spinlock as well.
+ *
+ * The completion handler fetches a buffer from the irq queue and fills it
+ * with video data. If no buffer is available (irq queue empty), the handler
+ * returns immediately.
+ *
+ * When the buffer is full, the completion handler removes it from the irq
+ * queue, marks it as ready (UVC_BUF_STATE_DONE) and wake its wait queue.
+ * At that point, any process waiting on the buffer will be woken up. If a
+ * process tries to dequeue a buffer after it has been marked ready, the
+ * dequeing will succeed immediately.
+ *
+ * 2. Buffers are queued, user is waiting on a buffer and the device gets
+ * disconnected.
+ *
+ * When the device is disconnected, the kernel calls the completion handler
+ * with an appropriate status code. The handler marks all buffers in the
+ * irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so
+ * that any process waiting on a buffer gets woken up.
+ *
+ * Waking up up the first buffer on the irq list is not enough, as the
+ * process waiting on the buffer might restart the dequeue operation
+ * immediately.
+ *
+ */
+
+void uvc_queue_init(struct uvc_video_queue *queue)
+{
+ mutex_init(&queue->mutex);
+ spin_lock_init(&queue->irqlock);
+ INIT_LIST_HEAD(&queue->mainqueue);
+ INIT_LIST_HEAD(&queue->irqqueue);
+}
+
+/*
+ * Allocate the video buffers.
+ *
+ * Pages are reserved to make sure they will not be swaped, as they will be
+ * filled in URB completion handler.
+ *
+ * Buffers will be individually mapped, so they must all be page aligned.
+ */
+int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
+ unsigned int buflength)
+{
+ unsigned int bufsize = PAGE_ALIGN(buflength);
+ unsigned int i;
+ void *mem = NULL;
+ int ret;
+
+ if (nbuffers > UVC_MAX_VIDEO_BUFFERS)
+ nbuffers = UVC_MAX_VIDEO_BUFFERS;
+
+ mutex_lock(&queue->mutex);
+
+ if ((ret = uvc_free_buffers(queue)) < 0)
+ goto done;
+
+ /* Bail out if no buffers should be allocated. */
+ if (nbuffers == 0)
+ goto done;
+
+ /* Decrement the number of buffers until allocation succeeds. */
+ for (; nbuffers > 0; --nbuffers) {
+ mem = vmalloc_32(nbuffers * bufsize);
+ if (mem != NULL)
+ break;
+ }
+
+ if (mem == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; i < nbuffers; ++i) {
+ memset(&queue->buffer[i], 0, sizeof queue->buffer[i]);
+ queue->buffer[i].buf.index = i;
+ queue->buffer[i].buf.m.offset = i * bufsize;
+ queue->buffer[i].buf.length = buflength;
+ queue->buffer[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ queue->buffer[i].buf.sequence = 0;
+ queue->buffer[i].buf.field = V4L2_FIELD_NONE;
+ queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
+ queue->buffer[i].buf.flags = 0;
+ init_waitqueue_head(&queue->buffer[i].wait);
+ }
+
+ queue->mem = mem;
+ queue->count = nbuffers;
+ queue->buf_size = bufsize;
+ ret = nbuffers;
+
+done:
+ mutex_unlock(&queue->mutex);
+ return ret;
+}
+
+/*
+ * Free the video buffers.
+ *
+ * This function must be called with the queue lock held.
+ */
+int uvc_free_buffers(struct uvc_video_queue *queue)
+{
+ unsigned int i;
+
+ for (i = 0; i < queue->count; ++i) {
+ if (queue->buffer[i].vma_use_count != 0)
+ return -EBUSY;
+ }
+
+ if (queue->count) {
+ vfree(queue->mem);
+ queue->count = 0;
+ }
+
+ return 0;
+}
+
+static void __uvc_query_buffer(struct uvc_buffer *buf,
+ struct v4l2_buffer *v4l2_buf)
+{
+ memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);
+
+ if (buf->vma_use_count)
+ v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED;
+
+ switch (buf->state) {
+ case UVC_BUF_STATE_ERROR:
+ case UVC_BUF_STATE_DONE:
+ v4l2_buf->flags |= V4L2_BUF_FLAG_DONE;
+ break;
+ case UVC_BUF_STATE_QUEUED:
+ case UVC_BUF_STATE_ACTIVE:
+ v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
+ break;
+ case UVC_BUF_STATE_IDLE:
+ default:
+ break;
+ }
+}
+
+int uvc_query_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *v4l2_buf)
+{
+ int ret = 0;
+
+ mutex_lock(&queue->mutex);
+ if (v4l2_buf->index >= queue->count) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ __uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf);
+
+done:
+ mutex_unlock(&queue->mutex);
+ return ret;
+}
+
+/*
+ * Queue a video buffer. Attempting to queue a buffer that has already been
+ * queued will return -EINVAL.
+ */
+int uvc_queue_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *v4l2_buf)
+{
+ struct uvc_buffer *buf;
+ unsigned long flags;
+ int ret = 0;
+
+ uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);
+
+ if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ v4l2_buf->memory != V4L2_MEMORY_MMAP) {
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
+ "and/or memory (%u).\n", v4l2_buf->type,
+ v4l2_buf->memory);
+ return -EINVAL;
+ }
+
+ mutex_lock(&queue->mutex);
+ if (v4l2_buf->index >= queue->count) {
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ buf = &queue->buffer[v4l2_buf->index];
+ if (buf->state != UVC_BUF_STATE_IDLE) {
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state "
+ "(%u).\n", buf->state);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ spin_lock_irqsave(&queue->irqlock, flags);
+ if (queue->flags & UVC_QUEUE_DISCONNECTED) {
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+ ret = -ENODEV;
+ goto done;
+ }
+ buf->state = UVC_BUF_STATE_QUEUED;
+ buf->buf.bytesused = 0;
+ list_add_tail(&buf->stream, &queue->mainqueue);
+ list_add_tail(&buf->queue, &queue->irqqueue);
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+
+done:
+ mutex_unlock(&queue->mutex);
+ return ret;
+}
+
+static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking)
+{
+ if (nonblocking) {
+ return (buf->state != UVC_BUF_STATE_QUEUED &&
+ buf->state != UVC_BUF_STATE_ACTIVE)
+ ? 0 : -EAGAIN;
+ }
+
+ return wait_event_interruptible(buf->wait,
+ buf->state != UVC_BUF_STATE_QUEUED &&
+ buf->state != UVC_BUF_STATE_ACTIVE);
+}
+
+/*
+ * Dequeue a video buffer. If nonblocking is false, block until a buffer is
+ * available.
+ */
+int uvc_dequeue_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *v4l2_buf, int nonblocking)
+{
+ struct uvc_buffer *buf;
+ int ret = 0;
+
+ if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ v4l2_buf->memory != V4L2_MEMORY_MMAP) {
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
+ "and/or memory (%u).\n", v4l2_buf->type,
+ v4l2_buf->memory);
+ return -EINVAL;
+ }
+
+ mutex_lock(&queue->mutex);
+ if (list_empty(&queue->mainqueue)) {
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
+ if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0)
+ goto done;
+
+ uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n",
+ buf->buf.index, buf->state, buf->buf.bytesused);
+
+ switch (buf->state) {
+ case UVC_BUF_STATE_ERROR:
+ uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data "
+ "(transmission error).\n");
+ ret = -EIO;
+ case UVC_BUF_STATE_DONE:
+ buf->state = UVC_BUF_STATE_IDLE;
+ break;
+
+ case UVC_BUF_STATE_IDLE:
+ case UVC_BUF_STATE_QUEUED:
+ case UVC_BUF_STATE_ACTIVE:
+ default:
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u "
+ "(driver bug?).\n", buf->state);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ list_del(&buf->stream);
+ __uvc_query_buffer(buf, v4l2_buf);
+
+done:
+ mutex_unlock(&queue->mutex);
+ return ret;
+}
+
+/*
+ * Poll the video queue.
+ *
+ * This function implements video queue polling and is intended to be used by
+ * the device poll handler.
+ */
+unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
+ poll_table *wait)
+{
+ struct uvc_buffer *buf;
+ unsigned int mask = 0;
+
+ mutex_lock(&queue->mutex);
+ if (list_empty(&queue->mainqueue)) {
+ mask |= POLLERR;
+ goto done;
+ }
+ buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
+
+ poll_wait(file, &buf->wait, wait);
+ if (buf->state == UVC_BUF_STATE_DONE ||
+ buf->state == UVC_BUF_STATE_ERROR)
+ mask |= POLLIN | POLLRDNORM;
+
+done:
+ mutex_unlock(&queue->mutex);
+ return mask;
+}
+
+/*
+ * Enable or disable the video buffers queue.
+ *
+ * The queue must be enabled before starting video acquisition and must be
+ * disabled after stopping it. This ensures that the video buffers queue
+ * state can be properly initialized before buffers are accessed from the
+ * interrupt handler.
+ *
+ * Enabling the video queue initializes parameters (such as sequence number,
+ * sync pattern, ...). If the queue is already enabled, return -EBUSY.
+ *
+ * Disabling the video queue cancels the queue and removes all buffers from
+ * the main queue.
+ *
+ * This function can't be called from interrupt context. Use
+ * uvc_queue_cancel() instead.
+ */
+int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
+{
+ unsigned int i;
+ int ret = 0;
+
+ mutex_lock(&queue->mutex);
+ if (enable) {
+ if (uvc_queue_streaming(queue)) {
+ ret = -EBUSY;
+ goto done;
+ }
+ queue->sequence = 0;
+ queue->flags |= UVC_QUEUE_STREAMING;
+ } else {
+ uvc_queue_cancel(queue, 0);
+ INIT_LIST_HEAD(&queue->mainqueue);
+
+ for (i = 0; i < queue->count; ++i)
+ queue->buffer[i].state = UVC_BUF_STATE_IDLE;
+
+ queue->flags &= ~UVC_QUEUE_STREAMING;
+ }
+
+done:
+ mutex_unlock(&queue->mutex);
+ return ret;
+}
+
+/*
+ * Cancel the video buffers queue.
+ *
+ * Cancelling the queue marks all buffers on the irq queue as erroneous,
+ * wakes them up and remove them from the queue.
+ *
+ * If the disconnect parameter is set, further calls to uvc_queue_buffer will
+ * fail with -ENODEV.
+ *
+ * This function acquires the irq spinlock and can be called from interrupt
+ * context.
+ */
+void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
+{
+ struct uvc_buffer *buf;
+ unsigned long flags;
+
+ spin_lock_irqsave(&queue->irqlock, flags);
+ while (!list_empty(&queue->irqqueue)) {
+ buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
+ queue);
+ list_del(&buf->queue);
+ buf->state = UVC_BUF_STATE_ERROR;
+ wake_up(&buf->wait);
+ }
+ /* This must be protected by the irqlock spinlock to avoid race
+ * conditions between uvc_queue_buffer and the disconnection event that
+ * could result in an interruptible wait in uvc_dequeue_buffer. Do not
+ * blindly replace this logic by checking for the UVC_DEV_DISCONNECTED
+ * state outside the queue code.
+ */
+ if (disconnect)
+ queue->flags |= UVC_QUEUE_DISCONNECTED;
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+}
+
+struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
+ struct uvc_buffer *buf)
+{
+ struct uvc_buffer *nextbuf;
+ unsigned long flags;
+
+ if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) &&
+ buf->buf.length != buf->buf.bytesused) {
+ buf->state = UVC_BUF_STATE_QUEUED;
+ buf->buf.bytesused = 0;
+ return buf;
+ }
+
+ spin_lock_irqsave(&queue->irqlock, flags);
+ list_del(&buf->queue);
+ if (!list_empty(&queue->irqqueue))
+ nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
+ queue);
+ else
+ nextbuf = NULL;
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+
+ buf->buf.sequence = queue->sequence++;
+ do_gettimeofday(&buf->buf.timestamp);
+
+ wake_up(&buf->wait);
+ return nextbuf;
+}
diff --git a/drivers/media/video/uvc/uvc_status.c b/drivers/media/video/uvc/uvc_status.c
new file mode 100644
index 000000000000..be9084e5eace
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_status.c
@@ -0,0 +1,207 @@
+/*
+ * uvc_status.c -- USB Video Class driver - Status endpoint
+ *
+ * Copyright (C) 2007-2008
+ * Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+
+#include "uvcvideo.h"
+
+/* --------------------------------------------------------------------------
+ * Input device
+ */
+static int uvc_input_init(struct uvc_device *dev)
+{
+ struct usb_device *udev = dev->udev;
+ struct input_dev *input;
+ char *phys = NULL;
+ int ret;
+
+ input = input_allocate_device();
+ if (input == NULL)
+ return -ENOMEM;
+
+ phys = kmalloc(6 + strlen(udev->bus->bus_name) + strlen(udev->devpath),
+ GFP_KERNEL);
+ if (phys == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ sprintf(phys, "usb-%s-%s", udev->bus->bus_name, udev->devpath);
+
+ input->name = dev->name;
+ input->phys = phys;
+ usb_to_input_id(udev, &input->id);
+ input->dev.parent = &dev->intf->dev;
+
+ set_bit(EV_KEY, input->evbit);
+ set_bit(BTN_0, input->keybit);
+
+ if ((ret = input_register_device(input)) < 0)
+ goto error;
+
+ dev->input = input;
+ return 0;
+
+error:
+ input_free_device(input);
+ kfree(phys);
+ return ret;
+}
+
+static void uvc_input_cleanup(struct uvc_device *dev)
+{
+ if (dev->input)
+ input_unregister_device(dev->input);
+}
+
+/* --------------------------------------------------------------------------
+ * Status interrupt endpoint
+ */
+static void uvc_event_streaming(struct uvc_device *dev, __u8 *data, int len)
+{
+ if (len < 3) {
+ uvc_trace(UVC_TRACE_STATUS, "Invalid streaming status event "
+ "received.\n");
+ return;
+ }
+
+ if (data[2] == 0) {
+ if (len < 4)
+ return;
+ uvc_trace(UVC_TRACE_STATUS, "Button (intf %u) %s len %d\n",
+ data[1], data[3] ? "pressed" : "released", len);
+ if (dev->input)
+ input_report_key(dev->input, BTN_0, data[3]);
+ } else {
+ uvc_trace(UVC_TRACE_STATUS, "Stream %u error event %02x %02x "
+ "len %d.\n", data[1], data[2], data[3], len);
+ }
+}
+
+static void uvc_event_control(struct uvc_device *dev, __u8 *data, int len)
+{
+ char *attrs[3] = { "value", "info", "failure" };
+
+ if (len < 6 || data[2] != 0 || data[4] > 2) {
+ uvc_trace(UVC_TRACE_STATUS, "Invalid control status event "
+ "received.\n");
+ return;
+ }
+
+ uvc_trace(UVC_TRACE_STATUS, "Control %u/%u %s change len %d.\n",
+ data[1], data[3], attrs[data[4]], len);
+}
+
+static void uvc_status_complete(struct urb *urb)
+{
+ struct uvc_device *dev = urb->context;
+ int len, ret;
+
+ switch (urb->status) {
+ case 0:
+ break;
+
+ case -ENOENT: /* usb_kill_urb() called. */
+ case -ECONNRESET: /* usb_unlink_urb() called. */
+ case -ESHUTDOWN: /* The endpoint is being disabled. */
+ case -EPROTO: /* Device is disconnected (reported by some
+ * host controller). */
+ return;
+
+ default:
+ uvc_printk(KERN_WARNING, "Non-zero status (%d) in status "
+ "completion handler.\n", urb->status);
+ return;
+ }
+
+ len = urb->actual_length;
+ if (len > 0) {
+ switch (dev->status[0] & 0x0f) {
+ case UVC_STATUS_TYPE_CONTROL:
+ uvc_event_control(dev, dev->status, len);
+ break;
+
+ case UVC_STATUS_TYPE_STREAMING:
+ uvc_event_streaming(dev, dev->status, len);
+ break;
+
+ default:
+ uvc_printk(KERN_INFO, "unknown event type %u.\n",
+ dev->status[0]);
+ break;
+ }
+ }
+
+ /* Resubmit the URB. */
+ urb->interval = dev->int_ep->desc.bInterval;
+ if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+ uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n",
+ ret);
+ }
+}
+
+int uvc_status_init(struct uvc_device *dev)
+{
+ struct usb_host_endpoint *ep = dev->int_ep;
+ unsigned int pipe;
+ int interval;
+
+ if (ep == NULL)
+ return 0;
+
+ uvc_input_init(dev);
+
+ dev->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (dev->int_urb == NULL)
+ return -ENOMEM;
+
+ pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
+
+ /* For high-speed interrupt endpoints, the bInterval value is used as
+ * an exponent of two. Some developers forgot about it.
+ */
+ interval = ep->desc.bInterval;
+ if (interval > 16 && dev->udev->speed == USB_SPEED_HIGH &&
+ (dev->quirks & UVC_QUIRK_STATUS_INTERVAL))
+ interval = fls(interval) - 1;
+
+ usb_fill_int_urb(dev->int_urb, dev->udev, pipe,
+ dev->status, sizeof dev->status, uvc_status_complete,
+ dev, interval);
+
+ return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+}
+
+void uvc_status_cleanup(struct uvc_device *dev)
+{
+ usb_kill_urb(dev->int_urb);
+ usb_free_urb(dev->int_urb);
+ uvc_input_cleanup(dev);
+}
+
+int uvc_status_suspend(struct uvc_device *dev)
+{
+ usb_kill_urb(dev->int_urb);
+ return 0;
+}
+
+int uvc_status_resume(struct uvc_device *dev)
+{
+ if (dev->int_urb == NULL)
+ return 0;
+
+ return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+}
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
new file mode 100644
index 000000000000..2e0a66575bb4
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -0,0 +1,1105 @@
+/*
+ * uvc_v4l2.c -- USB Video Class driver - V4L2 API
+ *
+ * Copyright (C) 2005-2008
+ * Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include <media/v4l2-common.h>
+
+#include "uvcvideo.h"
+
+/* ------------------------------------------------------------------------
+ * V4L2 interface
+ */
+
+/*
+ * Mapping V4L2 controls to UVC controls can be straighforward if done well.
+ * Most of the UVC controls exist in V4L2, and can be mapped directly. Some
+ * must be grouped (for instance the Red Balance, Blue Balance and Do White
+ * Balance V4L2 controls use the White Balance Component UVC control) or
+ * otherwise translated. The approach we take here is to use a translation
+ * table for the controls which can be mapped directly, and handle the others
+ * manually.
+ */
+static int uvc_v4l2_query_menu(struct uvc_video_device *video,
+ struct v4l2_querymenu *query_menu)
+{
+ struct uvc_menu_info *menu_info;
+ struct uvc_control_mapping *mapping;
+ struct uvc_control *ctrl;
+
+ ctrl = uvc_find_control(video, query_menu->id, &mapping);
+ if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
+ return -EINVAL;
+
+ if (query_menu->index >= mapping->menu_count)
+ return -EINVAL;
+
+ menu_info = &mapping->menu_info[query_menu->index];
+ strncpy(query_menu->name, menu_info->name, 32);
+ return 0;
+}
+
+/*
+ * Find the frame interval closest to the requested frame interval for the
+ * given frame format and size. This should be done by the device as part of
+ * the Video Probe and Commit negotiation, but some hardware don't implement
+ * that feature.
+ */
+static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval)
+{
+ unsigned int i;
+
+ if (frame->bFrameIntervalType) {
+ __u32 best = -1, dist;
+
+ for (i = 0; i < frame->bFrameIntervalType; ++i) {
+ dist = interval > frame->dwFrameInterval[i]
+ ? interval - frame->dwFrameInterval[i]
+ : frame->dwFrameInterval[i] - interval;
+
+ if (dist > best)
+ break;
+
+ best = dist;
+ }
+
+ interval = frame->dwFrameInterval[i-1];
+ } else {
+ const __u32 min = frame->dwFrameInterval[0];
+ const __u32 max = frame->dwFrameInterval[1];
+ const __u32 step = frame->dwFrameInterval[2];
+
+ interval = min + (interval - min + step/2) / step * step;
+ if (interval > max)
+ interval = max;
+ }
+
+ return interval;
+}
+
+static int uvc_v4l2_try_format(struct uvc_video_device *video,
+ struct v4l2_format *fmt, struct uvc_streaming_control *probe,
+ struct uvc_format **uvc_format, struct uvc_frame **uvc_frame)
+{
+ struct uvc_format *format = NULL;
+ struct uvc_frame *frame = NULL;
+ __u16 rw, rh;
+ unsigned int d, maxd;
+ unsigned int i;
+ __u32 interval;
+ int ret = 0;
+ __u8 *fcc;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ fcc = (__u8 *)&fmt->fmt.pix.pixelformat;
+ uvc_trace(UVC_TRACE_FORMAT, "Trying format 0x%08x (%c%c%c%c): %ux%u.\n",
+ fmt->fmt.pix.pixelformat,
+ fcc[0], fcc[1], fcc[2], fcc[3],
+ fmt->fmt.pix.width, fmt->fmt.pix.height);
+
+ /* Check if the hardware supports the requested format. */
+ for (i = 0; i < video->streaming->nformats; ++i) {
+ format = &video->streaming->format[i];
+ if (format->fcc == fmt->fmt.pix.pixelformat)
+ break;
+ }
+
+ if (format == NULL || format->fcc != fmt->fmt.pix.pixelformat) {
+ uvc_trace(UVC_TRACE_FORMAT, "Unsupported format 0x%08x.\n",
+ fmt->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ /* Find the closest image size. The distance between image sizes is
+ * the size in pixels of the non-overlapping regions between the
+ * requested size and the frame-specified size.
+ */
+ rw = fmt->fmt.pix.width;
+ rh = fmt->fmt.pix.height;
+ maxd = (unsigned int)-1;
+
+ for (i = 0; i < format->nframes; ++i) {
+ __u16 w = format->frame[i].wWidth;
+ __u16 h = format->frame[i].wHeight;
+
+ d = min(w, rw) * min(h, rh);
+ d = w*h + rw*rh - 2*d;
+ if (d < maxd) {
+ maxd = d;
+ frame = &format->frame[i];
+ }
+
+ if (maxd == 0)
+ break;
+ }
+
+ if (frame == NULL) {
+ uvc_trace(UVC_TRACE_FORMAT, "Unsupported size %ux%u.\n",
+ fmt->fmt.pix.width, fmt->fmt.pix.height);
+ return -EINVAL;
+ }
+
+ /* Use the default frame interval. */
+ interval = frame->dwDefaultFrameInterval;
+ uvc_trace(UVC_TRACE_FORMAT, "Using default frame interval %u.%u us "
+ "(%u.%u fps).\n", interval/10, interval%10, 10000000/interval,
+ (100000000/interval)%10);
+
+ /* Set the format index, frame index and frame interval. */
+ memset(probe, 0, sizeof *probe);
+ probe->bmHint = 1; /* dwFrameInterval */
+ probe->bFormatIndex = format->index;
+ probe->bFrameIndex = frame->bFrameIndex;
+ probe->dwFrameInterval = uvc_try_frame_interval(frame, interval);
+ /* Some webcams stall the probe control set request when the
+ * dwMaxVideoFrameSize field is set to zero. The UVC specification
+ * clearly states that the field is read-only from the host, so this
+ * is a webcam bug. Set dwMaxVideoFrameSize to the value reported by
+ * the webcam to work around the problem.
+ *
+ * The workaround could probably be enabled for all webcams, so the
+ * quirk can be removed if needed. It's currently useful to detect
+ * webcam bugs and fix them before they hit the market (providing
+ * developers test their webcams with the Linux driver as well as with
+ * the Windows driver).
+ */
+ if (video->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
+ probe->dwMaxVideoFrameSize =
+ video->streaming->ctrl.dwMaxVideoFrameSize;
+
+ /* Probe the device */
+ if ((ret = uvc_probe_video(video, probe)) < 0)
+ goto done;
+
+ fmt->fmt.pix.width = frame->wWidth;
+ fmt->fmt.pix.height = frame->wHeight;
+ fmt->fmt.pix.field = V4L2_FIELD_NONE;
+ fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8;
+ fmt->fmt.pix.sizeimage = probe->dwMaxVideoFrameSize;
+ fmt->fmt.pix.colorspace = format->colorspace;
+ fmt->fmt.pix.priv = 0;
+
+ if (uvc_format != NULL)
+ *uvc_format = format;
+ if (uvc_frame != NULL)
+ *uvc_frame = frame;
+
+done:
+ return ret;
+}
+
+static int uvc_v4l2_get_format(struct uvc_video_device *video,
+ struct v4l2_format *fmt)
+{
+ struct uvc_format *format = video->streaming->cur_format;
+ struct uvc_frame *frame = video->streaming->cur_frame;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (format == NULL || frame == NULL)
+ return -EINVAL;
+
+ fmt->fmt.pix.pixelformat = format->fcc;
+ fmt->fmt.pix.width = frame->wWidth;
+ fmt->fmt.pix.height = frame->wHeight;
+ fmt->fmt.pix.field = V4L2_FIELD_NONE;
+ fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8;
+ fmt->fmt.pix.sizeimage = video->streaming->ctrl.dwMaxVideoFrameSize;
+ fmt->fmt.pix.colorspace = format->colorspace;
+ fmt->fmt.pix.priv = 0;
+
+ return 0;
+}
+
+static int uvc_v4l2_set_format(struct uvc_video_device *video,
+ struct v4l2_format *fmt)
+{
+ struct uvc_streaming_control probe;
+ struct uvc_format *format;
+ struct uvc_frame *frame;
+ int ret;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (uvc_queue_streaming(&video->queue))
+ return -EBUSY;
+
+ ret = uvc_v4l2_try_format(video, fmt, &probe, &format, &frame);
+ if (ret < 0)
+ return ret;
+
+ if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0)
+ return ret;
+
+ memcpy(&video->streaming->ctrl, &probe, sizeof probe);
+ video->streaming->cur_format = format;
+ video->streaming->cur_frame = frame;
+
+ return 0;
+}
+
+static int uvc_v4l2_get_streamparm(struct uvc_video_device *video,
+ struct v4l2_streamparm *parm)
+{
+ uint32_t numerator, denominator;
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ numerator = video->streaming->ctrl.dwFrameInterval;
+ denominator = 10000000;
+ uvc_simplify_fraction(&numerator, &denominator, 8, 333);
+
+ memset(parm, 0, sizeof *parm);
+ parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+ parm->parm.capture.capturemode = 0;
+ parm->parm.capture.timeperframe.numerator = numerator;
+ parm->parm.capture.timeperframe.denominator = denominator;
+ parm->parm.capture.extendedmode = 0;
+ parm->parm.capture.readbuffers = 0;
+
+ return 0;
+}
+
+static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
+ struct v4l2_streamparm *parm)
+{
+ struct uvc_frame *frame = video->streaming->cur_frame;
+ struct uvc_streaming_control probe;
+ uint32_t interval;
+ int ret;
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (uvc_queue_streaming(&video->queue))
+ return -EBUSY;
+
+ memcpy(&probe, &video->streaming->ctrl, sizeof probe);
+ interval = uvc_fraction_to_interval(
+ parm->parm.capture.timeperframe.numerator,
+ parm->parm.capture.timeperframe.denominator);
+
+ uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n",
+ parm->parm.capture.timeperframe.numerator,
+ parm->parm.capture.timeperframe.denominator,
+ interval);
+ probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
+
+ /* Probe the device with the new settings. */
+ if ((ret = uvc_probe_video(video, &probe)) < 0)
+ return ret;
+
+ /* Commit the new settings. */
+ if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0)
+ return ret;
+
+ memcpy(&video->streaming->ctrl, &probe, sizeof probe);
+
+ /* Return the actual frame period. */
+ parm->parm.capture.timeperframe.numerator = probe.dwFrameInterval;
+ parm->parm.capture.timeperframe.denominator = 10000000;
+ uvc_simplify_fraction(&parm->parm.capture.timeperframe.numerator,
+ &parm->parm.capture.timeperframe.denominator,
+ 8, 333);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * Privilege management
+ */
+
+/*
+ * Privilege management is the multiple-open implementation basis. The current
+ * implementation is completely transparent for the end-user and doesn't
+ * require explicit use of the VIDIOC_G_PRIORITY and VIDIOC_S_PRIORITY ioctls.
+ * Those ioctls enable finer control on the device (by making possible for a
+ * user to request exclusive access to a device), but are not mature yet.
+ * Switching to the V4L2 priority mechanism might be considered in the future
+ * if this situation changes.
+ *
+ * Each open instance of a UVC device can either be in a privileged or
+ * unprivileged state. Only a single instance can be in a privileged state at
+ * a given time. Trying to perform an operation which requires privileges will
+ * automatically acquire the required privileges if possible, or return -EBUSY
+ * otherwise. Privileges are dismissed when closing the instance.
+ *
+ * Operations which require privileges are:
+ *
+ * - VIDIOC_S_INPUT
+ * - VIDIOC_S_PARM
+ * - VIDIOC_S_FMT
+ * - VIDIOC_TRY_FMT
+ * - VIDIOC_REQBUFS
+ */
+static int uvc_acquire_privileges(struct uvc_fh *handle)
+{
+ int ret = 0;
+
+ /* Always succeed if the handle is already privileged. */
+ if (handle->state == UVC_HANDLE_ACTIVE)
+ return 0;
+
+ /* Check if the device already has a privileged handle. */
+ mutex_lock(&uvc_driver.open_mutex);
+ if (atomic_inc_return(&handle->device->active) != 1) {
+ atomic_dec(&handle->device->active);
+ ret = -EBUSY;
+ goto done;
+ }
+
+ handle->state = UVC_HANDLE_ACTIVE;
+
+done:
+ mutex_unlock(&uvc_driver.open_mutex);
+ return ret;
+}
+
+static void uvc_dismiss_privileges(struct uvc_fh *handle)
+{
+ if (handle->state == UVC_HANDLE_ACTIVE)
+ atomic_dec(&handle->device->active);
+
+ handle->state = UVC_HANDLE_PASSIVE;
+}
+
+static int uvc_has_privileges(struct uvc_fh *handle)
+{
+ return handle->state == UVC_HANDLE_ACTIVE;
+}
+
+/* ------------------------------------------------------------------------
+ * V4L2 file operations
+ */
+
+static int uvc_v4l2_open(struct inode *inode, struct file *file)
+{
+ struct video_device *vdev;
+ struct uvc_video_device *video;
+ struct uvc_fh *handle;
+ int ret = 0;
+
+ uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");
+ mutex_lock(&uvc_driver.open_mutex);
+ vdev = video_devdata(file);
+ video = video_get_drvdata(vdev);
+
+ if (video->dev->state & UVC_DEV_DISCONNECTED) {
+ ret = -ENODEV;
+ goto done;
+ }
+
+ ret = usb_autopm_get_interface(video->dev->intf);
+ if (ret < 0)
+ goto done;
+
+ /* Create the device handle. */
+ handle = kzalloc(sizeof *handle, GFP_KERNEL);
+ if (handle == NULL) {
+ usb_autopm_put_interface(video->dev->intf);
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ handle->device = video;
+ handle->state = UVC_HANDLE_PASSIVE;
+ file->private_data = handle;
+
+ kref_get(&video->dev->kref);
+
+done:
+ mutex_unlock(&uvc_driver.open_mutex);
+ return ret;
+}
+
+static int uvc_v4l2_release(struct inode *inode, struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct uvc_video_device *video = video_get_drvdata(vdev);
+ struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+
+ uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n");
+
+ /* Only free resources if this is a privileged handle. */
+ if (uvc_has_privileges(handle)) {
+ uvc_video_enable(video, 0);
+
+ mutex_lock(&video->queue.mutex);
+ if (uvc_free_buffers(&video->queue) < 0)
+ uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to "
+ "free buffers.\n");
+ mutex_unlock(&video->queue.mutex);
+ }
+
+ /* Release the file handle. */
+ uvc_dismiss_privileges(handle);
+ kfree(handle);
+ file->private_data = NULL;
+
+ usb_autopm_put_interface(video->dev->intf);
+ kref_put(&video->dev->kref, uvc_delete);
+ return 0;
+}
+
+static int uvc_v4l2_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct uvc_video_device *video = video_get_drvdata(vdev);
+ struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+ int ret = 0;
+
+ if (uvc_trace_param & UVC_TRACE_IOCTL)
+ v4l_printk_ioctl(cmd);
+
+ switch (cmd) {
+ /* Query capabilities */
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap = arg;
+
+ memset(cap, 0, sizeof *cap);
+ strncpy(cap->driver, "uvcvideo", sizeof cap->driver);
+ strncpy(cap->card, vdev->name, 32);
+ strncpy(cap->bus_info, video->dev->udev->bus->bus_name,
+ sizeof cap->bus_info);
+ cap->version = DRIVER_VERSION_NUMBER;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_STREAMING;
+ break;
+ }
+
+ /* Get, Set & Query control */
+ case VIDIOC_QUERYCTRL:
+ return uvc_query_v4l2_ctrl(video, arg);
+
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+ struct v4l2_ext_control xctrl;
+
+ memset(&xctrl, 0, sizeof xctrl);
+ xctrl.id = ctrl->id;
+
+ uvc_ctrl_begin(video);
+ ret = uvc_ctrl_get(video, &xctrl);
+ uvc_ctrl_rollback(video);
+ if (ret >= 0)
+ ctrl->value = xctrl.value;
+ break;
+ }
+
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+ struct v4l2_ext_control xctrl;
+
+ memset(&xctrl, 0, sizeof xctrl);
+ xctrl.id = ctrl->id;
+ xctrl.value = ctrl->value;
+
+ uvc_ctrl_begin(video);
+ ret = uvc_ctrl_set(video, &xctrl);
+ if (ret < 0) {
+ uvc_ctrl_rollback(video);
+ return ret;
+ }
+ ret = uvc_ctrl_commit(video);
+ break;
+ }
+
+ case VIDIOC_QUERYMENU:
+ return uvc_v4l2_query_menu(video, arg);
+
+ case VIDIOC_G_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *ctrls = arg;
+ struct v4l2_ext_control *ctrl = ctrls->controls;
+ unsigned int i;
+
+ uvc_ctrl_begin(video);
+ for (i = 0; i < ctrls->count; ++ctrl, ++i) {
+ ret = uvc_ctrl_get(video, ctrl);
+ if (ret < 0) {
+ uvc_ctrl_rollback(video);
+ ctrls->error_idx = i;
+ return ret;
+ }
+ }
+ ctrls->error_idx = 0;
+ ret = uvc_ctrl_rollback(video);
+ break;
+ }
+
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *ctrls = arg;
+ struct v4l2_ext_control *ctrl = ctrls->controls;
+ unsigned int i;
+
+ ret = uvc_ctrl_begin(video);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ctrls->count; ++ctrl, ++i) {
+ ret = uvc_ctrl_set(video, ctrl);
+ if (ret < 0) {
+ uvc_ctrl_rollback(video);
+ ctrls->error_idx = i;
+ return ret;
+ }
+ }
+
+ ctrls->error_idx = 0;
+
+ if (cmd == VIDIOC_S_EXT_CTRLS)
+ ret = uvc_ctrl_commit(video);
+ else
+ ret = uvc_ctrl_rollback(video);
+ break;
+ }
+
+ /* Get, Set & Enum input */
+ case VIDIOC_ENUMINPUT:
+ {
+ const struct uvc_entity *selector = video->selector;
+ struct v4l2_input *input = arg;
+ struct uvc_entity *iterm = NULL;
+ u32 index = input->index;
+ int pin = 0;
+
+ if (selector == NULL ||
+ (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+ if (index != 0)
+ return -EINVAL;
+ iterm = list_first_entry(&video->iterms,
+ struct uvc_entity, chain);
+ pin = iterm->id;
+ } else if (pin < selector->selector.bNrInPins) {
+ pin = selector->selector.baSourceID[index];
+ list_for_each_entry(iterm, video->iterms.next, chain) {
+ if (iterm->id == pin)
+ break;
+ }
+ }
+
+ if (iterm == NULL || iterm->id != pin)
+ return -EINVAL;
+
+ memset(input, 0, sizeof *input);
+ input->index = index;
+ strncpy(input->name, iterm->name, sizeof input->name);
+ if (UVC_ENTITY_TYPE(iterm) == ITT_CAMERA)
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+ break;
+ }
+
+ case VIDIOC_G_INPUT:
+ {
+ u8 input;
+
+ if (video->selector == NULL ||
+ (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+ *(int *)arg = 0;
+ break;
+ }
+
+ ret = uvc_query_ctrl(video->dev, GET_CUR, video->selector->id,
+ video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
+ &input, 1);
+ if (ret < 0)
+ return ret;
+
+ *(int *)arg = input - 1;
+ break;
+ }
+
+ case VIDIOC_S_INPUT:
+ {
+ u8 input = *(u32 *)arg + 1;
+
+ if ((ret = uvc_acquire_privileges(handle)) < 0)
+ return ret;
+
+ if (video->selector == NULL ||
+ (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+ if (input != 1)
+ return -EINVAL;
+ break;
+ }
+
+ if (input > video->selector->selector.bNrInPins)
+ return -EINVAL;
+
+ return uvc_query_ctrl(video->dev, SET_CUR, video->selector->id,
+ video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
+ &input, 1);
+ }
+
+ /* Try, Get, Set & Enum format */
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *fmt = arg;
+ struct uvc_format *format;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ fmt->index >= video->streaming->nformats)
+ return -EINVAL;
+
+ format = &video->streaming->format[fmt->index];
+ fmt->flags = 0;
+ if (format->flags & UVC_FMT_FLAG_COMPRESSED)
+ fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
+ strncpy(fmt->description, format->name,
+ sizeof fmt->description);
+ fmt->description[sizeof fmt->description - 1] = 0;
+ fmt->pixelformat = format->fcc;
+ break;
+ }
+
+ case VIDIOC_TRY_FMT:
+ {
+ struct uvc_streaming_control probe;
+
+ if ((ret = uvc_acquire_privileges(handle)) < 0)
+ return ret;
+
+ return uvc_v4l2_try_format(video, arg, &probe, NULL, NULL);
+ }
+
+ case VIDIOC_S_FMT:
+ if ((ret = uvc_acquire_privileges(handle)) < 0)
+ return ret;
+
+ return uvc_v4l2_set_format(video, arg);
+
+ case VIDIOC_G_FMT:
+ return uvc_v4l2_get_format(video, arg);
+
+ /* Frame size enumeration */
+ case VIDIOC_ENUM_FRAMESIZES:
+ {
+ struct v4l2_frmsizeenum *fsize = arg;
+ struct uvc_format *format = NULL;
+ struct uvc_frame *frame;
+ int i;
+
+ /* Look for the given pixel format */
+ for (i = 0; i < video->streaming->nformats; i++) {
+ if (video->streaming->format[i].fcc ==
+ fsize->pixel_format) {
+ format = &video->streaming->format[i];
+ break;
+ }
+ }
+ if (format == NULL)
+ return -EINVAL;
+
+ if (fsize->index >= format->nframes)
+ return -EINVAL;
+
+ frame = &format->frame[fsize->index];
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = frame->wWidth;
+ fsize->discrete.height = frame->wHeight;
+ break;
+ }
+
+ /* Frame interval enumeration */
+ case VIDIOC_ENUM_FRAMEINTERVALS:
+ {
+ struct v4l2_frmivalenum *fival = arg;
+ struct uvc_format *format = NULL;
+ struct uvc_frame *frame = NULL;
+ int i;
+
+ /* Look for the given pixel format and frame size */
+ for (i = 0; i < video->streaming->nformats; i++) {
+ if (video->streaming->format[i].fcc ==
+ fival->pixel_format) {
+ format = &video->streaming->format[i];
+ break;
+ }
+ }
+ if (format == NULL)
+ return -EINVAL;
+
+ for (i = 0; i < format->nframes; i++) {
+ if (format->frame[i].wWidth == fival->width &&
+ format->frame[i].wHeight == fival->height) {
+ frame = &format->frame[i];
+ break;
+ }
+ }
+ if (frame == NULL)
+ return -EINVAL;
+
+ if (frame->bFrameIntervalType) {
+ if (fival->index >= frame->bFrameIntervalType)
+ return -EINVAL;
+
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fival->discrete.numerator =
+ frame->dwFrameInterval[fival->index];
+ fival->discrete.denominator = 10000000;
+ uvc_simplify_fraction(&fival->discrete.numerator,
+ &fival->discrete.denominator, 8, 333);
+ } else {
+ fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
+ fival->stepwise.min.numerator =
+ frame->dwFrameInterval[0];
+ fival->stepwise.min.denominator = 10000000;
+ fival->stepwise.max.numerator =
+ frame->dwFrameInterval[1];
+ fival->stepwise.max.denominator = 10000000;
+ fival->stepwise.step.numerator =
+ frame->dwFrameInterval[2];
+ fival->stepwise.step.denominator = 10000000;
+ uvc_simplify_fraction(&fival->stepwise.min.numerator,
+ &fival->stepwise.min.denominator, 8, 333);
+ uvc_simplify_fraction(&fival->stepwise.max.numerator,
+ &fival->stepwise.max.denominator, 8, 333);
+ uvc_simplify_fraction(&fival->stepwise.step.numerator,
+ &fival->stepwise.step.denominator, 8, 333);
+ }
+ break;
+ }
+
+ /* Get & Set streaming parameters */
+ case VIDIOC_G_PARM:
+ return uvc_v4l2_get_streamparm(video, arg);
+
+ case VIDIOC_S_PARM:
+ if ((ret = uvc_acquire_privileges(handle)) < 0)
+ return ret;
+
+ return uvc_v4l2_set_streamparm(video, arg);
+
+ /* Cropping and scaling */
+ case VIDIOC_CROPCAP:
+ {
+ struct v4l2_cropcap *ccap = arg;
+ struct uvc_frame *frame = video->streaming->cur_frame;
+
+ if (ccap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ ccap->bounds.left = 0;
+ ccap->bounds.top = 0;
+ ccap->bounds.width = frame->wWidth;
+ ccap->bounds.height = frame->wHeight;
+
+ ccap->defrect = ccap->bounds;
+
+ ccap->pixelaspect.numerator = 1;
+ ccap->pixelaspect.denominator = 1;
+ break;
+ }
+
+ case VIDIOC_G_CROP:
+ case VIDIOC_S_CROP:
+ return -EINVAL;
+
+ /* Buffers & streaming */
+ case VIDIOC_REQBUFS:
+ {
+ struct v4l2_requestbuffers *rb = arg;
+ unsigned int bufsize =
+ video->streaming->ctrl.dwMaxVideoFrameSize;
+
+ if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ rb->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ if ((ret = uvc_acquire_privileges(handle)) < 0)
+ return ret;
+
+ ret = uvc_alloc_buffers(&video->queue, rb->count, bufsize);
+ if (ret < 0)
+ return ret;
+
+ if (!(video->streaming->cur_format->flags &
+ UVC_FMT_FLAG_COMPRESSED))
+ video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
+
+ rb->count = ret;
+ ret = 0;
+ break;
+ }
+
+ case VIDIOC_QUERYBUF:
+ {
+ struct v4l2_buffer *buf = arg;
+
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (!uvc_has_privileges(handle))
+ return -EBUSY;
+
+ return uvc_query_buffer(&video->queue, buf);
+ }
+
+ case VIDIOC_QBUF:
+ if (!uvc_has_privileges(handle))
+ return -EBUSY;
+
+ return uvc_queue_buffer(&video->queue, arg);
+
+ case VIDIOC_DQBUF:
+ if (!uvc_has_privileges(handle))
+ return -EBUSY;
+
+ return uvc_dequeue_buffer(&video->queue, arg,
+ file->f_flags & O_NONBLOCK);
+
+ case VIDIOC_STREAMON:
+ {
+ int *type = arg;
+
+ if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (!uvc_has_privileges(handle))
+ return -EBUSY;
+
+ if ((ret = uvc_video_enable(video, 1)) < 0)
+ return ret;
+ break;
+ }
+
+ case VIDIOC_STREAMOFF:
+ {
+ int *type = arg;
+
+ if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (!uvc_has_privileges(handle))
+ return -EBUSY;
+
+ return uvc_video_enable(video, 0);
+ }
+
+ /* Analog video standards make no sense for digital cameras. */
+ case VIDIOC_ENUMSTD:
+ case VIDIOC_QUERYSTD:
+ case VIDIOC_G_STD:
+ case VIDIOC_S_STD:
+
+ case VIDIOC_OVERLAY:
+
+ case VIDIOC_ENUMAUDIO:
+ case VIDIOC_ENUMAUDOUT:
+
+ case VIDIOC_ENUMOUTPUT:
+ uvc_trace(UVC_TRACE_IOCTL, "Unsupported ioctl 0x%08x\n", cmd);
+ return -EINVAL;
+
+ /* Dynamic controls. */
+ case UVCIOC_CTRL_ADD:
+ {
+ struct uvc_xu_control_info *xinfo = arg;
+ struct uvc_control_info *info;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ info = kmalloc(sizeof *info, GFP_KERNEL);
+ if (info == NULL)
+ return -ENOMEM;
+
+ memcpy(info->entity, xinfo->entity, sizeof info->entity);
+ info->index = xinfo->index;
+ info->selector = xinfo->selector;
+ info->size = xinfo->size;
+ info->flags = xinfo->flags;
+
+ info->flags |= UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
+ UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF;
+
+ ret = uvc_ctrl_add_info(info);
+ if (ret < 0)
+ kfree(info);
+ break;
+ }
+
+ case UVCIOC_CTRL_MAP:
+ {
+ struct uvc_xu_control_mapping *xmap = arg;
+ struct uvc_control_mapping *map;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ map = kmalloc(sizeof *map, GFP_KERNEL);
+ if (map == NULL)
+ return -ENOMEM;
+
+ map->id = xmap->id;
+ memcpy(map->name, xmap->name, sizeof map->name);
+ memcpy(map->entity, xmap->entity, sizeof map->entity);
+ map->selector = xmap->selector;
+ map->size = xmap->size;
+ map->offset = xmap->offset;
+ map->v4l2_type = xmap->v4l2_type;
+ map->data_type = xmap->data_type;
+
+ ret = uvc_ctrl_add_mapping(map);
+ if (ret < 0)
+ kfree(map);
+ break;
+ }
+
+ case UVCIOC_CTRL_GET:
+ return uvc_xu_ctrl_query(video, arg, 0);
+
+ case UVCIOC_CTRL_SET:
+ return uvc_xu_ctrl_query(video, arg, 1);
+
+ default:
+ if ((ret = v4l_compat_translate_ioctl(inode, file, cmd, arg,
+ uvc_v4l2_do_ioctl)) == -ENOIOCTLCMD)
+ uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n",
+ cmd);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int uvc_v4l2_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_ioctl\n");
+ return video_usercopy(inode, file, cmd, arg, uvc_v4l2_do_ioctl);
+}
+
+static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
+ size_t count, loff_t *ppos)
+{
+ uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_read: not implemented.\n");
+ return -ENODEV;
+}
+
+/*
+ * VMA operations.
+ */
+static void uvc_vm_open(struct vm_area_struct *vma)
+{
+ struct uvc_buffer *buffer = vma->vm_private_data;
+ buffer->vma_use_count++;
+}
+
+static void uvc_vm_close(struct vm_area_struct *vma)
+{
+ struct uvc_buffer *buffer = vma->vm_private_data;
+ buffer->vma_use_count--;
+}
+
+static struct vm_operations_struct uvc_vm_ops = {
+ .open = uvc_vm_open,
+ .close = uvc_vm_close,
+};
+
+static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct uvc_video_device *video = video_get_drvdata(vdev);
+ struct uvc_buffer *buffer;
+ struct page *page;
+ unsigned long addr, start, size;
+ unsigned int i;
+ int ret = 0;
+
+ uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_mmap\n");
+
+ start = vma->vm_start;
+ size = vma->vm_end - vma->vm_start;
+
+ mutex_lock(&video->queue.mutex);
+
+ for (i = 0; i < video->queue.count; ++i) {
+ buffer = &video->queue.buffer[i];
+ if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
+ break;
+ }
+
+ if (i == video->queue.count || size != video->queue.buf_size) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /*
+ * VM_IO marks the area as being an mmaped region for I/O to a
+ * device. It also prevents the region from being core dumped.
+ */
+ vma->vm_flags |= VM_IO;
+
+ addr = (unsigned long)video->queue.mem + buffer->buf.m.offset;
+ while (size > 0) {
+ page = vmalloc_to_page((void *)addr);
+ if ((ret = vm_insert_page(vma, start, page)) < 0)
+ goto done;
+
+ start += PAGE_SIZE;
+ addr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ vma->vm_ops = &uvc_vm_ops;
+ vma->vm_private_data = buffer;
+ uvc_vm_open(vma);
+
+done:
+ mutex_unlock(&video->queue.mutex);
+ return ret;
+}
+
+static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct uvc_video_device *video = video_get_drvdata(vdev);
+
+ uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n");
+
+ return uvc_queue_poll(&video->queue, file, wait);
+}
+
+struct file_operations uvc_fops = {
+ .owner = THIS_MODULE,
+ .open = uvc_v4l2_open,
+ .release = uvc_v4l2_release,
+ .ioctl = uvc_v4l2_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
+ .llseek = no_llseek,
+ .read = uvc_v4l2_read,
+ .mmap = uvc_v4l2_mmap,
+ .poll = uvc_v4l2_poll,
+};
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
new file mode 100644
index 000000000000..6faf1fb21614
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -0,0 +1,934 @@
+/*
+ * uvc_video.c -- USB Video Class driver - Video handling
+ *
+ * Copyright (C) 2005-2008
+ * Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+#include <asm/unaligned.h>
+
+#include <media/v4l2-common.h>
+
+#include "uvcvideo.h"
+
+/* ------------------------------------------------------------------------
+ * UVC Controls
+ */
+
+static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+ __u8 intfnum, __u8 cs, void *data, __u16 size,
+ int timeout)
+{
+ __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ unsigned int pipe;
+ int ret;
+
+ pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0)
+ : usb_sndctrlpipe(dev->udev, 0);
+ type |= (query & 0x80) ? USB_DIR_IN : USB_DIR_OUT;
+
+ ret = usb_control_msg(dev->udev, pipe, query, type, cs << 8,
+ unit << 8 | intfnum, data, size, timeout);
+
+ if (ret != size) {
+ uvc_printk(KERN_ERR, "Failed to query (%u) UVC control %u "
+ "(unit %u) : %d (exp. %u).\n", query, cs, unit, ret,
+ size);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+ __u8 intfnum, __u8 cs, void *data, __u16 size)
+{
+ return __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
+ UVC_CTRL_CONTROL_TIMEOUT);
+}
+
+static void uvc_fixup_buffer_size(struct uvc_video_device *video,
+ struct uvc_streaming_control *ctrl)
+{
+ struct uvc_format *format;
+ struct uvc_frame *frame;
+
+ if (ctrl->bFormatIndex <= 0 ||
+ ctrl->bFormatIndex > video->streaming->nformats)
+ return;
+
+ format = &video->streaming->format[ctrl->bFormatIndex - 1];
+
+ if (ctrl->bFrameIndex <= 0 ||
+ ctrl->bFrameIndex > format->nframes)
+ return;
+
+ frame = &format->frame[ctrl->bFrameIndex - 1];
+
+ if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) ||
+ (ctrl->dwMaxVideoFrameSize == 0 &&
+ video->dev->uvc_version < 0x0110))
+ ctrl->dwMaxVideoFrameSize =
+ frame->dwMaxVideoFrameBufferSize;
+}
+
+static int uvc_get_video_ctrl(struct uvc_video_device *video,
+ struct uvc_streaming_control *ctrl, int probe, __u8 query)
+{
+ __u8 data[34];
+ __u8 size;
+ int ret;
+
+ size = video->dev->uvc_version >= 0x0110 ? 34 : 26;
+ ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum,
+ probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, &data, size,
+ UVC_CTRL_STREAMING_TIMEOUT);
+
+ if (ret < 0)
+ return ret;
+
+ ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]);
+ ctrl->bFormatIndex = data[2];
+ ctrl->bFrameIndex = data[3];
+ ctrl->dwFrameInterval = le32_to_cpup((__le32 *)&data[4]);
+ ctrl->wKeyFrameRate = le16_to_cpup((__le16 *)&data[8]);
+ ctrl->wPFrameRate = le16_to_cpup((__le16 *)&data[10]);
+ ctrl->wCompQuality = le16_to_cpup((__le16 *)&data[12]);
+ ctrl->wCompWindowSize = le16_to_cpup((__le16 *)&data[14]);
+ ctrl->wDelay = le16_to_cpup((__le16 *)&data[16]);
+ ctrl->dwMaxVideoFrameSize =
+ le32_to_cpu(get_unaligned((__le32 *)&data[18]));
+ ctrl->dwMaxPayloadTransferSize =
+ le32_to_cpu(get_unaligned((__le32 *)&data[22]));
+
+ if (size == 34) {
+ ctrl->dwClockFrequency =
+ le32_to_cpu(get_unaligned((__le32 *)&data[26]));
+ ctrl->bmFramingInfo = data[30];
+ ctrl->bPreferedVersion = data[31];
+ ctrl->bMinVersion = data[32];
+ ctrl->bMaxVersion = data[33];
+ } else {
+ ctrl->dwClockFrequency = video->dev->clock_frequency;
+ ctrl->bmFramingInfo = 0;
+ ctrl->bPreferedVersion = 0;
+ ctrl->bMinVersion = 0;
+ ctrl->bMaxVersion = 0;
+ }
+
+ /* Some broken devices return a null or wrong dwMaxVideoFrameSize.
+ * Try to get the value from the format and frame descriptor.
+ */
+ uvc_fixup_buffer_size(video, ctrl);
+
+ return 0;
+}
+
+int uvc_set_video_ctrl(struct uvc_video_device *video,
+ struct uvc_streaming_control *ctrl, int probe)
+{
+ __u8 data[34];
+ __u8 size;
+
+ size = video->dev->uvc_version >= 0x0110 ? 34 : 26;
+ memset(data, 0, sizeof data);
+
+ *(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint);
+ data[2] = ctrl->bFormatIndex;
+ data[3] = ctrl->bFrameIndex;
+ *(__le32 *)&data[4] = cpu_to_le32(ctrl->dwFrameInterval);
+ *(__le16 *)&data[8] = cpu_to_le16(ctrl->wKeyFrameRate);
+ *(__le16 *)&data[10] = cpu_to_le16(ctrl->wPFrameRate);
+ *(__le16 *)&data[12] = cpu_to_le16(ctrl->wCompQuality);
+ *(__le16 *)&data[14] = cpu_to_le16(ctrl->wCompWindowSize);
+ *(__le16 *)&data[16] = cpu_to_le16(ctrl->wDelay);
+ /* Note: Some of the fields below are not required for IN devices (see
+ * UVC spec, 4.3.1.1), but we still copy them in case support for OUT
+ * devices is added in the future. */
+ put_unaligned(cpu_to_le32(ctrl->dwMaxVideoFrameSize),
+ (__le32 *)&data[18]);
+ put_unaligned(cpu_to_le32(ctrl->dwMaxPayloadTransferSize),
+ (__le32 *)&data[22]);
+
+ if (size == 34) {
+ put_unaligned(cpu_to_le32(ctrl->dwClockFrequency),
+ (__le32 *)&data[26]);
+ data[30] = ctrl->bmFramingInfo;
+ data[31] = ctrl->bPreferedVersion;
+ data[32] = ctrl->bMinVersion;
+ data[33] = ctrl->bMaxVersion;
+ }
+
+ return __uvc_query_ctrl(video->dev, SET_CUR, 0,
+ video->streaming->intfnum,
+ probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, &data, size,
+ UVC_CTRL_STREAMING_TIMEOUT);
+}
+
+int uvc_probe_video(struct uvc_video_device *video,
+ struct uvc_streaming_control *probe)
+{
+ struct uvc_streaming_control probe_min, probe_max;
+ __u16 bandwidth;
+ unsigned int i;
+ int ret;
+
+ mutex_lock(&video->streaming->mutex);
+
+ /* Perform probing. The device should adjust the requested values
+ * according to its capabilities. However, some devices, namely the
+ * first generation UVC Logitech webcams, don't implement the Video
+ * Probe control properly, and just return the needed bandwidth. For
+ * that reason, if the needed bandwidth exceeds the maximum available
+ * bandwidth, try to lower the quality.
+ */
+ if ((ret = uvc_set_video_ctrl(video, probe, 1)) < 0)
+ goto done;
+
+ /* Get the minimum and maximum values for compression settings. */
+ if (!(video->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) {
+ ret = uvc_get_video_ctrl(video, &probe_min, 1, GET_MIN);
+ if (ret < 0)
+ goto done;
+ ret = uvc_get_video_ctrl(video, &probe_max, 1, GET_MAX);
+ if (ret < 0)
+ goto done;
+
+ probe->wCompQuality = probe_max.wCompQuality;
+ }
+
+ for (i = 0; i < 2; ++i) {
+ if ((ret = uvc_set_video_ctrl(video, probe, 1)) < 0 ||
+ (ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+ goto done;
+
+ if (video->streaming->intf->num_altsetting == 1)
+ break;
+
+ bandwidth = probe->dwMaxPayloadTransferSize;
+ if (bandwidth <= video->streaming->maxpsize)
+ break;
+
+ if (video->dev->quirks & UVC_QUIRK_PROBE_MINMAX) {
+ ret = -ENOSPC;
+ goto done;
+ }
+
+ /* TODO: negotiate compression parameters */
+ probe->wKeyFrameRate = probe_min.wKeyFrameRate;
+ probe->wPFrameRate = probe_min.wPFrameRate;
+ probe->wCompQuality = probe_max.wCompQuality;
+ probe->wCompWindowSize = probe_min.wCompWindowSize;
+ }
+
+done:
+ mutex_unlock(&video->streaming->mutex);
+ return ret;
+}
+
+/* ------------------------------------------------------------------------
+ * Video codecs
+ */
+
+/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
+#define UVC_STREAM_EOH (1 << 7)
+#define UVC_STREAM_ERR (1 << 6)
+#define UVC_STREAM_STI (1 << 5)
+#define UVC_STREAM_RES (1 << 4)
+#define UVC_STREAM_SCR (1 << 3)
+#define UVC_STREAM_PTS (1 << 2)
+#define UVC_STREAM_EOF (1 << 1)
+#define UVC_STREAM_FID (1 << 0)
+
+/* Video payload decoding is handled by uvc_video_decode_start(),
+ * uvc_video_decode_data() and uvc_video_decode_end().
+ *
+ * uvc_video_decode_start is called with URB data at the start of a bulk or
+ * isochronous payload. It processes header data and returns the header size
+ * in bytes if successful. If an error occurs, it returns a negative error
+ * code. The following error codes have special meanings.
+ *
+ * - EAGAIN informs the caller that the current video buffer should be marked
+ * as done, and that the function should be called again with the same data
+ * and a new video buffer. This is used when end of frame conditions can be
+ * reliably detected at the beginning of the next frame only.
+ *
+ * If an error other than -EAGAIN is returned, the caller will drop the current
+ * payload. No call to uvc_video_decode_data and uvc_video_decode_end will be
+ * made until the next payload. -ENODATA can be used to drop the current
+ * payload if no other error code is appropriate.
+ *
+ * uvc_video_decode_data is called for every URB with URB data. It copies the
+ * data to the video buffer.
+ *
+ * uvc_video_decode_end is called with header data at the end of a bulk or
+ * isochronous payload. It performs any additional header data processing and
+ * returns 0 or a negative error code if an error occured. As header data have
+ * already been processed by uvc_video_decode_start, this functions isn't
+ * required to perform sanity checks a second time.
+ *
+ * For isochronous transfers where a payload is always transfered in a single
+ * URB, the three functions will be called in a row.
+ *
+ * To let the decoder process header data and update its internal state even
+ * when no video buffer is available, uvc_video_decode_start must be prepared
+ * to be called with a NULL buf parameter. uvc_video_decode_data and
+ * uvc_video_decode_end will never be called with a NULL buffer.
+ */
+static int uvc_video_decode_start(struct uvc_video_device *video,
+ struct uvc_buffer *buf, const __u8 *data, int len)
+{
+ __u8 fid;
+
+ /* Sanity checks:
+ * - packet must be at least 2 bytes long
+ * - bHeaderLength value must be at least 2 bytes (see above)
+ * - bHeaderLength value can't be larger than the packet size.
+ */
+ if (len < 2 || data[0] < 2 || data[0] > len)
+ return -EINVAL;
+
+ /* Skip payloads marked with the error bit ("error frames"). */
+ if (data[1] & UVC_STREAM_ERR) {
+ uvc_trace(UVC_TRACE_FRAME, "Dropping payload (error bit "
+ "set).\n");
+ return -ENODATA;
+ }
+
+ fid = data[1] & UVC_STREAM_FID;
+
+ /* Store the payload FID bit and return immediately when the buffer is
+ * NULL.
+ */
+ if (buf == NULL) {
+ video->last_fid = fid;
+ return -ENODATA;
+ }
+
+ /* Synchronize to the input stream by waiting for the FID bit to be
+ * toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE.
+ * queue->last_fid is initialized to -1, so the first isochronous
+ * frame will always be in sync.
+ *
+ * If the device doesn't toggle the FID bit, invert video->last_fid
+ * when the EOF bit is set to force synchronisation on the next packet.
+ */
+ if (buf->state != UVC_BUF_STATE_ACTIVE) {
+ if (fid == video->last_fid) {
+ uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
+ "sync).\n");
+ if ((video->dev->quirks & UVC_QUIRK_STREAM_NO_FID) &&
+ (data[1] & UVC_STREAM_EOF))
+ video->last_fid ^= UVC_STREAM_FID;
+ return -ENODATA;
+ }
+
+ /* TODO: Handle PTS and SCR. */
+ buf->state = UVC_BUF_STATE_ACTIVE;
+ }
+
+ /* Mark the buffer as done if we're at the beginning of a new frame.
+ * End of frame detection is better implemented by checking the EOF
+ * bit (FID bit toggling is delayed by one frame compared to the EOF
+ * bit), but some devices don't set the bit at end of frame (and the
+ * last payload can be lost anyway). We thus must check if the FID has
+ * been toggled.
+ *
+ * queue->last_fid is initialized to -1, so the first isochronous
+ * frame will never trigger an end of frame detection.
+ *
+ * Empty buffers (bytesused == 0) don't trigger end of frame detection
+ * as it doesn't make sense to return an empty buffer. This also
+ * avoids detecting and of frame conditions at FID toggling if the
+ * previous payload had the EOF bit set.
+ */
+ if (fid != video->last_fid && buf->buf.bytesused != 0) {
+ uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit "
+ "toggled).\n");
+ buf->state = UVC_BUF_STATE_DONE;
+ return -EAGAIN;
+ }
+
+ video->last_fid = fid;
+
+ return data[0];
+}
+
+static void uvc_video_decode_data(struct uvc_video_device *video,
+ struct uvc_buffer *buf, const __u8 *data, int len)
+{
+ struct uvc_video_queue *queue = &video->queue;
+ unsigned int maxlen, nbytes;
+ void *mem;
+
+ if (len <= 0)
+ return;
+
+ /* Copy the video data to the buffer. */
+ maxlen = buf->buf.length - buf->buf.bytesused;
+ mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
+ nbytes = min((unsigned int)len, maxlen);
+ memcpy(mem, data, nbytes);
+ buf->buf.bytesused += nbytes;
+
+ /* Complete the current frame if the buffer size was exceeded. */
+ if (len > maxlen) {
+ uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");
+ buf->state = UVC_BUF_STATE_DONE;
+ }
+}
+
+static void uvc_video_decode_end(struct uvc_video_device *video,
+ struct uvc_buffer *buf, const __u8 *data, int len)
+{
+ /* Mark the buffer as done if the EOF marker is set. */
+ if (data[1] & UVC_STREAM_EOF && buf->buf.bytesused != 0) {
+ uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
+ if (data[0] == len)
+ uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n");
+ buf->state = UVC_BUF_STATE_DONE;
+ if (video->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
+ video->last_fid ^= UVC_STREAM_FID;
+ }
+}
+
+/* ------------------------------------------------------------------------
+ * URB handling
+ */
+
+/*
+ * Completion handler for video URBs.
+ */
+static void uvc_video_decode_isoc(struct urb *urb,
+ struct uvc_video_device *video, struct uvc_buffer *buf)
+{
+ u8 *mem;
+ int ret, i;
+
+ for (i = 0; i < urb->number_of_packets; ++i) {
+ if (urb->iso_frame_desc[i].status < 0) {
+ uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "
+ "lost (%d).\n", urb->iso_frame_desc[i].status);
+ continue;
+ }
+
+ /* Decode the payload header. */
+ mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+ do {
+ ret = uvc_video_decode_start(video, buf, mem,
+ urb->iso_frame_desc[i].actual_length);
+ if (ret == -EAGAIN)
+ buf = uvc_queue_next_buffer(&video->queue, buf);
+ } while (ret == -EAGAIN);
+
+ if (ret < 0)
+ continue;
+
+ /* Decode the payload data. */
+ uvc_video_decode_data(video, buf, mem + ret,
+ urb->iso_frame_desc[i].actual_length - ret);
+
+ /* Process the header again. */
+ uvc_video_decode_end(video, buf, mem, ret);
+
+ if (buf->state == UVC_BUF_STATE_DONE ||
+ buf->state == UVC_BUF_STATE_ERROR)
+ buf = uvc_queue_next_buffer(&video->queue, buf);
+ }
+}
+
+static void uvc_video_decode_bulk(struct urb *urb,
+ struct uvc_video_device *video, struct uvc_buffer *buf)
+{
+ u8 *mem;
+ int len, ret;
+
+ mem = urb->transfer_buffer;
+ len = urb->actual_length;
+ video->bulk.payload_size += len;
+
+ /* If the URB is the first of its payload, decode and save the
+ * header.
+ */
+ if (video->bulk.header_size == 0) {
+ do {
+ ret = uvc_video_decode_start(video, buf, mem, len);
+ if (ret == -EAGAIN)
+ buf = uvc_queue_next_buffer(&video->queue, buf);
+ } while (ret == -EAGAIN);
+
+ /* If an error occured skip the rest of the payload. */
+ if (ret < 0 || buf == NULL) {
+ video->bulk.skip_payload = 1;
+ return;
+ }
+
+ video->bulk.header_size = ret;
+ memcpy(video->bulk.header, mem, video->bulk.header_size);
+
+ mem += ret;
+ len -= ret;
+ }
+
+ /* The buffer queue might have been cancelled while a bulk transfer
+ * was in progress, so we can reach here with buf equal to NULL. Make
+ * sure buf is never dereferenced if NULL.
+ */
+
+ /* Process video data. */
+ if (!video->bulk.skip_payload && buf != NULL)
+ uvc_video_decode_data(video, buf, mem, len);
+
+ /* Detect the payload end by a URB smaller than the maximum size (or
+ * a payload size equal to the maximum) and process the header again.
+ */
+ if (urb->actual_length < urb->transfer_buffer_length ||
+ video->bulk.payload_size >= video->bulk.max_payload_size) {
+ if (!video->bulk.skip_payload && buf != NULL) {
+ uvc_video_decode_end(video, buf, video->bulk.header,
+ video->bulk.header_size);
+ if (buf->state == UVC_BUF_STATE_DONE ||
+ buf->state == UVC_BUF_STATE_ERROR)
+ buf = uvc_queue_next_buffer(&video->queue, buf);
+ }
+
+ video->bulk.header_size = 0;
+ video->bulk.skip_payload = 0;
+ video->bulk.payload_size = 0;
+ }
+}
+
+static void uvc_video_complete(struct urb *urb)
+{
+ struct uvc_video_device *video = urb->context;
+ struct uvc_video_queue *queue = &video->queue;
+ struct uvc_buffer *buf = NULL;
+ unsigned long flags;
+ int ret;
+
+ switch (urb->status) {
+ case 0:
+ break;
+
+ default:
+ uvc_printk(KERN_WARNING, "Non-zero status (%d) in video "
+ "completion handler.\n", urb->status);
+
+ case -ENOENT: /* usb_kill_urb() called. */
+ if (video->frozen)
+ return;
+
+ case -ECONNRESET: /* usb_unlink_urb() called. */
+ case -ESHUTDOWN: /* The endpoint is being disabled. */
+ uvc_queue_cancel(queue, urb->status == -ESHUTDOWN);
+ return;
+ }
+
+ spin_lock_irqsave(&queue->irqlock, flags);
+ if (!list_empty(&queue->irqqueue))
+ buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
+ queue);
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+
+ video->decode(urb, video, buf);
+
+ if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+ uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
+ ret);
+ }
+}
+
+/*
+ * Uninitialize isochronous/bulk URBs and free transfer buffers.
+ */
+static void uvc_uninit_video(struct uvc_video_device *video)
+{
+ struct urb *urb;
+ unsigned int i;
+
+ for (i = 0; i < UVC_URBS; ++i) {
+ if ((urb = video->urb[i]) == NULL)
+ continue;
+
+ usb_kill_urb(urb);
+ /* urb->transfer_buffer_length is not touched by USB core, so
+ * we can use it here as the buffer length.
+ */
+ if (video->urb_buffer[i]) {
+ usb_buffer_free(video->dev->udev,
+ urb->transfer_buffer_length,
+ video->urb_buffer[i], urb->transfer_dma);
+ video->urb_buffer[i] = NULL;
+ }
+
+ usb_free_urb(urb);
+ video->urb[i] = NULL;
+ }
+}
+
+/*
+ * Initialize isochronous URBs and allocate transfer buffers. The packet size
+ * is given by the endpoint.
+ */
+static int uvc_init_video_isoc(struct uvc_video_device *video,
+ struct usb_host_endpoint *ep)
+{
+ struct urb *urb;
+ unsigned int npackets, i, j;
+ __u16 psize;
+ __u32 size;
+
+ /* Compute the number of isochronous packets to allocate by dividing
+ * the maximum video frame size by the packet size. Limit the result
+ * to UVC_MAX_ISO_PACKETS.
+ */
+ psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+ psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+
+ size = video->streaming->ctrl.dwMaxVideoFrameSize;
+ if (size > UVC_MAX_FRAME_SIZE)
+ return -EINVAL;
+
+ npackets = (size + psize - 1) / psize;
+ if (npackets > UVC_MAX_ISO_PACKETS)
+ npackets = UVC_MAX_ISO_PACKETS;
+
+ size = npackets * psize;
+
+ for (i = 0; i < UVC_URBS; ++i) {
+ urb = usb_alloc_urb(npackets, GFP_KERNEL);
+ if (urb == NULL) {
+ uvc_uninit_video(video);
+ return -ENOMEM;
+ }
+
+ video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
+ size, GFP_KERNEL, &urb->transfer_dma);
+ if (video->urb_buffer[i] == NULL) {
+ usb_free_urb(urb);
+ uvc_uninit_video(video);
+ return -ENOMEM;
+ }
+
+ urb->dev = video->dev->udev;
+ urb->context = video;
+ urb->pipe = usb_rcvisocpipe(video->dev->udev,
+ ep->desc.bEndpointAddress);
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+ urb->interval = ep->desc.bInterval;
+ urb->transfer_buffer = video->urb_buffer[i];
+ urb->complete = uvc_video_complete;
+ urb->number_of_packets = npackets;
+ urb->transfer_buffer_length = size;
+
+ for (j = 0; j < npackets; ++j) {
+ urb->iso_frame_desc[j].offset = j * psize;
+ urb->iso_frame_desc[j].length = psize;
+ }
+
+ video->urb[i] = urb;
+ }
+
+ return 0;
+}
+
+/*
+ * Initialize bulk URBs and allocate transfer buffers. The packet size is
+ * given by the endpoint.
+ */
+static int uvc_init_video_bulk(struct uvc_video_device *video,
+ struct usb_host_endpoint *ep)
+{
+ struct urb *urb;
+ unsigned int pipe, i;
+ __u16 psize;
+ __u32 size;
+
+ /* Compute the bulk URB size. Some devices set the maximum payload
+ * size to a value too high for memory-constrained devices. We must
+ * then transfer the payload accross multiple URBs. To be consistant
+ * with isochronous mode, allocate maximum UVC_MAX_ISO_PACKETS per bulk
+ * URB.
+ */
+ psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;
+ size = video->streaming->ctrl.dwMaxPayloadTransferSize;
+ video->bulk.max_payload_size = size;
+ if (size > psize * UVC_MAX_ISO_PACKETS)
+ size = psize * UVC_MAX_ISO_PACKETS;
+
+ pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress);
+
+ for (i = 0; i < UVC_URBS; ++i) {
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (urb == NULL) {
+ uvc_uninit_video(video);
+ return -ENOMEM;
+ }
+
+ video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
+ size, GFP_KERNEL, &urb->transfer_dma);
+ if (video->urb_buffer[i] == NULL) {
+ usb_free_urb(urb);
+ uvc_uninit_video(video);
+ return -ENOMEM;
+ }
+
+ usb_fill_bulk_urb(urb, video->dev->udev, pipe,
+ video->urb_buffer[i], size, uvc_video_complete,
+ video);
+ urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+
+ video->urb[i] = urb;
+ }
+
+ return 0;
+}
+
+/*
+ * Initialize isochronous/bulk URBs and allocate transfer buffers.
+ */
+static int uvc_init_video(struct uvc_video_device *video)
+{
+ struct usb_interface *intf = video->streaming->intf;
+ struct usb_host_interface *alts;
+ struct usb_host_endpoint *ep = NULL;
+ int intfnum = video->streaming->intfnum;
+ unsigned int bandwidth, psize, i;
+ int ret;
+
+ video->last_fid = -1;
+ video->bulk.header_size = 0;
+ video->bulk.skip_payload = 0;
+ video->bulk.payload_size = 0;
+
+ if (intf->num_altsetting > 1) {
+ /* Isochronous endpoint, select the alternate setting. */
+ bandwidth = video->streaming->ctrl.dwMaxPayloadTransferSize;
+
+ if (bandwidth == 0) {
+ uvc_printk(KERN_WARNING, "device %s requested null "
+ "bandwidth, defaulting to lowest.\n",
+ video->vdev->name);
+ bandwidth = 1;
+ }
+
+ for (i = 0; i < intf->num_altsetting; ++i) {
+ alts = &intf->altsetting[i];
+ ep = uvc_find_endpoint(alts,
+ video->streaming->header.bEndpointAddress);
+ if (ep == NULL)
+ continue;
+
+ /* Check if the bandwidth is high enough. */
+ psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+ psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+ if (psize >= bandwidth)
+ break;
+ }
+
+ if (i >= intf->num_altsetting)
+ return -EIO;
+
+ if ((ret = usb_set_interface(video->dev->udev, intfnum, i)) < 0)
+ return ret;
+
+ ret = uvc_init_video_isoc(video, ep);
+ } else {
+ /* Bulk endpoint, proceed to URB initialization. */
+ ep = uvc_find_endpoint(&intf->altsetting[0],
+ video->streaming->header.bEndpointAddress);
+ if (ep == NULL)
+ return -EIO;
+
+ ret = uvc_init_video_bulk(video, ep);
+ }
+
+ if (ret < 0)
+ return ret;
+
+ /* Submit the URBs. */
+ for (i = 0; i < UVC_URBS; ++i) {
+ if ((ret = usb_submit_urb(video->urb[i], GFP_KERNEL)) < 0) {
+ uvc_printk(KERN_ERR, "Failed to submit URB %u "
+ "(%d).\n", i, ret);
+ uvc_uninit_video(video);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * Suspend/resume
+ */
+
+/*
+ * Stop streaming without disabling the video queue.
+ *
+ * To let userspace applications resume without trouble, we must not touch the
+ * video buffers in any way. We mark the device as frozen to make sure the URB
+ * completion handler won't try to cancel the queue when we kill the URBs.
+ */
+int uvc_video_suspend(struct uvc_video_device *video)
+{
+ if (!uvc_queue_streaming(&video->queue))
+ return 0;
+
+ video->frozen = 1;
+ uvc_uninit_video(video);
+ usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
+ return 0;
+}
+
+/*
+ * Reconfigure the video interface and restart streaming if it was enable
+ * before suspend.
+ *
+ * If an error occurs, disable the video queue. This will wake all pending
+ * buffers, making sure userspace applications are notified of the problem
+ * instead of waiting forever.
+ */
+int uvc_video_resume(struct uvc_video_device *video)
+{
+ int ret;
+
+ video->frozen = 0;
+
+ if ((ret = uvc_set_video_ctrl(video, &video->streaming->ctrl, 0)) < 0) {
+ uvc_queue_enable(&video->queue, 0);
+ return ret;
+ }
+
+ if (!uvc_queue_streaming(&video->queue))
+ return 0;
+
+ if ((ret = uvc_init_video(video)) < 0)
+ uvc_queue_enable(&video->queue, 0);
+
+ return ret;
+}
+
+/* ------------------------------------------------------------------------
+ * Video device
+ */
+
+/*
+ * Initialize the UVC video device by retrieving the default format and
+ * committing it.
+ *
+ * Some cameras (namely the Fuji Finepix) set the format and frame
+ * indexes to zero. The UVC standard doesn't clearly make this a spec
+ * violation, so try to silently fix the values if possible.
+ *
+ * This function is called before registering the device with V4L.
+ */
+int uvc_video_init(struct uvc_video_device *video)
+{
+ struct uvc_streaming_control *probe = &video->streaming->ctrl;
+ struct uvc_format *format = NULL;
+ struct uvc_frame *frame = NULL;
+ unsigned int i;
+ int ret;
+
+ if (video->streaming->nformats == 0) {
+ uvc_printk(KERN_INFO, "No supported video formats found.\n");
+ return -EINVAL;
+ }
+
+ /* Alternate setting 0 should be the default, yet the XBox Live Vision
+ * Cam (and possibly other devices) crash or otherwise misbehave if
+ * they don't receive a SET_INTERFACE request before any other video
+ * control request.
+ */
+ usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
+
+ /* Some webcams don't suport GET_DEF request on the probe control. We
+ * fall back to GET_CUR if GET_DEF fails.
+ */
+ if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_DEF)) < 0 &&
+ (ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+ return ret;
+
+ /* Check if the default format descriptor exists. Use the first
+ * available format otherwise.
+ */
+ for (i = video->streaming->nformats; i > 0; --i) {
+ format = &video->streaming->format[i-1];
+ if (format->index == probe->bFormatIndex)
+ break;
+ }
+
+ if (format->nframes == 0) {
+ uvc_printk(KERN_INFO, "No frame descriptor found for the "
+ "default format.\n");
+ return -EINVAL;
+ }
+
+ /* Zero bFrameIndex might be correct. Stream-based formats (including
+ * MPEG-2 TS and DV) do not support frames but have a dummy frame
+ * descriptor with bFrameIndex set to zero. If the default frame
+ * descriptor is not found, use the first avalable frame.
+ */
+ for (i = format->nframes; i > 0; --i) {
+ frame = &format->frame[i-1];
+ if (frame->bFrameIndex == probe->bFrameIndex)
+ break;
+ }
+
+ /* Commit the default settings. */
+ probe->bFormatIndex = format->index;
+ probe->bFrameIndex = frame->bFrameIndex;
+ if ((ret = uvc_set_video_ctrl(video, probe, 0)) < 0)
+ return ret;
+
+ video->streaming->cur_format = format;
+ video->streaming->cur_frame = frame;
+ atomic_set(&video->active, 0);
+
+ /* Select the video decoding function */
+ if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
+ video->decode = uvc_video_decode_isight;
+ else if (video->streaming->intf->num_altsetting > 1)
+ video->decode = uvc_video_decode_isoc;
+ else
+ video->decode = uvc_video_decode_bulk;
+
+ return 0;
+}
+
+/*
+ * Enable or disable the video stream.
+ */
+int uvc_video_enable(struct uvc_video_device *video, int enable)
+{
+ int ret;
+
+ if (!enable) {
+ uvc_uninit_video(video);
+ usb_set_interface(video->dev->udev,
+ video->streaming->intfnum, 0);
+ uvc_queue_enable(&video->queue, 0);
+ return 0;
+ }
+
+ if ((ret = uvc_queue_enable(&video->queue, 1)) < 0)
+ return ret;
+
+ return uvc_init_video(video);
+}
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
new file mode 100644
index 000000000000..a995a780db1c
--- /dev/null
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -0,0 +1,796 @@
+#ifndef _USB_VIDEO_H_
+#define _USB_VIDEO_H_
+
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+
+
+/*
+ * Dynamic controls
+ */
+
+/* Data types for UVC control data */
+#define UVC_CTRL_DATA_TYPE_RAW 0
+#define UVC_CTRL_DATA_TYPE_SIGNED 1
+#define UVC_CTRL_DATA_TYPE_UNSIGNED 2
+#define UVC_CTRL_DATA_TYPE_BOOLEAN 3
+#define UVC_CTRL_DATA_TYPE_ENUM 4
+#define UVC_CTRL_DATA_TYPE_BITMASK 5
+
+/* Control flags */
+#define UVC_CONTROL_SET_CUR (1 << 0)
+#define UVC_CONTROL_GET_CUR (1 << 1)
+#define UVC_CONTROL_GET_MIN (1 << 2)
+#define UVC_CONTROL_GET_MAX (1 << 3)
+#define UVC_CONTROL_GET_RES (1 << 4)
+#define UVC_CONTROL_GET_DEF (1 << 5)
+/* Control should be saved at suspend and restored at resume. */
+#define UVC_CONTROL_RESTORE (1 << 6)
+/* Control can be updated by the camera. */
+#define UVC_CONTROL_AUTO_UPDATE (1 << 7)
+
+#define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \
+ UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \
+ UVC_CONTROL_GET_DEF)
+
+struct uvc_xu_control_info {
+ __u8 entity[16];
+ __u8 index;
+ __u8 selector;
+ __u16 size;
+ __u32 flags;
+};
+
+struct uvc_xu_control_mapping {
+ __u32 id;
+ __u8 name[32];
+ __u8 entity[16];
+ __u8 selector;
+
+ __u8 size;
+ __u8 offset;
+ enum v4l2_ctrl_type v4l2_type;
+ __u32 data_type;
+};
+
+struct uvc_xu_control {
+ __u8 unit;
+ __u8 selector;
+ __u16 size;
+ __u8 __user *data;
+};
+
+#define UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info)
+#define UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping)
+#define UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control)
+#define UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control)
+
+#ifdef __KERNEL__
+
+#include <linux/poll.h>
+
+/* --------------------------------------------------------------------------
+ * UVC constants
+ */
+
+#define SC_UNDEFINED 0x00
+#define SC_VIDEOCONTROL 0x01
+#define SC_VIDEOSTREAMING 0x02
+#define SC_VIDEO_INTERFACE_COLLECTION 0x03
+
+#define PC_PROTOCOL_UNDEFINED 0x00
+
+#define CS_UNDEFINED 0x20
+#define CS_DEVICE 0x21
+#define CS_CONFIGURATION 0x22
+#define CS_STRING 0x23
+#define CS_INTERFACE 0x24
+#define CS_ENDPOINT 0x25
+
+/* VideoControl class specific interface descriptor */
+#define VC_DESCRIPTOR_UNDEFINED 0x00
+#define VC_HEADER 0x01
+#define VC_INPUT_TERMINAL 0x02
+#define VC_OUTPUT_TERMINAL 0x03
+#define VC_SELECTOR_UNIT 0x04
+#define VC_PROCESSING_UNIT 0x05
+#define VC_EXTENSION_UNIT 0x06
+
+/* VideoStreaming class specific interface descriptor */
+#define VS_UNDEFINED 0x00
+#define VS_INPUT_HEADER 0x01
+#define VS_OUTPUT_HEADER 0x02
+#define VS_STILL_IMAGE_FRAME 0x03
+#define VS_FORMAT_UNCOMPRESSED 0x04
+#define VS_FRAME_UNCOMPRESSED 0x05
+#define VS_FORMAT_MJPEG 0x06
+#define VS_FRAME_MJPEG 0x07
+#define VS_FORMAT_MPEG2TS 0x0a
+#define VS_FORMAT_DV 0x0c
+#define VS_COLORFORMAT 0x0d
+#define VS_FORMAT_FRAME_BASED 0x10
+#define VS_FRAME_FRAME_BASED 0x11
+#define VS_FORMAT_STREAM_BASED 0x12
+
+/* Endpoint type */
+#define EP_UNDEFINED 0x00
+#define EP_GENERAL 0x01
+#define EP_ENDPOINT 0x02
+#define EP_INTERRUPT 0x03
+
+/* Request codes */
+#define RC_UNDEFINED 0x00
+#define SET_CUR 0x01
+#define GET_CUR 0x81
+#define GET_MIN 0x82
+#define GET_MAX 0x83
+#define GET_RES 0x84
+#define GET_LEN 0x85
+#define GET_INFO 0x86
+#define GET_DEF 0x87
+
+/* VideoControl interface controls */
+#define VC_CONTROL_UNDEFINED 0x00
+#define VC_VIDEO_POWER_MODE_CONTROL 0x01
+#define VC_REQUEST_ERROR_CODE_CONTROL 0x02
+
+/* Terminal controls */
+#define TE_CONTROL_UNDEFINED 0x00
+
+/* Selector Unit controls */
+#define SU_CONTROL_UNDEFINED 0x00
+#define SU_INPUT_SELECT_CONTROL 0x01
+
+/* Camera Terminal controls */
+#define CT_CONTROL_UNDEFINED 0x00
+#define CT_SCANNING_MODE_CONTROL 0x01
+#define CT_AE_MODE_CONTROL 0x02
+#define CT_AE_PRIORITY_CONTROL 0x03
+#define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04
+#define CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05
+#define CT_FOCUS_ABSOLUTE_CONTROL 0x06
+#define CT_FOCUS_RELATIVE_CONTROL 0x07
+#define CT_FOCUS_AUTO_CONTROL 0x08
+#define CT_IRIS_ABSOLUTE_CONTROL 0x09
+#define CT_IRIS_RELATIVE_CONTROL 0x0a
+#define CT_ZOOM_ABSOLUTE_CONTROL 0x0b
+#define CT_ZOOM_RELATIVE_CONTROL 0x0c
+#define CT_PANTILT_ABSOLUTE_CONTROL 0x0d
+#define CT_PANTILT_RELATIVE_CONTROL 0x0e
+#define CT_ROLL_ABSOLUTE_CONTROL 0x0f
+#define CT_ROLL_RELATIVE_CONTROL 0x10
+#define CT_PRIVACY_CONTROL 0x11
+
+/* Processing Unit controls */
+#define PU_CONTROL_UNDEFINED 0x00
+#define PU_BACKLIGHT_COMPENSATION_CONTROL 0x01
+#define PU_BRIGHTNESS_CONTROL 0x02
+#define PU_CONTRAST_CONTROL 0x03
+#define PU_GAIN_CONTROL 0x04
+#define PU_POWER_LINE_FREQUENCY_CONTROL 0x05
+#define PU_HUE_CONTROL 0x06
+#define PU_SATURATION_CONTROL 0x07
+#define PU_SHARPNESS_CONTROL 0x08
+#define PU_GAMMA_CONTROL 0x09
+#define PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0a
+#define PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0b
+#define PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0c
+#define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0d
+#define PU_DIGITAL_MULTIPLIER_CONTROL 0x0e
+#define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0f
+#define PU_HUE_AUTO_CONTROL 0x10
+#define PU_ANALOG_VIDEO_STANDARD_CONTROL 0x11
+#define PU_ANALOG_LOCK_STATUS_CONTROL 0x12
+
+#define LXU_MOTOR_PANTILT_RELATIVE_CONTROL 0x01
+#define LXU_MOTOR_PANTILT_RESET_CONTROL 0x02
+#define LXU_MOTOR_FOCUS_MOTOR_CONTROL 0x03
+
+/* VideoStreaming interface controls */
+#define VS_CONTROL_UNDEFINED 0x00
+#define VS_PROBE_CONTROL 0x01
+#define VS_COMMIT_CONTROL 0x02
+#define VS_STILL_PROBE_CONTROL 0x03
+#define VS_STILL_COMMIT_CONTROL 0x04
+#define VS_STILL_IMAGE_TRIGGER_CONTROL 0x05
+#define VS_STREAM_ERROR_CODE_CONTROL 0x06
+#define VS_GENERATE_KEY_FRAME_CONTROL 0x07
+#define VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08
+#define VS_SYNC_DELAY_CONTROL 0x09
+
+#define TT_VENDOR_SPECIFIC 0x0100
+#define TT_STREAMING 0x0101
+
+/* Input Terminal types */
+#define ITT_VENDOR_SPECIFIC 0x0200
+#define ITT_CAMERA 0x0201
+#define ITT_MEDIA_TRANSPORT_INPUT 0x0202
+
+/* Output Terminal types */
+#define OTT_VENDOR_SPECIFIC 0x0300
+#define OTT_DISPLAY 0x0301
+#define OTT_MEDIA_TRANSPORT_OUTPUT 0x0302
+
+/* External Terminal types */
+#define EXTERNAL_VENDOR_SPECIFIC 0x0400
+#define COMPOSITE_CONNECTOR 0x0401
+#define SVIDEO_CONNECTOR 0x0402
+#define COMPONENT_CONNECTOR 0x0403
+
+#define UVC_TERM_INPUT 0x0000
+#define UVC_TERM_OUTPUT 0x8000
+
+#define UVC_ENTITY_TYPE(entity) ((entity)->type & 0x7fff)
+#define UVC_ENTITY_IS_UNIT(entity) (((entity)->type & 0xff00) == 0)
+#define UVC_ENTITY_IS_TERM(entity) (((entity)->type & 0xff00) != 0)
+#define UVC_ENTITY_IS_ITERM(entity) \
+ (((entity)->type & 0x8000) == UVC_TERM_INPUT)
+#define UVC_ENTITY_IS_OTERM(entity) \
+ (((entity)->type & 0x8000) == UVC_TERM_OUTPUT)
+
+#define UVC_STATUS_TYPE_CONTROL 1
+#define UVC_STATUS_TYPE_STREAMING 2
+
+/* ------------------------------------------------------------------------
+ * GUIDs
+ */
+#define UVC_GUID_UVC_CAMERA \
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
+#define UVC_GUID_UVC_OUTPUT \
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}
+#define UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT \
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+#define UVC_GUID_UVC_PROCESSING \
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01}
+#define UVC_GUID_UVC_SELECTOR \
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}
+
+#define UVC_GUID_LOGITECH_DEV_INFO \
+ {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
+ 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1e}
+#define UVC_GUID_LOGITECH_USER_HW \
+ {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
+ 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1f}
+#define UVC_GUID_LOGITECH_VIDEO \
+ {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
+ 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x50}
+#define UVC_GUID_LOGITECH_MOTOR \
+ {0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
+ 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x56}
+
+#define UVC_GUID_FORMAT_MJPEG \
+ { 'M', 'J', 'P', 'G', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YUY2 \
+ { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_NV12 \
+ { 'N', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YV12 \
+ { 'Y', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_I420 \
+ { 'I', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_UYVY \
+ { 'U', 'Y', 'V', 'Y', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y800 \
+ { 'Y', '8', '0', '0', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_BY8 \
+ { 'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+
+
+/* ------------------------------------------------------------------------
+ * Driver specific constants.
+ */
+
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 0)
+
+/* Number of isochronous URBs. */
+#define UVC_URBS 5
+/* Maximum number of packets per isochronous URB. */
+#define UVC_MAX_ISO_PACKETS 40
+/* Maximum frame size in bytes, for sanity checking. */
+#define UVC_MAX_FRAME_SIZE (16*1024*1024)
+/* Maximum number of video buffers. */
+#define UVC_MAX_VIDEO_BUFFERS 32
+
+#define UVC_CTRL_CONTROL_TIMEOUT 300
+#define UVC_CTRL_STREAMING_TIMEOUT 1000
+
+/* Devices quirks */
+#define UVC_QUIRK_STATUS_INTERVAL 0x00000001
+#define UVC_QUIRK_PROBE_MINMAX 0x00000002
+#define UVC_QUIRK_PROBE_EXTRAFIELDS 0x00000004
+#define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008
+#define UVC_QUIRK_STREAM_NO_FID 0x00000010
+#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
+
+/* Format flags */
+#define UVC_FMT_FLAG_COMPRESSED 0x00000001
+#define UVC_FMT_FLAG_STREAM 0x00000002
+
+/* ------------------------------------------------------------------------
+ * Structures.
+ */
+
+struct uvc_device;
+
+/* TODO: Put the most frequently accessed fields at the beginning of
+ * structures to maximize cache efficiency.
+ */
+struct uvc_streaming_control {
+ __u16 bmHint;
+ __u8 bFormatIndex;
+ __u8 bFrameIndex;
+ __u32 dwFrameInterval;
+ __u16 wKeyFrameRate;
+ __u16 wPFrameRate;
+ __u16 wCompQuality;
+ __u16 wCompWindowSize;
+ __u16 wDelay;
+ __u32 dwMaxVideoFrameSize;
+ __u32 dwMaxPayloadTransferSize;
+ __u32 dwClockFrequency;
+ __u8 bmFramingInfo;
+ __u8 bPreferedVersion;
+ __u8 bMinVersion;
+ __u8 bMaxVersion;
+};
+
+struct uvc_menu_info {
+ __u32 value;
+ __u8 name[32];
+};
+
+struct uvc_control_info {
+ struct list_head list;
+ struct list_head mappings;
+
+ __u8 entity[16];
+ __u8 index;
+ __u8 selector;
+
+ __u16 size;
+ __u32 flags;
+};
+
+struct uvc_control_mapping {
+ struct list_head list;
+
+ struct uvc_control_info *ctrl;
+
+ __u32 id;
+ __u8 name[32];
+ __u8 entity[16];
+ __u8 selector;
+
+ __u8 size;
+ __u8 offset;
+ enum v4l2_ctrl_type v4l2_type;
+ __u32 data_type;
+
+ struct uvc_menu_info *menu_info;
+ __u32 menu_count;
+};
+
+struct uvc_control {
+ struct uvc_entity *entity;
+ struct uvc_control_info *info;
+
+ __u8 index; /* Used to match the uvc_control entry with a
+ uvc_control_info. */
+ __u8 dirty : 1,
+ loaded : 1,
+ modified : 1;
+
+ __u8 *data;
+};
+
+struct uvc_format_desc {
+ char *name;
+ __u8 guid[16];
+ __u32 fcc;
+};
+
+/* The term 'entity' refers to both UVC units and UVC terminals.
+ *
+ * The type field is either the terminal type (wTerminalType in the terminal
+ * descriptor), or the unit type (bDescriptorSubtype in the unit descriptor).
+ * As the bDescriptorSubtype field is one byte long, the type value will
+ * always have a null MSB for units. All terminal types defined by the UVC
+ * specification have a non-null MSB, so it is safe to use the MSB to
+ * differentiate between units and terminals as long as the descriptor parsing
+ * code makes sure terminal types have a non-null MSB.
+ *
+ * For terminals, the type's most significant bit stores the terminal
+ * direction (either UVC_TERM_INPUT or UVC_TERM_OUTPUT). The type field should
+ * always be accessed with the UVC_ENTITY_* macros and never directly.
+ */
+
+struct uvc_entity {
+ struct list_head list; /* Entity as part of a UVC device. */
+ struct list_head chain; /* Entity as part of a video device
+ * chain. */
+ __u8 id;
+ __u16 type;
+ char name[64];
+
+ union {
+ struct {
+ __u16 wObjectiveFocalLengthMin;
+ __u16 wObjectiveFocalLengthMax;
+ __u16 wOcularFocalLength;
+ __u8 bControlSize;
+ __u8 *bmControls;
+ } camera;
+
+ struct {
+ __u8 bControlSize;
+ __u8 *bmControls;
+ __u8 bTransportModeSize;
+ __u8 *bmTransportModes;
+ } media;
+
+ struct {
+ __u8 bSourceID;
+ } output;
+
+ struct {
+ __u8 bSourceID;
+ __u16 wMaxMultiplier;
+ __u8 bControlSize;
+ __u8 *bmControls;
+ __u8 bmVideoStandards;
+ } processing;
+
+ struct {
+ __u8 bNrInPins;
+ __u8 *baSourceID;
+ } selector;
+
+ struct {
+ __u8 guidExtensionCode[16];
+ __u8 bNumControls;
+ __u8 bNrInPins;
+ __u8 *baSourceID;
+ __u8 bControlSize;
+ __u8 *bmControls;
+ __u8 *bmControlsType;
+ } extension;
+ };
+
+ unsigned int ncontrols;
+ struct uvc_control *controls;
+};
+
+struct uvc_frame {
+ __u8 bFrameIndex;
+ __u8 bmCapabilities;
+ __u16 wWidth;
+ __u16 wHeight;
+ __u32 dwMinBitRate;
+ __u32 dwMaxBitRate;
+ __u32 dwMaxVideoFrameBufferSize;
+ __u8 bFrameIntervalType;
+ __u32 dwDefaultFrameInterval;
+ __u32 *dwFrameInterval;
+};
+
+struct uvc_format {
+ __u8 type;
+ __u8 index;
+ __u8 bpp;
+ __u8 colorspace;
+ __u32 fcc;
+ __u32 flags;
+
+ char name[32];
+
+ unsigned int nframes;
+ struct uvc_frame *frame;
+};
+
+struct uvc_streaming_header {
+ __u8 bNumFormats;
+ __u8 bEndpointAddress;
+ __u8 bTerminalLink;
+ __u8 bControlSize;
+ __u8 *bmaControls;
+ /* The following fields are used by input headers only. */
+ __u8 bmInfo;
+ __u8 bStillCaptureMethod;
+ __u8 bTriggerSupport;
+ __u8 bTriggerUsage;
+};
+
+struct uvc_streaming {
+ struct list_head list;
+
+ struct usb_interface *intf;
+ int intfnum;
+ __u16 maxpsize;
+
+ struct uvc_streaming_header header;
+
+ unsigned int nformats;
+ struct uvc_format *format;
+
+ struct uvc_streaming_control ctrl;
+ struct uvc_format *cur_format;
+ struct uvc_frame *cur_frame;
+
+ struct mutex mutex;
+};
+
+enum uvc_buffer_state {
+ UVC_BUF_STATE_IDLE = 0,
+ UVC_BUF_STATE_QUEUED = 1,
+ UVC_BUF_STATE_ACTIVE = 2,
+ UVC_BUF_STATE_DONE = 3,
+ UVC_BUF_STATE_ERROR = 4,
+};
+
+struct uvc_buffer {
+ unsigned long vma_use_count;
+ struct list_head stream;
+
+ /* Touched by interrupt handler. */
+ struct v4l2_buffer buf;
+ struct list_head queue;
+ wait_queue_head_t wait;
+ enum uvc_buffer_state state;
+};
+
+#define UVC_QUEUE_STREAMING (1 << 0)
+#define UVC_QUEUE_DISCONNECTED (1 << 1)
+#define UVC_QUEUE_DROP_INCOMPLETE (1 << 2)
+
+struct uvc_video_queue {
+ void *mem;
+ unsigned int flags;
+ __u32 sequence;
+
+ unsigned int count;
+ unsigned int buf_size;
+ struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS];
+ struct mutex mutex; /* protects buffers and mainqueue */
+ spinlock_t irqlock; /* protects irqqueue */
+
+ struct list_head mainqueue;
+ struct list_head irqqueue;
+};
+
+struct uvc_video_device {
+ struct uvc_device *dev;
+ struct video_device *vdev;
+ atomic_t active;
+ unsigned int frozen : 1;
+
+ struct list_head iterms;
+ struct uvc_entity *oterm;
+ struct uvc_entity *processing;
+ struct uvc_entity *selector;
+ struct list_head extensions;
+ struct mutex ctrl_mutex;
+
+ struct uvc_video_queue queue;
+
+ /* Video streaming object, must always be non-NULL. */
+ struct uvc_streaming *streaming;
+
+ void (*decode) (struct urb *urb, struct uvc_video_device *video,
+ struct uvc_buffer *buf);
+
+ /* Context data used by the bulk completion handler. */
+ struct {
+ __u8 header[256];
+ unsigned int header_size;
+ int skip_payload;
+ __u32 payload_size;
+ __u32 max_payload_size;
+ } bulk;
+
+ struct urb *urb[UVC_URBS];
+ char *urb_buffer[UVC_URBS];
+
+ __u8 last_fid;
+};
+
+enum uvc_device_state {
+ UVC_DEV_DISCONNECTED = 1,
+};
+
+struct uvc_device {
+ struct usb_device *udev;
+ struct usb_interface *intf;
+ __u32 quirks;
+ int intfnum;
+ char name[32];
+
+ enum uvc_device_state state;
+ struct kref kref;
+ struct list_head list;
+
+ /* Video control interface */
+ __u16 uvc_version;
+ __u32 clock_frequency;
+
+ struct list_head entities;
+
+ struct uvc_video_device video;
+
+ /* Status Interrupt Endpoint */
+ struct usb_host_endpoint *int_ep;
+ struct urb *int_urb;
+ __u8 status[16];
+ struct input_dev *input;
+
+ /* Video Streaming interfaces */
+ struct list_head streaming;
+};
+
+enum uvc_handle_state {
+ UVC_HANDLE_PASSIVE = 0,
+ UVC_HANDLE_ACTIVE = 1,
+};
+
+struct uvc_fh {
+ struct uvc_video_device *device;
+ enum uvc_handle_state state;
+};
+
+struct uvc_driver {
+ struct usb_driver driver;
+
+ struct mutex open_mutex; /* protects from open/disconnect race */
+
+ struct list_head devices; /* struct uvc_device list */
+ struct list_head controls; /* struct uvc_control_info list */
+ struct mutex ctrl_mutex; /* protects controls and devices
+ lists */
+};
+
+/* ------------------------------------------------------------------------
+ * Debugging, printing and logging
+ */
+
+#define UVC_TRACE_PROBE (1 << 0)
+#define UVC_TRACE_DESCR (1 << 1)
+#define UVC_TRACE_CONTROL (1 << 2)
+#define UVC_TRACE_FORMAT (1 << 3)
+#define UVC_TRACE_CAPTURE (1 << 4)
+#define UVC_TRACE_CALLS (1 << 5)
+#define UVC_TRACE_IOCTL (1 << 6)
+#define UVC_TRACE_FRAME (1 << 7)
+#define UVC_TRACE_SUSPEND (1 << 8)
+#define UVC_TRACE_STATUS (1 << 9)
+
+extern unsigned int uvc_trace_param;
+
+#define uvc_trace(flag, msg...) \
+ do { \
+ if (uvc_trace_param & flag) \
+ printk(KERN_DEBUG "uvcvideo: " msg); \
+ } while (0)
+
+#define uvc_printk(level, msg...) \
+ printk(level "uvcvideo: " msg)
+
+#define UVC_GUID_FORMAT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" \
+ "%02x%02x%02x%02x%02x%02x"
+#define UVC_GUID_ARGS(guid) \
+ (guid)[3], (guid)[2], (guid)[1], (guid)[0], \
+ (guid)[5], (guid)[4], \
+ (guid)[7], (guid)[6], \
+ (guid)[8], (guid)[9], \
+ (guid)[10], (guid)[11], (guid)[12], \
+ (guid)[13], (guid)[14], (guid)[15]
+
+/* --------------------------------------------------------------------------
+ * Internal functions.
+ */
+
+/* Core driver */
+extern struct uvc_driver uvc_driver;
+extern void uvc_delete(struct kref *kref);
+
+/* Video buffers queue management. */
+extern void uvc_queue_init(struct uvc_video_queue *queue);
+extern int uvc_alloc_buffers(struct uvc_video_queue *queue,
+ unsigned int nbuffers, unsigned int buflength);
+extern int uvc_free_buffers(struct uvc_video_queue *queue);
+extern int uvc_query_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *v4l2_buf);
+extern int uvc_queue_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *v4l2_buf);
+extern int uvc_dequeue_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *v4l2_buf, int nonblocking);
+extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable);
+extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
+extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
+ struct uvc_buffer *buf);
+extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
+ struct file *file, poll_table *wait);
+static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
+{
+ return queue->flags & UVC_QUEUE_STREAMING;
+}
+
+/* V4L2 interface */
+extern struct file_operations uvc_fops;
+
+/* Video */
+extern int uvc_video_init(struct uvc_video_device *video);
+extern int uvc_video_suspend(struct uvc_video_device *video);
+extern int uvc_video_resume(struct uvc_video_device *video);
+extern int uvc_video_enable(struct uvc_video_device *video, int enable);
+extern int uvc_probe_video(struct uvc_video_device *video,
+ struct uvc_streaming_control *probe);
+extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+ __u8 intfnum, __u8 cs, void *data, __u16 size);
+extern int uvc_set_video_ctrl(struct uvc_video_device *video,
+ struct uvc_streaming_control *ctrl, int probe);
+
+/* Status */
+extern int uvc_status_init(struct uvc_device *dev);
+extern void uvc_status_cleanup(struct uvc_device *dev);
+extern int uvc_status_suspend(struct uvc_device *dev);
+extern int uvc_status_resume(struct uvc_device *dev);
+
+/* Controls */
+extern struct uvc_control *uvc_find_control(struct uvc_video_device *video,
+ __u32 v4l2_id, struct uvc_control_mapping **mapping);
+extern int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
+ struct v4l2_queryctrl *v4l2_ctrl);
+
+extern int uvc_ctrl_add_info(struct uvc_control_info *info);
+extern int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping);
+extern int uvc_ctrl_init_device(struct uvc_device *dev);
+extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
+extern int uvc_ctrl_resume_device(struct uvc_device *dev);
+extern void uvc_ctrl_init(void);
+
+extern int uvc_ctrl_begin(struct uvc_video_device *video);
+extern int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback);
+static inline int uvc_ctrl_commit(struct uvc_video_device *video)
+{
+ return __uvc_ctrl_commit(video, 0);
+}
+static inline int uvc_ctrl_rollback(struct uvc_video_device *video)
+{
+ return __uvc_ctrl_commit(video, 1);
+}
+
+extern int uvc_ctrl_get(struct uvc_video_device *video,
+ struct v4l2_ext_control *xctrl);
+extern int uvc_ctrl_set(struct uvc_video_device *video,
+ struct v4l2_ext_control *xctrl);
+
+extern int uvc_xu_ctrl_query(struct uvc_video_device *video,
+ struct uvc_xu_control *ctrl, int set);
+
+/* Utility functions */
+extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
+ unsigned int n_terms, unsigned int threshold);
+extern uint32_t uvc_fraction_to_interval(uint32_t numerator,
+ uint32_t denominator);
+extern struct usb_host_endpoint *uvc_find_endpoint(
+ struct usb_host_interface *alts, __u8 epaddr);
+
+/* Quirks support */
+void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
+ struct uvc_buffer *buf);
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index 982f4463896c..0a88c44ace00 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -331,7 +331,7 @@ int videobuf_mmap_free(struct videobuf_queue *q)
}
/* Locking: Caller holds q->vb_lock */
-static int __videobuf_mmap_setup(struct videobuf_queue *q,
+int __videobuf_mmap_setup(struct videobuf_queue *q,
unsigned int bcount, unsigned int bsize,
enum v4l2_memory memory)
{
@@ -1129,6 +1129,7 @@ EXPORT_SYMBOL_GPL(videobuf_read_stream);
EXPORT_SYMBOL_GPL(videobuf_read_one);
EXPORT_SYMBOL_GPL(videobuf_poll_stream);
+EXPORT_SYMBOL_GPL(__videobuf_mmap_setup);
EXPORT_SYMBOL_GPL(videobuf_mmap_setup);
EXPORT_SYMBOL_GPL(videobuf_mmap_free);
EXPORT_SYMBOL_GPL(videobuf_mmap_mapper);
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index e5679c28163f..7649860a388d 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -52,12 +52,51 @@
#define VIDEO_NUM_DEVICES 256
#define VIDEO_NAME "video4linux"
+struct std_descr {
+ v4l2_std_id std;
+ const char *descr;
+};
+
+static const struct std_descr standards[] = {
+ { V4L2_STD_NTSC, "NTSC" },
+ { V4L2_STD_NTSC_M, "NTSC-M" },
+ { V4L2_STD_NTSC_M_JP, "NTSC-M-JP" },
+ { V4L2_STD_NTSC_M_KR, "NTSC-M-KR" },
+ { V4L2_STD_NTSC_443, "NTSC-443" },
+ { V4L2_STD_PAL, "PAL" },
+ { V4L2_STD_PAL_BG, "PAL-BG" },
+ { V4L2_STD_PAL_B, "PAL-B" },
+ { V4L2_STD_PAL_B1, "PAL-B1" },
+ { V4L2_STD_PAL_G, "PAL-G" },
+ { V4L2_STD_PAL_H, "PAL-H" },
+ { V4L2_STD_PAL_I, "PAL-I" },
+ { V4L2_STD_PAL_DK, "PAL-DK" },
+ { V4L2_STD_PAL_D, "PAL-D" },
+ { V4L2_STD_PAL_D1, "PAL-D1" },
+ { V4L2_STD_PAL_K, "PAL-K" },
+ { V4L2_STD_PAL_M, "PAL-M" },
+ { V4L2_STD_PAL_N, "PAL-N" },
+ { V4L2_STD_PAL_Nc, "PAL-Nc" },
+ { V4L2_STD_PAL_60, "PAL-60" },
+ { V4L2_STD_SECAM, "SECAM" },
+ { V4L2_STD_SECAM_B, "SECAM-B" },
+ { V4L2_STD_SECAM_G, "SECAM-G" },
+ { V4L2_STD_SECAM_H, "SECAM-H" },
+ { V4L2_STD_SECAM_DK, "SECAM-DK" },
+ { V4L2_STD_SECAM_D, "SECAM-D" },
+ { V4L2_STD_SECAM_K, "SECAM-K" },
+ { V4L2_STD_SECAM_K1, "SECAM-K1" },
+ { V4L2_STD_SECAM_L, "SECAM-L" },
+ { V4L2_STD_SECAM_LC, "SECAM-Lc" },
+ { 0, "Unknown" }
+};
+
/* video4linux standard ID conversion to standard name
*/
-char *v4l2_norm_to_name(v4l2_std_id id)
+const char *v4l2_norm_to_name(v4l2_std_id id)
{
- char *name;
u32 myid = id;
+ int i;
/* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle
64 bit comparations. So, on that architecture, with some gcc
@@ -65,110 +104,17 @@ char *v4l2_norm_to_name(v4l2_std_id id)
*/
BUG_ON(myid != id);
- switch (myid) {
- case V4L2_STD_PAL:
- name = "PAL";
- break;
- case V4L2_STD_PAL_BG:
- name = "PAL-BG";
- break;
- case V4L2_STD_PAL_DK:
- name = "PAL-DK";
- break;
- case V4L2_STD_PAL_B:
- name = "PAL-B";
- break;
- case V4L2_STD_PAL_B1:
- name = "PAL-B1";
- break;
- case V4L2_STD_PAL_G:
- name = "PAL-G";
- break;
- case V4L2_STD_PAL_H:
- name = "PAL-H";
- break;
- case V4L2_STD_PAL_I:
- name = "PAL-I";
- break;
- case V4L2_STD_PAL_D:
- name = "PAL-D";
- break;
- case V4L2_STD_PAL_D1:
- name = "PAL-D1";
- break;
- case V4L2_STD_PAL_K:
- name = "PAL-K";
- break;
- case V4L2_STD_PAL_M:
- name = "PAL-M";
- break;
- case V4L2_STD_PAL_N:
- name = "PAL-N";
- break;
- case V4L2_STD_PAL_Nc:
- name = "PAL-Nc";
- break;
- case V4L2_STD_PAL_60:
- name = "PAL-60";
- break;
- case V4L2_STD_NTSC:
- name = "NTSC";
- break;
- case V4L2_STD_NTSC_M:
- name = "NTSC-M";
- break;
- case V4L2_STD_NTSC_M_JP:
- name = "NTSC-M-JP";
- break;
- case V4L2_STD_NTSC_443:
- name = "NTSC-443";
- break;
- case V4L2_STD_NTSC_M_KR:
- name = "NTSC-M-KR";
- break;
- case V4L2_STD_SECAM:
- name = "SECAM";
- break;
- case V4L2_STD_SECAM_DK:
- name = "SECAM-DK";
- break;
- case V4L2_STD_SECAM_B:
- name = "SECAM-B";
- break;
- case V4L2_STD_SECAM_D:
- name = "SECAM-D";
- break;
- case V4L2_STD_SECAM_G:
- name = "SECAM-G";
- break;
- case V4L2_STD_SECAM_H:
- name = "SECAM-H";
- break;
- case V4L2_STD_SECAM_K:
- name = "SECAM-K";
- break;
- case V4L2_STD_SECAM_K1:
- name = "SECAM-K1";
- break;
- case V4L2_STD_SECAM_L:
- name = "SECAM-L";
- break;
- case V4L2_STD_SECAM_LC:
- name = "SECAM-LC";
- break;
- default:
- name = "Unknown";
- break;
- }
-
- return name;
+ for (i = 0; standards[i].std; i++)
+ if (myid == standards[i].std)
+ break;
+ return standards[i].descr;
}
EXPORT_SYMBOL(v4l2_norm_to_name);
/* Fill in the fields of a v4l2_standard structure according to the
'id' and 'transmission' parameters. Returns negative on error. */
int v4l2_video_std_construct(struct v4l2_standard *vs,
- int id, char *name)
+ int id, const char *name)
{
u32 index = vs->index;
@@ -1222,95 +1168,40 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_ENUMSTD:
{
struct v4l2_standard *p = arg;
- v4l2_std_id id = vfd->tvnorms,curr_id=0;
- unsigned int index = p->index,i;
-
- if (index<0) {
- ret=-EINVAL;
- break;
- }
-
- /* Return norm array on a canonical way */
- for (i=0;i<= index && id; i++) {
- if ( (id & V4L2_STD_PAL) == V4L2_STD_PAL) {
- curr_id = V4L2_STD_PAL;
- } else if ( (id & V4L2_STD_PAL_BG) == V4L2_STD_PAL_BG) {
- curr_id = V4L2_STD_PAL_BG;
- } else if ( (id & V4L2_STD_PAL_DK) == V4L2_STD_PAL_DK) {
- curr_id = V4L2_STD_PAL_DK;
- } else if ( (id & V4L2_STD_PAL_B) == V4L2_STD_PAL_B) {
- curr_id = V4L2_STD_PAL_B;
- } else if ( (id & V4L2_STD_PAL_B1) == V4L2_STD_PAL_B1) {
- curr_id = V4L2_STD_PAL_B1;
- } else if ( (id & V4L2_STD_PAL_G) == V4L2_STD_PAL_G) {
- curr_id = V4L2_STD_PAL_G;
- } else if ( (id & V4L2_STD_PAL_H) == V4L2_STD_PAL_H) {
- curr_id = V4L2_STD_PAL_H;
- } else if ( (id & V4L2_STD_PAL_I) == V4L2_STD_PAL_I) {
- curr_id = V4L2_STD_PAL_I;
- } else if ( (id & V4L2_STD_PAL_D) == V4L2_STD_PAL_D) {
- curr_id = V4L2_STD_PAL_D;
- } else if ( (id & V4L2_STD_PAL_D1) == V4L2_STD_PAL_D1) {
- curr_id = V4L2_STD_PAL_D1;
- } else if ( (id & V4L2_STD_PAL_K) == V4L2_STD_PAL_K) {
- curr_id = V4L2_STD_PAL_K;
- } else if ( (id & V4L2_STD_PAL_M) == V4L2_STD_PAL_M) {
- curr_id = V4L2_STD_PAL_M;
- } else if ( (id & V4L2_STD_PAL_N) == V4L2_STD_PAL_N) {
- curr_id = V4L2_STD_PAL_N;
- } else if ( (id & V4L2_STD_PAL_Nc) == V4L2_STD_PAL_Nc) {
- curr_id = V4L2_STD_PAL_Nc;
- } else if ( (id & V4L2_STD_PAL_60) == V4L2_STD_PAL_60) {
- curr_id = V4L2_STD_PAL_60;
- } else if ( (id & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
- curr_id = V4L2_STD_NTSC;
- } else if ( (id & V4L2_STD_NTSC_M) == V4L2_STD_NTSC_M) {
- curr_id = V4L2_STD_NTSC_M;
- } else if ( (id & V4L2_STD_NTSC_M_JP) == V4L2_STD_NTSC_M_JP) {
- curr_id = V4L2_STD_NTSC_M_JP;
- } else if ( (id & V4L2_STD_NTSC_443) == V4L2_STD_NTSC_443) {
- curr_id = V4L2_STD_NTSC_443;
- } else if ( (id & V4L2_STD_NTSC_M_KR) == V4L2_STD_NTSC_M_KR) {
- curr_id = V4L2_STD_NTSC_M_KR;
- } else if ( (id & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
- curr_id = V4L2_STD_SECAM;
- } else if ( (id & V4L2_STD_SECAM_DK) == V4L2_STD_SECAM_DK) {
- curr_id = V4L2_STD_SECAM_DK;
- } else if ( (id & V4L2_STD_SECAM_B) == V4L2_STD_SECAM_B) {
- curr_id = V4L2_STD_SECAM_B;
- } else if ( (id & V4L2_STD_SECAM_D) == V4L2_STD_SECAM_D) {
- curr_id = V4L2_STD_SECAM_D;
- } else if ( (id & V4L2_STD_SECAM_G) == V4L2_STD_SECAM_G) {
- curr_id = V4L2_STD_SECAM_G;
- } else if ( (id & V4L2_STD_SECAM_H) == V4L2_STD_SECAM_H) {
- curr_id = V4L2_STD_SECAM_H;
- } else if ( (id & V4L2_STD_SECAM_K) == V4L2_STD_SECAM_K) {
- curr_id = V4L2_STD_SECAM_K;
- } else if ( (id & V4L2_STD_SECAM_K1) == V4L2_STD_SECAM_K1) {
- curr_id = V4L2_STD_SECAM_K1;
- } else if ( (id & V4L2_STD_SECAM_L) == V4L2_STD_SECAM_L) {
- curr_id = V4L2_STD_SECAM_L;
- } else if ( (id & V4L2_STD_SECAM_LC) == V4L2_STD_SECAM_LC) {
- curr_id = V4L2_STD_SECAM_LC;
- } else {
+ v4l2_std_id id = vfd->tvnorms, curr_id = 0;
+ unsigned int index = p->index, i, j = 0;
+ const char *descr = "";
+
+ /* Return norm array in a canonical way */
+ for (i = 0; i <= index && id; i++) {
+ /* last std value in the standards array is 0, so this
+ while always ends there since (id & 0) == 0. */
+ while ((id & standards[j].std) != standards[j].std)
+ j++;
+ curr_id = standards[j].std;
+ descr = standards[j].descr;
+ j++;
+ if (curr_id == 0)
break;
- }
- id &= ~curr_id;
+ if (curr_id != V4L2_STD_PAL &&
+ curr_id != V4L2_STD_SECAM &&
+ curr_id != V4L2_STD_NTSC)
+ id &= ~curr_id;
}
- if (i<=index)
+ if (i <= index)
return -EINVAL;
- v4l2_video_std_construct(p, curr_id,v4l2_norm_to_name(curr_id));
+ v4l2_video_std_construct(p, curr_id, descr);
p->index = index;
- dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
+ dbgarg(cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
"framelines=%d\n", p->index,
(unsigned long long)p->id, p->name,
p->frameperiod.numerator,
p->frameperiod.denominator,
p->framelines);
- ret=0;
+ ret = 0;
break;
}
case VIDIOC_G_STD:
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 845be1864f68..5ff9a58b6135 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -327,13 +327,14 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
int hmax = buf->vb.height;
int wmax = buf->vb.width;
struct timeval ts;
- char *tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
+ char *tmpbuf;
void *vbuf = videobuf_to_vmalloc(&buf->vb);
- if (!tmpbuf)
+ if (!vbuf)
return;
- if (!vbuf)
+ tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
+ if (!tmpbuf)
return;
for (h = 0; h < hmax; h++) {
diff --git a/drivers/media/video/zoran.h b/drivers/media/video/zoran.h
index 81cc3b00a079..46b7ad477ceb 100644
--- a/drivers/media/video/zoran.h
+++ b/drivers/media/video/zoran.h
@@ -285,7 +285,7 @@ struct zoran_mapping {
struct zoran_jpg_buffer {
struct zoran_mapping *map;
- u32 *frag_tab; /* addresses of frag table */
+ __le32 *frag_tab; /* addresses of frag table */
u32 frag_tab_bus; /* same value cached to save time in ISR */
enum zoran_buffer_state state; /* non-zero if corresponding buffer is in use in grab queue */
struct zoran_sync bs; /* DONE: info to return to application */
@@ -450,7 +450,7 @@ struct zoran {
unsigned long jpg_queued_num; /* count of frames queued since grab/play started */
/* zr36057's code buffer table */
- u32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */
+ __le32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */
/* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */
int jpg_pend[BUZ_MAX_FRAME];
diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
index 37629ffd34c3..88d369708e4c 100644
--- a/drivers/media/video/zoran_device.c
+++ b/drivers/media/video/zoran_device.c
@@ -1320,7 +1320,7 @@ error_handler (struct zoran *zr,
if (i) {
/* Rotate stat_comm entries to make current entry first */
int j;
- u32 bus_addr[BUZ_NUM_STAT_COM];
+ __le32 bus_addr[BUZ_NUM_STAT_COM];
/* Here we are copying the stat_com array, which
* is already in little endian format, so
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index 345c77e46837..5394d7a5cfee 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -495,7 +495,7 @@ jpg_fbuffer_alloc (struct file *file)
jpg_fbuffer_free(file);
return -ENOBUFS;
}
- fh->jpg_buffers.buffer[i].frag_tab = (u32 *) mem;
+ fh->jpg_buffers.buffer[i].frag_tab = (__le32 *) mem;
fh->jpg_buffers.buffer[i].frag_tab_bus =
virt_to_bus((void *) mem);
@@ -1167,7 +1167,7 @@ zoran_close_end_session (struct file *file)
/* v4l capture */
if (fh->v4l_buffers.active != ZORAN_FREE) {
- long flags;
+ unsigned long flags;
spin_lock_irqsave(&zr->spinlock, flags);
zr36057_set_memgrab(zr, 0);
@@ -3436,7 +3436,7 @@ zoran_do_ioctl (struct inode *inode,
/* unload capture */
if (zr->v4l_memgrab_active) {
- long flags;
+ unsigned long flags;
spin_lock_irqsave(&zr->spinlock, flags);
zr36057_set_memgrab(zr, 0);
@@ -4375,7 +4375,7 @@ zoran_vm_close (struct vm_area_struct *vma)
mutex_lock(&zr->resource_lock);
if (fh->v4l_buffers.active != ZORAN_FREE) {
- long flags;
+ unsigned long flags;
spin_lock_irqsave(&zr->spinlock, flags);
zr36057_set_memgrab(zr, 0);
@@ -4506,7 +4506,7 @@ zoran_mmap (struct file *file,
if (todo > fraglen)
todo = fraglen;
pos =
- le32_to_cpu((unsigned long) fh->jpg_buffers.
+ le32_to_cpu(fh->jpg_buffers.
buffer[i].frag_tab[2 * j]);
/* should just be pos on i386 */
page = virt_to_phys(bus_to_virt(pos))
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index db3c892f87fb..d40d6d15ae20 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -1686,9 +1686,14 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->bus_type = SAS;
}
- if (ioc->bus_type == SAS && mpt_msi_enable == -1)
- ioc->msi_enable = 1;
- else
+ if (mpt_msi_enable == -1) {
+ /* Enable on SAS, disable on FC and SPI */
+ if (ioc->bus_type == SAS)
+ ioc->msi_enable = 1;
+ else
+ ioc->msi_enable = 0;
+ } else
+ /* follow flag: 0 - disable; 1 - enable */
ioc->msi_enable = mpt_msi_enable;
if (ioc->errata_flag_1064)
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index 3cdd4e962115..1e24ab4ac38c 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -1238,8 +1238,6 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sh->max_id = ioc->pfacts->MaxDevices;
sh->max_lun = max_lun;
- sh->this_id = ioc->pfacts[0].PortSCSIID;
-
/* Required entry.
*/
sh->unique_id = ioc->id;
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index 468480771f13..4d492ba232b0 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -3193,8 +3193,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sh->transportt = mptsas_transport_template;
- sh->this_id = ioc->pfacts[0].PortSCSIID;
-
/* Required entry.
*/
sh->unique_id = ioc->id;
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index b109bd8a4d19..c68ef00c2f92 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -2451,12 +2451,6 @@ mptscsih_slave_configure(struct scsi_device *sdev)
ioc->name, sdev->sdtr, sdev->wdtr,
sdev->ppr, sdev->inquiry_len));
- if (sdev->id > sh->max_id) {
- /* error case, should never happen */
- scsi_adjust_queue_depth(sdev, 0, 1);
- goto slave_configure_exit;
- }
-
vdevice->configured_lun = 1;
mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
@@ -2470,8 +2464,6 @@ mptscsih_slave_configure(struct scsi_device *sdev)
ioc->name, vtarget->negoFlags, vtarget->maxOffset,
vtarget->minSyncFactor));
-slave_configure_exit:
-
dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"tagged %d, simple %d, ordered %d\n",
ioc->name,sdev->tagged_supported, sdev->simple_tags,
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 25bcfcf36f2e..1effca4e40e1 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -1266,13 +1266,18 @@ mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd)
static int
mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
{
- struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
int rc;
rc = mptscsih_ioc_reset(ioc, reset_phase);
- if (reset_phase == MPT_IOC_POST_RESET)
+ /* only try to do a renegotiation if we're properly set up
+ * if we get an ioc fault on bringup, ioc->sh will be NULL */
+ if (reset_phase == MPT_IOC_POST_RESET &&
+ ioc->sh) {
+ struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
+
mptspi_dv_renegotiate(hd);
+ }
return rc;
}
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 2566479937c9..ae96bd6242f2 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -24,7 +24,7 @@ config MFD_ASIC3
config HTC_EGPIO
bool "HTC EGPIO support"
- depends on GENERIC_HARDIRQS && HAVE_GPIO_LIB
+ depends on GENERIC_HARDIRQS && HAVE_GPIO_LIB && ARM
help
This driver supports the CPLD egpio chip present on
several HTC phones. It provides basic support for input
diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c
index e2e7c05a147b..6d14e8fe1537 100644
--- a/drivers/misc/fujitsu-laptop.c
+++ b/drivers/misc/fujitsu-laptop.c
@@ -352,3 +352,9 @@ MODULE_AUTHOR("Jonathan Woithe");
MODULE_DESCRIPTION("Fujitsu laptop extras support");
MODULE_VERSION(FUJITSU_DRIVER_VERSION);
MODULE_LICENSE("GPL");
+
+static struct pnp_device_id pnp_ids[] = {
+ { .id = "FUJ02bf" },
+ { .id = "" }
+};
+MODULE_DEVICE_TABLE(pnp, pnp_ids);
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c
index fa394104339c..e4ff50b95a5e 100644
--- a/drivers/misc/kgdbts.c
+++ b/drivers/misc/kgdbts.c
@@ -102,7 +102,6 @@
#include <linux/nmi.h>
#include <linux/delay.h>
#include <linux/kthread.h>
-#include <linux/delay.h>
#define v1printk(a...) do { \
if (verbose) \
@@ -119,7 +118,6 @@
} while (0)
#define MAX_CONFIG_LEN 40
-static const char hexchars[] = "0123456789abcdef";
static struct kgdb_io kgdbts_io_ops;
static char get_buf[BUFMAX];
static int get_buf_cnt;
@@ -131,6 +129,8 @@ static int repeat_test;
static int test_complete;
static int send_ack;
static int final_ack;
+static int force_hwbrks;
+static int hwbreaks_ok;
static int hw_break_val;
static int hw_break_val2;
#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_SPARC)
@@ -234,12 +234,12 @@ static void break_helper(char *bp_type, char *arg, unsigned long vaddr)
static void sw_break(char *arg)
{
- break_helper("Z0", arg, 0);
+ break_helper(force_hwbrks ? "Z1" : "Z0", arg, 0);
}
static void sw_rem_break(char *arg)
{
- break_helper("z0", arg, 0);
+ break_helper(force_hwbrks ? "z1" : "z0", arg, 0);
}
static void hw_break(char *arg)
@@ -619,8 +619,8 @@ static void fill_get_buf(char *buf)
count++;
}
strcat(get_buf, "#");
- get_buf[count + 2] = hexchars[checksum >> 4];
- get_buf[count + 3] = hexchars[checksum & 0xf];
+ get_buf[count + 2] = hex_asc_hi(checksum);
+ get_buf[count + 3] = hex_asc_lo(checksum);
get_buf[count + 4] = '\0';
v2printk("get%i: %s\n", ts.idx, get_buf);
}
@@ -781,6 +781,8 @@ static void run_breakpoint_test(int is_hw_breakpoint)
return;
eprintk("kgdbts: ERROR %s test failed\n", ts.name);
+ if (is_hw_breakpoint)
+ hwbreaks_ok = 0;
}
static void run_hw_break_test(int is_write_test)
@@ -798,9 +800,11 @@ static void run_hw_break_test(int is_write_test)
kgdb_breakpoint();
hw_break_val_access();
if (is_write_test) {
- if (test_complete == 2)
+ if (test_complete == 2) {
eprintk("kgdbts: ERROR %s broke on access\n",
ts.name);
+ hwbreaks_ok = 0;
+ }
hw_break_val_write();
}
kgdb_breakpoint();
@@ -809,6 +813,7 @@ static void run_hw_break_test(int is_write_test)
return;
eprintk("kgdbts: ERROR %s test failed\n", ts.name);
+ hwbreaks_ok = 0;
}
static void run_nmi_sleep_test(int nmi_sleep)
@@ -912,6 +917,7 @@ static void kgdbts_run_tests(void)
/* All HW break point tests */
if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT) {
+ hwbreaks_ok = 1;
v1printk("kgdbts:RUN hw breakpoint test\n");
run_breakpoint_test(1);
v1printk("kgdbts:RUN hw write breakpoint test\n");
@@ -925,6 +931,19 @@ static void kgdbts_run_tests(void)
run_nmi_sleep_test(nmi_sleep);
}
+#ifdef CONFIG_DEBUG_RODATA
+ /* Until there is an api to write to read-only text segments, use
+ * HW breakpoints for the remainder of any tests, else print a
+ * failure message if hw breakpoints do not work.
+ */
+ if (!(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT && hwbreaks_ok)) {
+ eprintk("kgdbts: HW breakpoints do not work,"
+ "skipping remaining tests\n");
+ return;
+ }
+ force_hwbrks = 1;
+#endif /* CONFIG_DEBUG_RODATA */
+
/* If the do_fork test is run it will be the last test that is
* executed because a kernel thread will be spawned at the very
* end to unregister the debug hooks.
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 3f28f6eabdbf..b5969298f3d3 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -1293,7 +1293,7 @@ static void tpacpi_input_send_radiosw(void)
mutex_lock(&tpacpi_inputdev_send_mutex);
input_report_switch(tpacpi_inputdev,
- SW_RADIO, !!wlsw);
+ SW_RFKILL_ALL, !!wlsw);
input_sync(tpacpi_inputdev);
mutex_unlock(&tpacpi_inputdev_send_mutex);
@@ -1921,6 +1921,29 @@ static struct attribute *hotkey_mask_attributes[] __initdata = {
&dev_attr_hotkey_wakeup_hotunplug_complete.attr,
};
+static void hotkey_exit(void)
+{
+#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
+ hotkey_poll_stop_sync();
+#endif
+
+ if (hotkey_dev_attributes)
+ delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
+
+ kfree(hotkey_keycode_map);
+
+ if (tp_features.hotkey) {
+ dbg_printk(TPACPI_DBG_EXIT,
+ "restoring original hot key mask\n");
+ /* no short-circuit boolean operator below! */
+ if ((hotkey_mask_set(hotkey_orig_mask) |
+ hotkey_status_set(hotkey_orig_status)) != 0)
+ printk(TPACPI_ERR
+ "failed to restore hot key mask "
+ "to BIOS defaults\n");
+ }
+}
+
static int __init hotkey_init(struct ibm_init_struct *iibm)
{
/* Requirements for changing the default keymaps:
@@ -2060,226 +2083,220 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n",
str_supported(tp_features.hotkey));
- if (tp_features.hotkey) {
- hotkey_dev_attributes = create_attr_set(13, NULL);
- if (!hotkey_dev_attributes)
- return -ENOMEM;
- res = add_many_to_attr_set(hotkey_dev_attributes,
- hotkey_attributes,
- ARRAY_SIZE(hotkey_attributes));
- if (res)
- return res;
+ if (!tp_features.hotkey)
+ return 1;
- /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
- A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking
- for HKEY interface version 0x100 */
- if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
- if ((hkeyv >> 8) != 1) {
- printk(TPACPI_ERR "unknown version of the "
- "HKEY interface: 0x%x\n", hkeyv);
- printk(TPACPI_ERR "please report this to %s\n",
- TPACPI_MAIL);
- } else {
- /*
- * MHKV 0x100 in A31, R40, R40e,
- * T4x, X31, and later
- */
- tp_features.hotkey_mask = 1;
- }
+ hotkey_dev_attributes = create_attr_set(13, NULL);
+ if (!hotkey_dev_attributes)
+ return -ENOMEM;
+ res = add_many_to_attr_set(hotkey_dev_attributes,
+ hotkey_attributes,
+ ARRAY_SIZE(hotkey_attributes));
+ if (res)
+ goto err_exit;
+
+ /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
+ A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking
+ for HKEY interface version 0x100 */
+ if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
+ if ((hkeyv >> 8) != 1) {
+ printk(TPACPI_ERR "unknown version of the "
+ "HKEY interface: 0x%x\n", hkeyv);
+ printk(TPACPI_ERR "please report this to %s\n",
+ TPACPI_MAIL);
+ } else {
+ /*
+ * MHKV 0x100 in A31, R40, R40e,
+ * T4x, X31, and later
+ */
+ tp_features.hotkey_mask = 1;
}
+ }
- vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
- str_supported(tp_features.hotkey_mask));
+ vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
+ str_supported(tp_features.hotkey_mask));
- if (tp_features.hotkey_mask) {
- if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
- "MHKA", "qd")) {
- printk(TPACPI_ERR
- "missing MHKA handler, "
- "please report this to %s\n",
- TPACPI_MAIL);
- /* FN+F12, FN+F4, FN+F3 */
- hotkey_all_mask = 0x080cU;
- }
+ if (tp_features.hotkey_mask) {
+ if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
+ "MHKA", "qd")) {
+ printk(TPACPI_ERR
+ "missing MHKA handler, "
+ "please report this to %s\n",
+ TPACPI_MAIL);
+ /* FN+F12, FN+F4, FN+F3 */
+ hotkey_all_mask = 0x080cU;
}
+ }
- /* hotkey_source_mask *must* be zero for
- * the first hotkey_mask_get */
- res = hotkey_status_get(&hotkey_orig_status);
- if (!res && tp_features.hotkey_mask) {
- res = hotkey_mask_get();
- hotkey_orig_mask = hotkey_mask;
- if (!res) {
- res = add_many_to_attr_set(
- hotkey_dev_attributes,
- hotkey_mask_attributes,
- ARRAY_SIZE(hotkey_mask_attributes));
- }
- }
+ /* hotkey_source_mask *must* be zero for
+ * the first hotkey_mask_get */
+ res = hotkey_status_get(&hotkey_orig_status);
+ if (res)
+ goto err_exit;
+
+ if (tp_features.hotkey_mask) {
+ res = hotkey_mask_get();
+ if (res)
+ goto err_exit;
+
+ hotkey_orig_mask = hotkey_mask;
+ res = add_many_to_attr_set(
+ hotkey_dev_attributes,
+ hotkey_mask_attributes,
+ ARRAY_SIZE(hotkey_mask_attributes));
+ if (res)
+ goto err_exit;
+ }
#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
- if (tp_features.hotkey_mask) {
- hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK
- & ~hotkey_all_mask;
- } else {
- hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK;
- }
+ if (tp_features.hotkey_mask) {
+ hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK
+ & ~hotkey_all_mask;
+ } else {
+ hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK;
+ }
- vdbg_printk(TPACPI_DBG_INIT,
- "hotkey source mask 0x%08x, polling freq %d\n",
- hotkey_source_mask, hotkey_poll_freq);
+ vdbg_printk(TPACPI_DBG_INIT,
+ "hotkey source mask 0x%08x, polling freq %d\n",
+ hotkey_source_mask, hotkey_poll_freq);
#endif
- /* Not all thinkpads have a hardware radio switch */
- if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
- tp_features.hotkey_wlsw = 1;
- printk(TPACPI_INFO
- "radio switch found; radios are %s\n",
- enabled(status, 0));
- res = add_to_attr_set(hotkey_dev_attributes,
- &dev_attr_hotkey_radio_sw.attr);
- }
+ /* Not all thinkpads have a hardware radio switch */
+ if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
+ tp_features.hotkey_wlsw = 1;
+ printk(TPACPI_INFO
+ "radio switch found; radios are %s\n",
+ enabled(status, 0));
+ res = add_to_attr_set(hotkey_dev_attributes,
+ &dev_attr_hotkey_radio_sw.attr);
+ }
- /* For X41t, X60t, X61t Tablets... */
- if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) {
- tp_features.hotkey_tablet = 1;
- printk(TPACPI_INFO
- "possible tablet mode switch found; "
- "ThinkPad in %s mode\n",
- (status & TP_HOTKEY_TABLET_MASK)?
- "tablet" : "laptop");
- res = add_to_attr_set(hotkey_dev_attributes,
- &dev_attr_hotkey_tablet_mode.attr);
- }
+ /* For X41t, X60t, X61t Tablets... */
+ if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) {
+ tp_features.hotkey_tablet = 1;
+ printk(TPACPI_INFO
+ "possible tablet mode switch found; "
+ "ThinkPad in %s mode\n",
+ (status & TP_HOTKEY_TABLET_MASK)?
+ "tablet" : "laptop");
+ res = add_to_attr_set(hotkey_dev_attributes,
+ &dev_attr_hotkey_tablet_mode.attr);
+ }
- if (!res)
- res = register_attr_set_with_sysfs(
- hotkey_dev_attributes,
- &tpacpi_pdev->dev.kobj);
- if (res)
- return res;
+ if (!res)
+ res = register_attr_set_with_sysfs(
+ hotkey_dev_attributes,
+ &tpacpi_pdev->dev.kobj);
+ if (res)
+ goto err_exit;
- /* Set up key map */
+ /* Set up key map */
- hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
- GFP_KERNEL);
- if (!hotkey_keycode_map) {
- printk(TPACPI_ERR
- "failed to allocate memory for key map\n");
- return -ENOMEM;
- }
+ hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
+ GFP_KERNEL);
+ if (!hotkey_keycode_map) {
+ printk(TPACPI_ERR
+ "failed to allocate memory for key map\n");
+ res = -ENOMEM;
+ goto err_exit;
+ }
- if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
- dbg_printk(TPACPI_DBG_INIT,
- "using Lenovo default hot key map\n");
- memcpy(hotkey_keycode_map, &lenovo_keycode_map,
- TPACPI_HOTKEY_MAP_SIZE);
+ if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
+ dbg_printk(TPACPI_DBG_INIT,
+ "using Lenovo default hot key map\n");
+ memcpy(hotkey_keycode_map, &lenovo_keycode_map,
+ TPACPI_HOTKEY_MAP_SIZE);
+ } else {
+ dbg_printk(TPACPI_DBG_INIT,
+ "using IBM default hot key map\n");
+ memcpy(hotkey_keycode_map, &ibm_keycode_map,
+ TPACPI_HOTKEY_MAP_SIZE);
+ }
+
+ set_bit(EV_KEY, tpacpi_inputdev->evbit);
+ set_bit(EV_MSC, tpacpi_inputdev->evbit);
+ set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
+ tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;
+ tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN;
+ tpacpi_inputdev->keycode = hotkey_keycode_map;
+ for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) {
+ if (hotkey_keycode_map[i] != KEY_RESERVED) {
+ set_bit(hotkey_keycode_map[i],
+ tpacpi_inputdev->keybit);
} else {
- dbg_printk(TPACPI_DBG_INIT,
- "using IBM default hot key map\n");
- memcpy(hotkey_keycode_map, &ibm_keycode_map,
- TPACPI_HOTKEY_MAP_SIZE);
- }
-
- set_bit(EV_KEY, tpacpi_inputdev->evbit);
- set_bit(EV_MSC, tpacpi_inputdev->evbit);
- set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
- tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;
- tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN;
- tpacpi_inputdev->keycode = hotkey_keycode_map;
- for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) {
- if (hotkey_keycode_map[i] != KEY_RESERVED) {
- set_bit(hotkey_keycode_map[i],
- tpacpi_inputdev->keybit);
- } else {
- if (i < sizeof(hotkey_reserved_mask)*8)
- hotkey_reserved_mask |= 1 << i;
- }
- }
-
- if (tp_features.hotkey_wlsw) {
- set_bit(EV_SW, tpacpi_inputdev->evbit);
- set_bit(SW_RADIO, tpacpi_inputdev->swbit);
- }
- if (tp_features.hotkey_tablet) {
- set_bit(EV_SW, tpacpi_inputdev->evbit);
- set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit);
+ if (i < sizeof(hotkey_reserved_mask)*8)
+ hotkey_reserved_mask |= 1 << i;
}
+ }
- /* Do not issue duplicate brightness change events to
- * userspace */
- if (!tp_features.bright_acpimode)
- /* update bright_acpimode... */
- tpacpi_check_std_acpi_brightness_support();
-
- if (tp_features.bright_acpimode) {
- printk(TPACPI_INFO
- "This ThinkPad has standard ACPI backlight "
- "brightness control, supported by the ACPI "
- "video driver\n");
- printk(TPACPI_NOTICE
- "Disabling thinkpad-acpi brightness events "
- "by default...\n");
-
- /* The hotkey_reserved_mask change below is not
- * necessary while the keys are at KEY_RESERVED in the
- * default map, but better safe than sorry, leave it
- * here as a marker of what we have to do, especially
- * when we finally become able to set this at runtime
- * on response to X.org requests */
- hotkey_reserved_mask |=
- (1 << TP_ACPI_HOTKEYSCAN_FNHOME)
- | (1 << TP_ACPI_HOTKEYSCAN_FNEND);
- }
+ if (tp_features.hotkey_wlsw) {
+ set_bit(EV_SW, tpacpi_inputdev->evbit);
+ set_bit(SW_RFKILL_ALL, tpacpi_inputdev->swbit);
+ }
+ if (tp_features.hotkey_tablet) {
+ set_bit(EV_SW, tpacpi_inputdev->evbit);
+ set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit);
+ }
- dbg_printk(TPACPI_DBG_INIT,
- "enabling hot key handling\n");
- res = hotkey_status_set(1);
- if (res)
- return res;
- res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask)
- & ~hotkey_reserved_mask)
- | hotkey_orig_mask);
- if (res < 0 && res != -ENXIO)
- return res;
+ /* Do not issue duplicate brightness change events to
+ * userspace */
+ if (!tp_features.bright_acpimode)
+ /* update bright_acpimode... */
+ tpacpi_check_std_acpi_brightness_support();
- dbg_printk(TPACPI_DBG_INIT,
- "legacy hot key reporting over procfs %s\n",
- (hotkey_report_mode < 2) ?
- "enabled" : "disabled");
+ if (tp_features.bright_acpimode) {
+ printk(TPACPI_INFO
+ "This ThinkPad has standard ACPI backlight "
+ "brightness control, supported by the ACPI "
+ "video driver\n");
+ printk(TPACPI_NOTICE
+ "Disabling thinkpad-acpi brightness events "
+ "by default...\n");
+
+ /* The hotkey_reserved_mask change below is not
+ * necessary while the keys are at KEY_RESERVED in the
+ * default map, but better safe than sorry, leave it
+ * here as a marker of what we have to do, especially
+ * when we finally become able to set this at runtime
+ * on response to X.org requests */
+ hotkey_reserved_mask |=
+ (1 << TP_ACPI_HOTKEYSCAN_FNHOME)
+ | (1 << TP_ACPI_HOTKEYSCAN_FNEND);
+ }
+
+ dbg_printk(TPACPI_DBG_INIT, "enabling hot key handling\n");
+ res = hotkey_status_set(1);
+ if (res) {
+ hotkey_exit();
+ return res;
+ }
+ res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask)
+ & ~hotkey_reserved_mask)
+ | hotkey_orig_mask);
+ if (res < 0 && res != -ENXIO) {
+ hotkey_exit();
+ return res;
+ }
- tpacpi_inputdev->open = &hotkey_inputdev_open;
- tpacpi_inputdev->close = &hotkey_inputdev_close;
+ dbg_printk(TPACPI_DBG_INIT,
+ "legacy hot key reporting over procfs %s\n",
+ (hotkey_report_mode < 2) ?
+ "enabled" : "disabled");
- hotkey_poll_setup_safe(1);
- tpacpi_input_send_radiosw();
- tpacpi_input_send_tabletsw();
- }
+ tpacpi_inputdev->open = &hotkey_inputdev_open;
+ tpacpi_inputdev->close = &hotkey_inputdev_close;
- return (tp_features.hotkey)? 0 : 1;
-}
+ hotkey_poll_setup_safe(1);
+ tpacpi_input_send_radiosw();
+ tpacpi_input_send_tabletsw();
-static void hotkey_exit(void)
-{
-#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
- hotkey_poll_stop_sync();
-#endif
+ return 0;
- if (tp_features.hotkey) {
- dbg_printk(TPACPI_DBG_EXIT,
- "restoring original hot key mask\n");
- /* no short-circuit boolean operator below! */
- if ((hotkey_mask_set(hotkey_orig_mask) |
- hotkey_status_set(hotkey_orig_status)) != 0)
- printk(TPACPI_ERR
- "failed to restore hot key mask "
- "to BIOS defaults\n");
- }
+err_exit:
+ delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
+ hotkey_dev_attributes = NULL;
- if (hotkey_dev_attributes) {
- delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
- hotkey_dev_attributes = NULL;
- }
+ return (res < 0)? res : 1;
}
static void hotkey_notify(struct ibm_struct *ibm, u32 event)
@@ -3319,7 +3336,7 @@ static struct tpacpi_led_classdev tpacpi_led_thinklight = {
static int __init light_init(struct ibm_init_struct *iibm)
{
- int rc = 0;
+ int rc;
vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
@@ -3337,20 +3354,23 @@ static int __init light_init(struct ibm_init_struct *iibm)
tp_features.light_status =
acpi_evalf(ec_handle, NULL, "KBLT", "qv");
- vdbg_printk(TPACPI_DBG_INIT, "light is %s\n",
- str_supported(tp_features.light));
+ vdbg_printk(TPACPI_DBG_INIT, "light is %s, light status is %s\n",
+ str_supported(tp_features.light),
+ str_supported(tp_features.light_status));
- if (tp_features.light) {
- rc = led_classdev_register(&tpacpi_pdev->dev,
- &tpacpi_led_thinklight.led_classdev);
- }
+ if (!tp_features.light)
+ return 1;
+
+ rc = led_classdev_register(&tpacpi_pdev->dev,
+ &tpacpi_led_thinklight.led_classdev);
if (rc < 0) {
tp_features.light = 0;
tp_features.light_status = 0;
- } else {
- rc = (tp_features.light)? 0 : 1;
+ } else {
+ rc = 0;
}
+
return rc;
}
@@ -3821,7 +3841,7 @@ TPACPI_HANDLE(led, ec, "SLED", /* 570 */
#define TPACPI_LED_NUMLEDS 8
static struct tpacpi_led_classdev *tpacpi_leds;
static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS];
-static const char const *tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
+static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
/* there's a limit of 19 chars + NULL before 2.6.26 */
"tpacpi::power",
"tpacpi:orange:batt",
@@ -3833,7 +3853,7 @@ static const char const *tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
"tpacpi::standby",
};
-static int led_get_status(unsigned int led)
+static int led_get_status(const unsigned int led)
{
int status;
enum led_status_t led_s;
@@ -3857,41 +3877,42 @@ static int led_get_status(unsigned int led)
/* not reached */
}
-static int led_set_status(unsigned int led, enum led_status_t ledstatus)
+static int led_set_status(const unsigned int led,
+ const enum led_status_t ledstatus)
{
/* off, on, blink. Index is led_status_t */
- static const int const led_sled_arg1[] = { 0, 1, 3 };
- static const int const led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
- static const int const led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
- static const int const led_led_arg1[] = { 0, 0x80, 0xc0 };
+ static const unsigned int led_sled_arg1[] = { 0, 1, 3 };
+ static const unsigned int led_led_arg1[] = { 0, 0x80, 0xc0 };
int rc = 0;
switch (led_supported) {
case TPACPI_LED_570:
- /* 570 */
- led = 1 << led;
- if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
- led, led_sled_arg1[ledstatus]))
- rc = -EIO;
- break;
+ /* 570 */
+ if (led > 7)
+ return -EINVAL;
+ if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+ (1 << led), led_sled_arg1[ledstatus]))
+ rc = -EIO;
+ break;
case TPACPI_LED_OLD:
- /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
- led = 1 << led;
- rc = ec_write(TPACPI_LED_EC_HLMS, led);
- if (rc >= 0)
- rc = ec_write(TPACPI_LED_EC_HLBL,
- led * led_exp_hlbl[ledstatus]);
- if (rc >= 0)
- rc = ec_write(TPACPI_LED_EC_HLCL,
- led * led_exp_hlcl[ledstatus]);
- break;
+ /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
+ if (led > 7)
+ return -EINVAL;
+ rc = ec_write(TPACPI_LED_EC_HLMS, (1 << led));
+ if (rc >= 0)
+ rc = ec_write(TPACPI_LED_EC_HLBL,
+ (ledstatus == TPACPI_LED_BLINK) << led);
+ if (rc >= 0)
+ rc = ec_write(TPACPI_LED_EC_HLCL,
+ (ledstatus != TPACPI_LED_OFF) << led);
+ break;
case TPACPI_LED_NEW:
- /* all others */
- if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
- led, led_led_arg1[ledstatus]))
- rc = -EIO;
- break;
+ /* all others */
+ if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+ led, led_led_arg1[ledstatus]))
+ rc = -EIO;
+ break;
default:
rc = -ENXIO;
}
@@ -3978,7 +3999,6 @@ static void led_exit(void)
}
kfree(tpacpi_leds);
- tpacpi_leds = NULL;
}
static int __init led_init(struct ibm_init_struct *iibm)
@@ -4802,7 +4822,6 @@ static void brightness_exit(void)
vdbg_printk(TPACPI_DBG_EXIT,
"calling backlight_device_unregister()\n");
backlight_device_unregister(ibm_backlight_device);
- ibm_backlight_device = NULL;
}
}
@@ -5764,11 +5783,16 @@ static int __init fan_init(struct ibm_init_struct *iibm)
fan_control_access_mode != TPACPI_FAN_WR_NONE) {
rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
&fan_attr_group);
- if (!(rc < 0))
- rc = driver_create_file(&tpacpi_hwmon_pdriver.driver,
- &driver_attr_fan_watchdog);
if (rc < 0)
return rc;
+
+ rc = driver_create_file(&tpacpi_hwmon_pdriver.driver,
+ &driver_attr_fan_watchdog);
+ if (rc < 0) {
+ sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
+ &fan_attr_group);
+ return rc;
+ }
return 0;
} else
return 1;
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index aa8a4e461942..dd0f398ee2f5 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -39,3 +39,15 @@ config SDIO_UART
SDIO function driver for SDIO cards that implements the UART
class, as well as the GPS class which appears like a UART.
+config MMC_TEST
+ tristate "MMC host test driver"
+ default n
+ help
+ Development driver that performs a series of reads and writes
+ to a memory card in order to expose certain well known bugs
+ in host controllers. The tests are executed by writing to the
+ "test" file in sysfs under each card. Note that whatever is
+ on your card will be overwritten by these tests.
+
+ This driver is only of interest to those developing or
+ testing a host driver. Most people should say N here.
diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile
index fc5a784cfa1a..0d407514f67d 100644
--- a/drivers/mmc/card/Makefile
+++ b/drivers/mmc/card/Makefile
@@ -8,6 +8,7 @@ endif
obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
mmc_block-objs := block.o queue.o
+obj-$(CONFIG_MMC_TEST) += mmc_test.o
obj-$(CONFIG_SDIO_UART) += sdio_uart.o
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 91ded3e82401..f9ad960d7c1a 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -46,7 +46,7 @@
#define MMC_SHIFT 3
#define MMC_NUM_MINORS (256 >> MMC_SHIFT)
-static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))];
+static DECLARE_BITMAP(dev_use, MMC_NUM_MINORS);
/*
* There is one mmc_blk_data per slot.
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
new file mode 100644
index 000000000000..ffadee549a41
--- /dev/null
+++ b/drivers/mmc/card/mmc_test.c
@@ -0,0 +1,892 @@
+/*
+ * linux/drivers/mmc/card/mmc_test.c
+ *
+ * Copyright 2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+
+#include <linux/scatterlist.h>
+
+#define RESULT_OK 0
+#define RESULT_FAIL 1
+#define RESULT_UNSUP_HOST 2
+#define RESULT_UNSUP_CARD 3
+
+#define BUFFER_SIZE (PAGE_SIZE * 4)
+
+struct mmc_test_card {
+ struct mmc_card *card;
+
+ u8 *buffer;
+};
+
+/*******************************************************************/
+/* Helper functions */
+/*******************************************************************/
+
+static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
+{
+ struct mmc_command cmd;
+ int ret;
+
+ cmd.opcode = MMC_SET_BLOCKLEN;
+ cmd.arg = size;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ ret = mmc_wait_for_cmd(test->card->host, &cmd, 0);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int __mmc_test_transfer(struct mmc_test_card *test, int write,
+ unsigned broken_xfer, u8 *buffer, unsigned addr,
+ unsigned blocks, unsigned blksz)
+{
+ int ret, busy;
+
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_command stop;
+ struct mmc_data data;
+
+ struct scatterlist sg;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ if (broken_xfer) {
+ if (blocks > 1) {
+ cmd.opcode = write ?
+ MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK;
+ } else {
+ cmd.opcode = MMC_SEND_STATUS;
+ }
+ } else {
+ if (blocks > 1) {
+ cmd.opcode = write ?
+ MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK;
+ } else {
+ cmd.opcode = write ?
+ MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK;
+ }
+ }
+
+ if (broken_xfer && blocks == 1)
+ cmd.arg = test->card->rca << 16;
+ else
+ cmd.arg = addr;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ memset(&stop, 0, sizeof(struct mmc_command));
+
+ if (!broken_xfer && (blocks > 1)) {
+ stop.opcode = MMC_STOP_TRANSMISSION;
+ stop.arg = 0;
+ stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+
+ mrq.stop = &stop;
+ }
+
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ data.blksz = blksz;
+ data.blocks = blocks;
+ data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ sg_init_one(&sg, buffer, blocks * blksz);
+
+ mmc_set_data_timeout(&data, test->card);
+
+ mmc_wait_for_req(test->card->host, &mrq);
+
+ ret = 0;
+
+ if (broken_xfer) {
+ if (!ret && cmd.error)
+ ret = cmd.error;
+ if (!ret && data.error == 0)
+ ret = RESULT_FAIL;
+ if (!ret && data.error != -ETIMEDOUT)
+ ret = data.error;
+ if (!ret && stop.error)
+ ret = stop.error;
+ if (blocks > 1) {
+ if (!ret && data.bytes_xfered > blksz)
+ ret = RESULT_FAIL;
+ } else {
+ if (!ret && data.bytes_xfered > 0)
+ ret = RESULT_FAIL;
+ }
+ } else {
+ if (!ret && cmd.error)
+ ret = cmd.error;
+ if (!ret && data.error)
+ ret = data.error;
+ if (!ret && stop.error)
+ ret = stop.error;
+ if (!ret && data.bytes_xfered != blocks * blksz)
+ ret = RESULT_FAIL;
+ }
+
+ if (ret == -EINVAL)
+ ret = RESULT_UNSUP_HOST;
+
+ busy = 0;
+ do {
+ int ret2;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SEND_STATUS;
+ cmd.arg = test->card->rca << 16;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+ ret2 = mmc_wait_for_cmd(test->card->host, &cmd, 0);
+ if (ret2)
+ break;
+
+ if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) {
+ busy = 1;
+ printk(KERN_INFO "%s: Warning: Host did not "
+ "wait for busy state to end.\n",
+ mmc_hostname(test->card->host));
+ }
+ } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
+
+ return ret;
+}
+
+static int mmc_test_transfer(struct mmc_test_card *test, int write,
+ u8 *buffer, unsigned addr, unsigned blocks, unsigned blksz)
+{
+ return __mmc_test_transfer(test, write, 0, buffer,
+ addr, blocks, blksz);
+}
+
+static int mmc_test_prepare_verify(struct mmc_test_card *test, int write)
+{
+ int ret, i;
+
+ ret = mmc_test_set_blksize(test, 512);
+ if (ret)
+ return ret;
+
+ if (write)
+ memset(test->buffer, 0xDF, BUFFER_SIZE);
+ else {
+ for (i = 0;i < BUFFER_SIZE;i++)
+ test->buffer[i] = i;
+ }
+
+ for (i = 0;i < BUFFER_SIZE / 512;i++) {
+ ret = mmc_test_transfer(test, 1, test->buffer + i * 512,
+ i * 512, 1, 512);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mmc_test_prepare_verify_write(struct mmc_test_card *test)
+{
+ return mmc_test_prepare_verify(test, 1);
+}
+
+static int mmc_test_prepare_verify_read(struct mmc_test_card *test)
+{
+ return mmc_test_prepare_verify(test, 0);
+}
+
+static int mmc_test_verified_transfer(struct mmc_test_card *test, int write,
+ u8 *buffer, unsigned addr, unsigned blocks, unsigned blksz)
+{
+ int ret, i, sectors;
+
+ /*
+ * It is assumed that the above preparation has been done.
+ */
+
+ memset(test->buffer, 0, BUFFER_SIZE);
+
+ if (write) {
+ for (i = 0;i < blocks * blksz;i++)
+ buffer[i] = i;
+ }
+
+ ret = mmc_test_set_blksize(test, blksz);
+ if (ret)
+ return ret;
+
+ ret = mmc_test_transfer(test, write, buffer, addr, blocks, blksz);
+ if (ret)
+ return ret;
+
+ if (write) {
+ ret = mmc_test_set_blksize(test, 512);
+ if (ret)
+ return ret;
+
+ sectors = (blocks * blksz + 511) / 512;
+ if ((sectors * 512) == (blocks * blksz))
+ sectors++;
+
+ if ((sectors * 512) > BUFFER_SIZE)
+ return -EINVAL;
+
+ memset(test->buffer, 0, sectors * 512);
+
+ for (i = 0;i < sectors;i++) {
+ ret = mmc_test_transfer(test, 0,
+ test->buffer + i * 512,
+ addr + i * 512, 1, 512);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0;i < blocks * blksz;i++) {
+ if (test->buffer[i] != (u8)i)
+ return RESULT_FAIL;
+ }
+
+ for (;i < sectors * 512;i++) {
+ if (test->buffer[i] != 0xDF)
+ return RESULT_FAIL;
+ }
+ } else {
+ for (i = 0;i < blocks * blksz;i++) {
+ if (buffer[i] != (u8)i)
+ return RESULT_FAIL;
+ }
+ }
+
+ return 0;
+}
+
+static int mmc_test_cleanup_verify(struct mmc_test_card *test)
+{
+ int ret, i;
+
+ ret = mmc_test_set_blksize(test, 512);
+ if (ret)
+ return ret;
+
+ memset(test->buffer, 0, BUFFER_SIZE);
+
+ for (i = 0;i < BUFFER_SIZE / 512;i++) {
+ ret = mmc_test_transfer(test, 1, test->buffer + i * 512,
+ i * 512, 1, 512);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*******************************************************************/
+/* Tests */
+/*******************************************************************/
+
+struct mmc_test_case {
+ const char *name;
+
+ int (*prepare)(struct mmc_test_card *);
+ int (*run)(struct mmc_test_card *);
+ int (*cleanup)(struct mmc_test_card *);
+};
+
+static int mmc_test_basic_write(struct mmc_test_card *test)
+{
+ int ret;
+
+ ret = mmc_test_set_blksize(test, 512);
+ if (ret)
+ return ret;
+
+ ret = mmc_test_transfer(test, 1, test->buffer, 0, 1, 512);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int mmc_test_basic_read(struct mmc_test_card *test)
+{
+ int ret;
+
+ ret = mmc_test_set_blksize(test, 512);
+ if (ret)
+ return ret;
+
+ ret = mmc_test_transfer(test, 0, test->buffer, 0, 1, 512);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int mmc_test_verify_write(struct mmc_test_card *test)
+{
+ int ret;
+
+ ret = mmc_test_verified_transfer(test, 1, test->buffer, 0, 1, 512);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int mmc_test_verify_read(struct mmc_test_card *test)
+{
+ int ret;
+
+ ret = mmc_test_verified_transfer(test, 0, test->buffer, 0, 1, 512);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int mmc_test_multi_write(struct mmc_test_card *test)
+{
+ int ret;
+ unsigned int size;
+
+ if (test->card->host->max_blk_count == 1)
+ return RESULT_UNSUP_HOST;
+
+ size = PAGE_SIZE * 2;
+ size = min(size, test->card->host->max_req_size);
+ size = min(size, test->card->host->max_seg_size);
+ size = min(size, test->card->host->max_blk_count * 512);
+
+ if (size < 1024)
+ return RESULT_UNSUP_HOST;
+
+ ret = mmc_test_verified_transfer(test, 1, test->buffer, 0,
+ size / 512, 512);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int mmc_test_multi_read(struct mmc_test_card *test)
+{
+ int ret;
+ unsigned int size;
+
+ if (test->card->host->max_blk_count == 1)
+ return RESULT_UNSUP_HOST;
+
+ size = PAGE_SIZE * 2;
+ size = min(size, test->card->host->max_req_size);
+ size = min(size, test->card->host->max_seg_size);
+ size = min(size, test->card->host->max_blk_count * 512);
+
+ if (size < 1024)
+ return RESULT_UNSUP_HOST;
+
+ ret = mmc_test_verified_transfer(test, 0, test->buffer, 0,
+ size / 512, 512);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int mmc_test_pow2_write(struct mmc_test_card *test)
+{
+ int ret, i;
+
+ if (!test->card->csd.write_partial)
+ return RESULT_UNSUP_CARD;
+
+ for (i = 1; i < 512;i <<= 1) {
+ ret = mmc_test_verified_transfer(test, 1,
+ test->buffer, 0, 1, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mmc_test_pow2_read(struct mmc_test_card *test)
+{
+ int ret, i;
+
+ if (!test->card->csd.read_partial)
+ return RESULT_UNSUP_CARD;
+
+ for (i = 1; i < 512;i <<= 1) {
+ ret = mmc_test_verified_transfer(test, 0,
+ test->buffer, 0, 1, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mmc_test_weird_write(struct mmc_test_card *test)
+{
+ int ret, i;
+
+ if (!test->card->csd.write_partial)
+ return RESULT_UNSUP_CARD;
+
+ for (i = 3; i < 512;i += 7) {
+ ret = mmc_test_verified_transfer(test, 1,
+ test->buffer, 0, 1, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mmc_test_weird_read(struct mmc_test_card *test)
+{
+ int ret, i;
+
+ if (!test->card->csd.read_partial)
+ return RESULT_UNSUP_CARD;
+
+ for (i = 3; i < 512;i += 7) {
+ ret = mmc_test_verified_transfer(test, 0,
+ test->buffer, 0, 1, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mmc_test_align_write(struct mmc_test_card *test)
+{
+ int ret, i;
+
+ for (i = 1;i < 4;i++) {
+ ret = mmc_test_verified_transfer(test, 1, test->buffer + i,
+ 0, 1, 512);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mmc_test_align_read(struct mmc_test_card *test)
+{
+ int ret, i;
+
+ for (i = 1;i < 4;i++) {
+ ret = mmc_test_verified_transfer(test, 0, test->buffer + i,
+ 0, 1, 512);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mmc_test_align_multi_write(struct mmc_test_card *test)
+{
+ int ret, i;
+ unsigned int size;
+
+ if (test->card->host->max_blk_count == 1)
+ return RESULT_UNSUP_HOST;
+
+ size = PAGE_SIZE * 2;
+ size = min(size, test->card->host->max_req_size);
+ size = min(size, test->card->host->max_seg_size);
+ size = min(size, test->card->host->max_blk_count * 512);
+
+ if (size < 1024)
+ return RESULT_UNSUP_HOST;
+
+ for (i = 1;i < 4;i++) {
+ ret = mmc_test_verified_transfer(test, 1, test->buffer + i,
+ 0, size / 512, 512);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mmc_test_align_multi_read(struct mmc_test_card *test)
+{
+ int ret, i;
+ unsigned int size;
+
+ if (test->card->host->max_blk_count == 1)
+ return RESULT_UNSUP_HOST;
+
+ size = PAGE_SIZE * 2;
+ size = min(size, test->card->host->max_req_size);
+ size = min(size, test->card->host->max_seg_size);
+ size = min(size, test->card->host->max_blk_count * 512);
+
+ if (size < 1024)
+ return RESULT_UNSUP_HOST;
+
+ for (i = 1;i < 4;i++) {
+ ret = mmc_test_verified_transfer(test, 0, test->buffer + i,
+ 0, size / 512, 512);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mmc_test_xfersize_write(struct mmc_test_card *test)
+{
+ int ret;
+
+ ret = mmc_test_set_blksize(test, 512);
+ if (ret)
+ return ret;
+
+ ret = __mmc_test_transfer(test, 1, 1, test->buffer, 0, 1, 512);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int mmc_test_xfersize_read(struct mmc_test_card *test)
+{
+ int ret;
+
+ ret = mmc_test_set_blksize(test, 512);
+ if (ret)
+ return ret;
+
+ ret = __mmc_test_transfer(test, 0, 1, test->buffer, 0, 1, 512);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int mmc_test_multi_xfersize_write(struct mmc_test_card *test)
+{
+ int ret;
+
+ if (test->card->host->max_blk_count == 1)
+ return RESULT_UNSUP_HOST;
+
+ ret = mmc_test_set_blksize(test, 512);
+ if (ret)
+ return ret;
+
+ ret = __mmc_test_transfer(test, 1, 1, test->buffer, 0, 2, 512);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int mmc_test_multi_xfersize_read(struct mmc_test_card *test)
+{
+ int ret;
+
+ if (test->card->host->max_blk_count == 1)
+ return RESULT_UNSUP_HOST;
+
+ ret = mmc_test_set_blksize(test, 512);
+ if (ret)
+ return ret;
+
+ ret = __mmc_test_transfer(test, 0, 1, test->buffer, 0, 2, 512);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct mmc_test_case mmc_test_cases[] = {
+ {
+ .name = "Basic write (no data verification)",
+ .run = mmc_test_basic_write,
+ },
+
+ {
+ .name = "Basic read (no data verification)",
+ .run = mmc_test_basic_read,
+ },
+
+ {
+ .name = "Basic write (with data verification)",
+ .prepare = mmc_test_prepare_verify_write,
+ .run = mmc_test_verify_write,
+ .cleanup = mmc_test_cleanup_verify,
+ },
+
+ {
+ .name = "Basic read (with data verification)",
+ .prepare = mmc_test_prepare_verify_read,
+ .run = mmc_test_verify_read,
+ .cleanup = mmc_test_cleanup_verify,
+ },
+
+ {
+ .name = "Multi-block write",
+ .prepare = mmc_test_prepare_verify_write,
+ .run = mmc_test_multi_write,
+ .cleanup = mmc_test_cleanup_verify,
+ },
+
+ {
+ .name = "Multi-block read",
+ .prepare = mmc_test_prepare_verify_read,
+ .run = mmc_test_multi_read,
+ .cleanup = mmc_test_cleanup_verify,
+ },
+
+ {
+ .name = "Power of two block writes",
+ .prepare = mmc_test_prepare_verify_write,
+ .run = mmc_test_pow2_write,
+ .cleanup = mmc_test_cleanup_verify,
+ },
+
+ {
+ .name = "Power of two block reads",
+ .prepare = mmc_test_prepare_verify_read,
+ .run = mmc_test_pow2_read,
+ .cleanup = mmc_test_cleanup_verify,
+ },
+
+ {
+ .name = "Weird sized block writes",
+ .prepare = mmc_test_prepare_verify_write,
+ .run = mmc_test_weird_write,
+ .cleanup = mmc_test_cleanup_verify,
+ },
+
+ {
+ .name = "Weird sized block reads",
+ .prepare = mmc_test_prepare_verify_read,
+ .run = mmc_test_weird_read,
+ .cleanup = mmc_test_cleanup_verify,
+ },
+
+ {
+ .name = "Badly aligned write",
+ .prepare = mmc_test_prepare_verify_write,
+ .run = mmc_test_align_write,
+ .cleanup = mmc_test_cleanup_verify,
+ },
+
+ {
+ .name = "Badly aligned read",
+ .prepare = mmc_test_prepare_verify_read,
+ .run = mmc_test_align_read,
+ .cleanup = mmc_test_cleanup_verify,
+ },
+
+ {
+ .name = "Badly aligned multi-block write",
+ .prepare = mmc_test_prepare_verify_write,
+ .run = mmc_test_align_multi_write,
+ .cleanup = mmc_test_cleanup_verify,
+ },
+
+ {
+ .name = "Badly aligned multi-block read",
+ .prepare = mmc_test_prepare_verify_read,
+ .run = mmc_test_align_multi_read,
+ .cleanup = mmc_test_cleanup_verify,
+ },
+
+ {
+ .name = "Correct xfer_size at write (start failure)",
+ .run = mmc_test_xfersize_write,
+ },
+
+ {
+ .name = "Correct xfer_size at read (start failure)",
+ .run = mmc_test_xfersize_read,
+ },
+
+ {
+ .name = "Correct xfer_size at write (midway failure)",
+ .run = mmc_test_multi_xfersize_write,
+ },
+
+ {
+ .name = "Correct xfer_size at read (midway failure)",
+ .run = mmc_test_multi_xfersize_read,
+ },
+};
+
+static struct mutex mmc_test_lock;
+
+static void mmc_test_run(struct mmc_test_card *test)
+{
+ int i, ret;
+
+ printk(KERN_INFO "%s: Starting tests of card %s...\n",
+ mmc_hostname(test->card->host), mmc_card_id(test->card));
+
+ mmc_claim_host(test->card->host);
+
+ for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) {
+ printk(KERN_INFO "%s: Test case %d. %s...\n",
+ mmc_hostname(test->card->host), i + 1,
+ mmc_test_cases[i].name);
+
+ if (mmc_test_cases[i].prepare) {
+ ret = mmc_test_cases[i].prepare(test);
+ if (ret) {
+ printk(KERN_INFO "%s: Result: Prepare "
+ "stage failed! (%d)\n",
+ mmc_hostname(test->card->host),
+ ret);
+ continue;
+ }
+ }
+
+ ret = mmc_test_cases[i].run(test);
+ switch (ret) {
+ case RESULT_OK:
+ printk(KERN_INFO "%s: Result: OK\n",
+ mmc_hostname(test->card->host));
+ break;
+ case RESULT_FAIL:
+ printk(KERN_INFO "%s: Result: FAILED\n",
+ mmc_hostname(test->card->host));
+ break;
+ case RESULT_UNSUP_HOST:
+ printk(KERN_INFO "%s: Result: UNSUPPORTED "
+ "(by host)\n",
+ mmc_hostname(test->card->host));
+ break;
+ case RESULT_UNSUP_CARD:
+ printk(KERN_INFO "%s: Result: UNSUPPORTED "
+ "(by card)\n",
+ mmc_hostname(test->card->host));
+ break;
+ default:
+ printk(KERN_INFO "%s: Result: ERROR (%d)\n",
+ mmc_hostname(test->card->host), ret);
+ }
+
+ if (mmc_test_cases[i].cleanup) {
+ ret = mmc_test_cases[i].cleanup(test);
+ if (ret) {
+ printk(KERN_INFO "%s: Warning: Cleanup "
+ "stage failed! (%d)\n",
+ mmc_hostname(test->card->host),
+ ret);
+ }
+ }
+ }
+
+ mmc_release_host(test->card->host);
+
+ printk(KERN_INFO "%s: Tests completed.\n",
+ mmc_hostname(test->card->host));
+}
+
+static ssize_t mmc_test_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ mutex_lock(&mmc_test_lock);
+ mutex_unlock(&mmc_test_lock);
+
+ return 0;
+}
+
+static ssize_t mmc_test_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct mmc_card *card;
+ struct mmc_test_card *test;
+
+ card = container_of(dev, struct mmc_card, dev);
+
+ test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL);
+ if (!test)
+ return -ENOMEM;
+
+ test->card = card;
+
+ test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
+ if (test->buffer) {
+ mutex_lock(&mmc_test_lock);
+ mmc_test_run(test);
+ mutex_unlock(&mmc_test_lock);
+ }
+
+ kfree(test->buffer);
+ kfree(test);
+
+ return count;
+}
+
+static DEVICE_ATTR(test, S_IWUSR | S_IRUGO, mmc_test_show, mmc_test_store);
+
+static int mmc_test_probe(struct mmc_card *card)
+{
+ int ret;
+
+ mutex_init(&mmc_test_lock);
+
+ ret = device_create_file(&card->dev, &dev_attr_test);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void mmc_test_remove(struct mmc_card *card)
+{
+ device_remove_file(&card->dev, &dev_attr_test);
+}
+
+static struct mmc_driver mmc_driver = {
+ .drv = {
+ .name = "mmc_test",
+ },
+ .probe = mmc_test_probe,
+ .remove = mmc_test_remove,
+};
+
+static int __init mmc_test_init(void)
+{
+ return mmc_register_driver(&mmc_driver);
+}
+
+static void __exit mmc_test_exit(void)
+{
+ mmc_unregister_driver(&mmc_driver);
+}
+
+module_init(mmc_test_init);
+module_exit(mmc_test_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Multimedia Card (MMC) host test driver");
+MODULE_AUTHOR("Pierre Ossman");
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 3b3cd0e74715..dead61754ad7 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -119,7 +119,7 @@ config MMC_TIFM_SD
config MMC_SPI
tristate "MMC/SD over SPI"
- depends on MMC && SPI_MASTER && !HIGHMEM
+ depends on MMC && SPI_MASTER && !HIGHMEM && HAS_DMA
select CRC7
select CRC_ITU_T
help
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index a28fc2f68ce2..8979ad330a4d 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -663,9 +663,12 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
gpio_set_value(host->board->vcc_pin, 0);
break;
case MMC_POWER_UP:
- case MMC_POWER_ON:
gpio_set_value(host->board->vcc_pin, 1);
break;
+ case MMC_POWER_ON:
+ break;
+ default:
+ WARN_ON(1);
}
}
}
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index 14759e9f42ad..549517c35675 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -1003,7 +1003,7 @@ static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data)
static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data *data)
{
- const char *dev_name;
+ const char *dma_dev_name;
int sync_dev, dma_ch, is_read, r;
is_read = !(data->flags & MMC_DATA_WRITE);
@@ -1018,21 +1018,21 @@ static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data
if (is_read) {
if (host->id == 1) {
sync_dev = OMAP_DMA_MMC_RX;
- dev_name = "MMC1 read";
+ dma_dev_name = "MMC1 read";
} else {
sync_dev = OMAP_DMA_MMC2_RX;
- dev_name = "MMC2 read";
+ dma_dev_name = "MMC2 read";
}
} else {
if (host->id == 1) {
sync_dev = OMAP_DMA_MMC_TX;
- dev_name = "MMC1 write";
+ dma_dev_name = "MMC1 write";
} else {
sync_dev = OMAP_DMA_MMC2_TX;
- dev_name = "MMC2 write";
+ dma_dev_name = "MMC2 write";
}
}
- r = omap_request_dma(sync_dev, dev_name, mmc_omap_dma_cb,
+ r = omap_request_dma(sync_dev, dma_dev_name, mmc_omap_dma_cb,
host, &dma_ch);
if (r != 0) {
dev_dbg(mmc_dev(host->mmc), "omap_request_dma() failed with %d\n", r);
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 65210fca37ed..d89475d36988 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -114,6 +114,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
unsigned int nob = data->blocks;
unsigned long long clks;
unsigned int timeout;
+ bool dalgn = 0;
u32 dcmd;
int i;
@@ -152,6 +153,9 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
host->sg_cpu[i].dcmd = dcmd | length;
if (length & 31 && !(data->flags & MMC_DATA_READ))
host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN;
+ /* Not aligned to 8-byte boundary? */
+ if (sg_dma_address(&data->sg[i]) & 0x7)
+ dalgn = 1;
if (data->flags & MMC_DATA_READ) {
host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
@@ -165,6 +169,15 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
wmb();
+ /*
+ * The PXA27x DMA controller encounters overhead when working with
+ * unaligned (to 8-byte boundaries) data, so switch on byte alignment
+ * mode only if we have unaligned data.
+ */
+ if (dalgn)
+ DALGN |= (1 << host->dma);
+ else
+ DALGN &= (1 << host->dma);
DDADR(host->dma) = host->sg_dma;
DCSR(host->dma) = DCSR_RUN;
}
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 07c2048b230b..b413aa6c246b 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -55,6 +55,10 @@ static unsigned int debug_quirks = 0;
#define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<7)
/* Controller needs to be reset after each request to stay stable */
#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<8)
+/* Controller needs voltage and power writes to happen separately */
+#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<9)
+/* Controller has an off-by-one issue with timeout value */
+#define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL (1<<10)
static const struct pci_device_id pci_ids[] __devinitdata = {
{
@@ -115,7 +119,8 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE |
- SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
+ SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS |
+ SDHCI_QUIRK_BROKEN_DMA,
},
{
@@ -124,7 +129,17 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE |
- SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
+ SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS |
+ SDHCI_QUIRK_BROKEN_DMA,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_MARVELL,
+ .device = PCI_DEVICE_ID_MARVELL_CAFE_SD,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
+ SDHCI_QUIRK_INCR_TIMEOUT_CONTROL,
},
{
@@ -469,6 +484,13 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
break;
}
+ /*
+ * Compensate for an off-by-one error in the CaFe hardware; otherwise,
+ * a too-small count gives us interrupt timeouts.
+ */
+ if ((host->chip->quirks & SDHCI_QUIRK_INCR_TIMEOUT_CONTROL))
+ count++;
+
if (count >= 0xF) {
printk(KERN_WARNING "%s: Too large timeout requested!\n",
mmc_hostname(host->mmc));
@@ -774,6 +796,14 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
BUG();
}
+ /*
+ * At least the CaFe chip gets confused if we set the voltage
+ * and set turn on power at the same time, so set the voltage first.
+ */
+ if ((host->chip->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER))
+ writeb(pwr & ~SDHCI_POWER_ON,
+ host->ioaddr + SDHCI_POWER_CONTROL);
+
writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
out:
diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c
index be624a049c67..c303e7f57ab4 100644
--- a/drivers/mmc/host/wbsd.c
+++ b/drivers/mmc/host/wbsd.c
@@ -1457,17 +1457,7 @@ static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq)
int ret;
/*
- * Allocate interrupt.
- */
-
- ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host);
- if (ret)
- return ret;
-
- host->irq = irq;
-
- /*
- * Set up tasklets.
+ * Set up tasklets. Must be done before requesting interrupt.
*/
tasklet_init(&host->card_tasklet, wbsd_tasklet_card,
(unsigned long)host);
@@ -1480,6 +1470,15 @@ static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq)
tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish,
(unsigned long)host);
+ /*
+ * Allocate interrupt.
+ */
+ ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host);
+ if (ret)
+ return ret;
+
+ host->irq = irq;
+
return 0;
}
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 25efd331ef28..b402269301f6 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -346,8 +346,10 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
mutex_lock(&flash->lock);
/* Wait until finished previous write command. */
- if (wait_till_ready(flash))
+ if (wait_till_ready(flash)) {
+ mutex_unlock(&flash->lock);
return 1;
+ }
write_enable(flash);
diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c
index 59d8fb49270a..effaf7cdefab 100644
--- a/drivers/mtd/maps/ck804xrom.c
+++ b/drivers/mtd/maps/ck804xrom.c
@@ -331,15 +331,15 @@ static void __devexit ck804xrom_remove_one (struct pci_dev *pdev)
}
static struct pci_device_id ck804xrom_pci_tbl[] = {
- { PCI_VENDOR_ID_NVIDIA, 0x0051, PCI_ANY_ID, PCI_ANY_ID, DEV_CK804 },
- { PCI_VENDOR_ID_NVIDIA, 0x0360, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 },
- { PCI_VENDOR_ID_NVIDIA, 0x0361, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 },
- { PCI_VENDOR_ID_NVIDIA, 0x0362, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 },
- { PCI_VENDOR_ID_NVIDIA, 0x0363, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 },
- { PCI_VENDOR_ID_NVIDIA, 0x0364, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 },
- { PCI_VENDOR_ID_NVIDIA, 0x0365, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 },
- { PCI_VENDOR_ID_NVIDIA, 0x0366, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 },
- { PCI_VENDOR_ID_NVIDIA, 0x0367, PCI_ANY_ID, PCI_ANY_ID, DEV_MCP55 },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0051), .driver_data = DEV_CK804 },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0360), .driver_data = DEV_MCP55 },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0361), .driver_data = DEV_MCP55 },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0362), .driver_data = DEV_MCP55 },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0363), .driver_data = DEV_MCP55 },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0364), .driver_data = DEV_MCP55 },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0365), .driver_data = DEV_MCP55 },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0366), .driver_data = DEV_MCP55 },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0367), .driver_data = DEV_MCP55 },
{ 0, }
};
diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c
index 240b0e2d095d..c12d8056bebd 100644
--- a/drivers/mtd/maps/omap_nor.c
+++ b/drivers/mtd/maps/omap_nor.c
@@ -110,7 +110,7 @@ static int __init omapflash_probe(struct platform_device *pdev)
err = parse_mtd_partitions(info->mtd, part_probes, &info->parts, 0);
if (err > 0)
add_mtd_partitions(info->mtd, info->parts, err);
- else if (err < 0 && pdata->parts)
+ else if (err <= 0 && pdata->parts)
add_mtd_partitions(info->mtd, pdata->parts, pdata->nr_parts);
else
#endif
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index fceb468ccdec..fe2bc7e42119 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -1216,7 +1216,7 @@ static int pxa3xx_nand_resume(struct platform_device *pdev)
clk_enable(info->clk);
- return pxa3xx_nand_config_flash(info);
+ return pxa3xx_nand_config_flash(info, info->flash_info);
}
#else
#define pxa3xx_nand_suspend NULL
diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c
index 3d44d040a47d..ad81ab8e95e2 100644
--- a/drivers/mtd/onenand/generic.c
+++ b/drivers/mtd/onenand/generic.c
@@ -76,7 +76,7 @@ static int __devinit generic_onenand_probe(struct device *dev)
err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);
if (err > 0)
add_mtd_partitions(&info->mtd, info->parts, err);
- else if (err < 0 && pdata->parts)
+ else if (err <= 0 && pdata->parts)
add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts);
else
#endif
diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c
index 47474903263c..c5030f94f04e 100644
--- a/drivers/mtd/redboot.c
+++ b/drivers/mtd/redboot.c
@@ -295,5 +295,5 @@ module_init(redboot_parser_init);
module_exit(redboot_parser_exit);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>");
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
MODULE_DESCRIPTION("Parsing code for RedBoot Flash Image System (FIS) tables");
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index e6c545fe5f58..b9d097c9f6bb 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -413,7 +413,7 @@ static int __devinit el3_pnp_probe(struct pnp_dev *pdev,
{
short i;
int ioaddr, irq, if_port;
- u16 phys_addr[3];
+ __be16 phys_addr[3];
struct net_device *dev = NULL;
int err;
@@ -605,7 +605,7 @@ static int __init el3_mca_probe(struct device *device)
short i;
int ioaddr, irq, if_port;
- u16 phys_addr[3];
+ __be16 phys_addr[3];
struct net_device *dev = NULL;
u_char pos4, pos5;
struct mca_device *mdev = to_mca_device(device);
@@ -635,14 +635,13 @@ static int __init el3_mca_probe(struct device *device)
printk(KERN_DEBUG "3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port);
}
EL3WINDOW(0);
- for (i = 0; i < 3; i++) {
- phys_addr[i] = htons(read_eeprom(ioaddr, i));
- }
+ for (i = 0; i < 3; i++)
+ phys_addr[i] = htons(read_eeprom(ioaddr, i));
dev = alloc_etherdev(sizeof (struct el3_private));
if (dev == NULL) {
- release_region(ioaddr, EL3_IO_EXTENT);
- return -ENOMEM;
+ release_region(ioaddr, EL3_IO_EXTENT);
+ return -ENOMEM;
}
netdev_boot_setup_check(dev);
@@ -668,7 +667,7 @@ static int __init el3_eisa_probe (struct device *device)
{
short i;
int ioaddr, irq, if_port;
- u16 phys_addr[3];
+ __be16 phys_addr[3];
struct net_device *dev = NULL;
struct eisa_device *edev;
int err;
@@ -1063,7 +1062,6 @@ el3_rx(struct net_device *dev)
struct sk_buff *skb;
skb = dev_alloc_skb(pkt_len+5);
- dev->stats.rx_bytes += pkt_len;
if (el3_debug > 4)
printk("Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
@@ -1078,6 +1076,7 @@ el3_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
+ dev->stats.rx_bytes += pkt_len;
dev->stats.rx_packets++;
continue;
}
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 2edda8cc7f99..aabad8ce7458 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -1768,9 +1768,10 @@ vortex_timer(unsigned long data)
case XCVR_MII: case XCVR_NWAY:
{
ok = 1;
- spin_lock_bh(&vp->lock);
+ /* Interrupts are already disabled */
+ spin_lock(&vp->lock);
vortex_check_media(dev, 0);
- spin_unlock_bh(&vp->lock);
+ spin_unlock(&vp->lock);
}
break;
default: /* Other media types handled by Tx timeouts. */
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index 750a46f4bc58..ad6b8a5b6574 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -506,6 +506,7 @@ int lance_open (struct net_device *dev)
return res;
}
+EXPORT_SYMBOL_GPL(lance_open);
int lance_close (struct net_device *dev)
{
@@ -521,6 +522,7 @@ int lance_close (struct net_device *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(lance_close);
void lance_tx_timeout(struct net_device *dev)
{
@@ -529,7 +531,7 @@ void lance_tx_timeout(struct net_device *dev)
dev->trans_start = jiffies;
netif_wake_queue (dev);
}
-
+EXPORT_SYMBOL_GPL(lance_tx_timeout);
int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
{
@@ -586,6 +588,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(lance_start_xmit);
/* taken from the depca driver via a2065.c */
static void lance_load_multicast (struct net_device *dev)
@@ -654,6 +657,7 @@ void lance_set_multicast (struct net_device *dev)
if (!stopped)
netif_start_queue (dev);
}
+EXPORT_SYMBOL_GPL(lance_set_multicast);
#ifdef CONFIG_NET_POLL_CONTROLLER
void lance_poll(struct net_device *dev)
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 9f6cc8a56073..f4182cfffe9d 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1353,7 +1353,7 @@ config APRICOT
config B44
tristate "Broadcom 440x/47xx ethernet support"
- depends on SSB_POSSIBLE
+ depends on SSB_POSSIBLE && HAS_DMA
select SSB
select MII
help
@@ -2426,7 +2426,7 @@ config CHELSIO_T3
config EHEA
tristate "eHEA Ethernet support"
- depends on IBMEBUS && INET && SPARSEMEM && MEMORY_HOTPLUG
+ depends on IBMEBUS && INET && SPARSEMEM
select INET_LRO
---help---
This driver supports the IBM pSeries eHEA ethernet adapter.
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index 9c2394d49428..3c798ae5c343 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -471,7 +471,6 @@ static int atl1_get_permanent_address(struct atl1_hw *hw)
memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN);
return 0;
}
- return 1;
}
/* see if SPI FLAGS exist ? */
@@ -637,22 +636,6 @@ static s32 atl1_phy_leave_power_saving(struct atl1_hw *hw)
}
/*
- * Force the PHY into power saving mode using vendor magic.
- */
-#ifdef CONFIG_PM
-static void atl1_phy_enter_power_saving(struct atl1_hw *hw)
-{
- atl1_write_phy_reg(hw, MII_DBG_ADDR, 0);
- atl1_write_phy_reg(hw, MII_DBG_DATA, 0x124E);
- atl1_write_phy_reg(hw, MII_DBG_ADDR, 2);
- atl1_write_phy_reg(hw, MII_DBG_DATA, 0x3000);
- atl1_write_phy_reg(hw, MII_DBG_ADDR, 3);
- atl1_write_phy_reg(hw, MII_DBG_DATA, 0);
-
-}
-#endif
-
-/*
* Resets the PHY and make all config validate
* hw - Struct containing variables accessed by shared code
*
@@ -2023,6 +2006,7 @@ rrd_ok:
/* Good Receive */
pci_unmap_page(adapter->pdev, buffer_info->dma,
buffer_info->length, PCI_DMA_FROMDEVICE);
+ buffer_info->dma = 0;
skb = buffer_info->skb;
length = le16_to_cpu(rrd->xsz.xsum_sz.pkt_size);
@@ -2135,7 +2119,7 @@ static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
return -1;
}
- if (skb->protocol == ntohs(ETH_P_IP)) {
+ if (skb->protocol == htons(ETH_P_IP)) {
struct iphdr *iph = ip_hdr(skb);
real_len = (((unsigned char *)iph - skb->data) +
@@ -2859,7 +2843,6 @@ disable_wol:
ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
iowrite32(ctrl, hw->hw_addr + REG_PCIE_PHYMISC);
ioread32(hw->hw_addr + REG_PCIE_PHYMISC);
- atl1_phy_enter_power_saving(hw);
hw->phy_configured = false;
pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
exit:
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 3634b5fd7919..7023d77bf380 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -1239,12 +1239,7 @@ static int au1000_rx(struct net_device *dev)
*/
static irqreturn_t au1000_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *) dev_id;
-
- if (dev == NULL) {
- printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name);
- return IRQ_RETVAL(1);
- }
+ struct net_device *dev = dev_id;
/* Handle RX interrupts first to minimize chance of overrun */
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 89c0018132ec..41443435ab1c 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -22,7 +22,6 @@
#include <linux/crc32.h>
#include <linux/device.h>
#include <linux/spinlock.h>
-#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/phy.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 4b46e68183e0..367b6d462708 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -5724,14 +5724,12 @@ bnx2_reset_task(struct work_struct *work)
if (!netif_running(bp->dev))
return;
- bp->in_reset_task = 1;
bnx2_netif_stop(bp);
bnx2_init_nic(bp);
atomic_set(&bp->intr_sem, 1);
bnx2_netif_start(bp);
- bp->in_reset_task = 0;
}
static void
@@ -5907,12 +5905,7 @@ bnx2_close(struct net_device *dev)
struct bnx2 *bp = netdev_priv(dev);
u32 reset_code;
- /* Calling flush_scheduled_work() may deadlock because
- * linkwatch_event() may be on the workqueue and it will try to get
- * the rtnl_lock which we are holding.
- */
- while (bp->in_reset_task)
- msleep(1);
+ cancel_work_sync(&bp->reset_task);
bnx2_disable_int_sync(bp);
bnx2_napi_disable(bp);
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index 1eaf5bb3d9c2..2377cc13bf61 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -6656,7 +6656,6 @@ struct bnx2 {
int current_interval;
struct timer_list timer;
struct work_struct reset_task;
- int in_reset_task;
/* Used to synchronize phy accesses. */
spinlock_t phy_lock;
diff --git a/drivers/net/bnx2x.c b/drivers/net/bnx2x.c
index 7bdb5af35951..70cba64732ca 100644
--- a/drivers/net/bnx2x.c
+++ b/drivers/net/bnx2x.c
@@ -6,7 +6,8 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
- * Written by: Eliezer Tamir <eliezert@broadcom.com>
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Eliezer Tamir
* Based on code from Michael Chan's bnx2 driver
* UDP CSUM errata workaround by Arik Gendelman
* Slowpath rework by Vladislav Zolotarov
@@ -74,7 +75,7 @@ static char version[] __devinitdata =
"Broadcom NetXtreme II 5771X 10Gigabit Ethernet Driver "
DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
-MODULE_AUTHOR("Eliezer Tamir <eliezert@broadcom.com>");
+MODULE_AUTHOR("Eliezer Tamir");
MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710 Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h
index 4f0c0d31e7c1..8e68d06510a6 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x.h
@@ -6,7 +6,8 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
- * Written by: Eliezer Tamir <eliezert@broadcom.com>
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Eliezer Tamir
* Based on code from Michael Chan's bnx2 driver
*/
diff --git a/drivers/net/bnx2x_init.h b/drivers/net/bnx2x_init.h
index dcaecc53bdb1..370686eef97c 100644
--- a/drivers/net/bnx2x_init.h
+++ b/drivers/net/bnx2x_init.h
@@ -6,7 +6,8 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
- * Written by: Eliezer Tamir <eliezert@broadcom.com>
+ * Maintained by: Eilon Greenstein <eilong@broadcom.com>
+ * Written by: Eliezer Tamir
*/
#ifndef BNX2X_INIT_H
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 68c41a00d93d..08f3d396bcd6 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -1437,8 +1437,16 @@ int bond_create_sysfs(void)
* configure multiple bonding devices.
*/
if (ret == -EEXIST) {
- netdev_class = NULL;
- return 0;
+ /* Is someone being kinky and naming a device bonding_master? */
+ if (__dev_get_by_name(&init_net,
+ class_attr_bonding_masters.attr.name))
+ printk(KERN_ERR
+ "network device named %s already exists in sysfs",
+ class_attr_bonding_masters.attr.name);
+ else {
+ netdev_class = NULL;
+ return 0;
+ }
}
return ret;
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 93e13636f8dd..83768df27806 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -142,8 +142,8 @@
#define DRV_MODULE_NAME "cassini"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.5"
-#define DRV_MODULE_RELDATE "4 Jan 2008"
+#define DRV_MODULE_VERSION "1.6"
+#define DRV_MODULE_RELDATE "21 May 2008"
#define CAS_DEF_MSG_ENABLE \
(NETIF_MSG_DRV | \
@@ -2136,9 +2136,12 @@ end_copy_pkt:
if (addr)
cas_page_unmap(addr);
}
- skb->csum = csum_unfold(~csum);
- skb->ip_summed = CHECKSUM_COMPLETE;
skb->protocol = eth_type_trans(skb, cp->dev);
+ if (skb->protocol == htons(ETH_P_IP)) {
+ skb->csum = csum_unfold(~csum);
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ } else
+ skb->ip_summed = CHECKSUM_NONE;
return len;
}
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c
index 2b5740b3d182..7f3f62e1b113 100644
--- a/drivers/net/cpmac.c
+++ b/drivers/net/cpmac.c
@@ -38,6 +38,7 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <asm/gpio.h>
+#include <asm/atomic.h>
MODULE_AUTHOR("Eugene Konev <ejka@imfi.kspu.ru>");
MODULE_DESCRIPTION("TI AR7 ethernet driver (CPMAC)");
@@ -187,6 +188,7 @@ struct cpmac_desc {
#define CPMAC_EOQ 0x1000
struct sk_buff *skb;
struct cpmac_desc *next;
+ struct cpmac_desc *prev;
dma_addr_t mapping;
dma_addr_t data_mapping;
};
@@ -208,6 +210,7 @@ struct cpmac_priv {
struct work_struct reset_work;
struct platform_device *pdev;
struct napi_struct napi;
+ atomic_t reset_pending;
};
static irqreturn_t cpmac_irq(int, void *);
@@ -241,6 +244,16 @@ static void cpmac_dump_desc(struct net_device *dev, struct cpmac_desc *desc)
printk("\n");
}
+static void cpmac_dump_all_desc(struct net_device *dev)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+ struct cpmac_desc *dump = priv->rx_head;
+ do {
+ cpmac_dump_desc(dev, dump);
+ dump = dump->next;
+ } while (dump != priv->rx_head);
+}
+
static void cpmac_dump_skb(struct net_device *dev, struct sk_buff *skb)
{
int i;
@@ -412,21 +425,42 @@ static struct sk_buff *cpmac_rx_one(struct cpmac_priv *priv,
static int cpmac_poll(struct napi_struct *napi, int budget)
{
struct sk_buff *skb;
- struct cpmac_desc *desc;
- int received = 0;
+ struct cpmac_desc *desc, *restart;
struct cpmac_priv *priv = container_of(napi, struct cpmac_priv, napi);
+ int received = 0, processed = 0;
spin_lock(&priv->rx_lock);
if (unlikely(!priv->rx_head)) {
if (netif_msg_rx_err(priv) && net_ratelimit())
printk(KERN_WARNING "%s: rx: polling, but no queue\n",
priv->dev->name);
+ spin_unlock(&priv->rx_lock);
netif_rx_complete(priv->dev, napi);
return 0;
}
desc = priv->rx_head;
+ restart = NULL;
while (((desc->dataflags & CPMAC_OWN) == 0) && (received < budget)) {
+ processed++;
+
+ if ((desc->dataflags & CPMAC_EOQ) != 0) {
+ /* The last update to eoq->hw_next didn't happen
+ * soon enough, and the receiver stopped here.
+ *Remember this descriptor so we can restart
+ * the receiver after freeing some space.
+ */
+ if (unlikely(restart)) {
+ if (netif_msg_rx_err(priv))
+ printk(KERN_ERR "%s: poll found a"
+ " duplicate EOQ: %p and %p\n",
+ priv->dev->name, restart, desc);
+ goto fatal_error;
+ }
+
+ restart = desc->next;
+ }
+
skb = cpmac_rx_one(priv, desc);
if (likely(skb)) {
netif_receive_skb(skb);
@@ -435,19 +469,90 @@ static int cpmac_poll(struct napi_struct *napi, int budget)
desc = desc->next;
}
+ if (desc != priv->rx_head) {
+ /* We freed some buffers, but not the whole ring,
+ * add what we did free to the rx list */
+ desc->prev->hw_next = (u32)0;
+ priv->rx_head->prev->hw_next = priv->rx_head->mapping;
+ }
+
+ /* Optimization: If we did not actually process an EOQ (perhaps because
+ * of quota limits), check to see if the tail of the queue has EOQ set.
+ * We should immediately restart in that case so that the receiver can
+ * restart and run in parallel with more packet processing.
+ * This lets us handle slightly larger bursts before running
+ * out of ring space (assuming dev->weight < ring_size) */
+
+ if (!restart &&
+ (priv->rx_head->prev->dataflags & (CPMAC_OWN|CPMAC_EOQ))
+ == CPMAC_EOQ &&
+ (priv->rx_head->dataflags & CPMAC_OWN) != 0) {
+ /* reset EOQ so the poll loop (above) doesn't try to
+ * restart this when it eventually gets to this descriptor.
+ */
+ priv->rx_head->prev->dataflags &= ~CPMAC_EOQ;
+ restart = priv->rx_head;
+ }
+
+ if (restart) {
+ priv->dev->stats.rx_errors++;
+ priv->dev->stats.rx_fifo_errors++;
+ if (netif_msg_rx_err(priv) && net_ratelimit())
+ printk(KERN_WARNING "%s: rx dma ring overrun\n",
+ priv->dev->name);
+
+ if (unlikely((restart->dataflags & CPMAC_OWN) == 0)) {
+ if (netif_msg_drv(priv))
+ printk(KERN_ERR "%s: cpmac_poll is trying to "
+ "restart rx from a descriptor that's "
+ "not free: %p\n",
+ priv->dev->name, restart);
+ goto fatal_error;
+ }
+
+ cpmac_write(priv->regs, CPMAC_RX_PTR(0), restart->mapping);
+ }
+
priv->rx_head = desc;
spin_unlock(&priv->rx_lock);
if (unlikely(netif_msg_rx_status(priv)))
printk(KERN_DEBUG "%s: poll processed %d packets\n",
priv->dev->name, received);
- if (desc->dataflags & CPMAC_OWN) {
+ if (processed == 0) {
+ /* we ran out of packets to read,
+ * revert to interrupt-driven mode */
netif_rx_complete(priv->dev, napi);
- cpmac_write(priv->regs, CPMAC_RX_PTR(0), (u32)desc->mapping);
cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1);
return 0;
}
return 1;
+
+fatal_error:
+ /* Something went horribly wrong.
+ * Reset hardware to try to recover rather than wedging. */
+
+ if (netif_msg_drv(priv)) {
+ printk(KERN_ERR "%s: cpmac_poll is confused. "
+ "Resetting hardware\n", priv->dev->name);
+ cpmac_dump_all_desc(priv->dev);
+ printk(KERN_DEBUG "%s: RX_PTR(0)=0x%08x RX_ACK(0)=0x%08x\n",
+ priv->dev->name,
+ cpmac_read(priv->regs, CPMAC_RX_PTR(0)),
+ cpmac_read(priv->regs, CPMAC_RX_ACK(0)));
+ }
+
+ spin_unlock(&priv->rx_lock);
+ netif_rx_complete(priv->dev, napi);
+ netif_stop_queue(priv->dev);
+ napi_disable(&priv->napi);
+
+ atomic_inc(&priv->reset_pending);
+ cpmac_hw_stop(priv->dev);
+ if (!schedule_work(&priv->reset_work))
+ atomic_dec(&priv->reset_pending);
+ return 0;
+
}
static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -456,6 +561,9 @@ static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct cpmac_desc *desc;
struct cpmac_priv *priv = netdev_priv(dev);
+ if (unlikely(atomic_read(&priv->reset_pending)))
+ return NETDEV_TX_BUSY;
+
if (unlikely(skb_padto(skb, ETH_ZLEN)))
return NETDEV_TX_OK;
@@ -621,8 +729,10 @@ static void cpmac_clear_rx(struct net_device *dev)
desc->dataflags = CPMAC_OWN;
dev->stats.rx_dropped++;
}
+ desc->hw_next = desc->next->mapping;
desc = desc->next;
}
+ priv->rx_head->prev->hw_next = 0;
}
static void cpmac_clear_tx(struct net_device *dev)
@@ -635,14 +745,14 @@ static void cpmac_clear_tx(struct net_device *dev)
priv->desc_ring[i].dataflags = 0;
if (priv->desc_ring[i].skb) {
dev_kfree_skb_any(priv->desc_ring[i].skb);
- if (netif_subqueue_stopped(dev, i))
- netif_wake_subqueue(dev, i);
+ priv->desc_ring[i].skb = NULL;
}
}
}
static void cpmac_hw_error(struct work_struct *work)
{
+ int i;
struct cpmac_priv *priv =
container_of(work, struct cpmac_priv, reset_work);
@@ -651,8 +761,48 @@ static void cpmac_hw_error(struct work_struct *work)
spin_unlock(&priv->rx_lock);
cpmac_clear_tx(priv->dev);
cpmac_hw_start(priv->dev);
- napi_enable(&priv->napi);
- netif_start_queue(priv->dev);
+ barrier();
+ atomic_dec(&priv->reset_pending);
+
+ for (i = 0; i < CPMAC_QUEUES; i++)
+ netif_wake_subqueue(priv->dev, i);
+ netif_wake_queue(priv->dev);
+ cpmac_write(priv->regs, CPMAC_MAC_INT_ENABLE, 3);
+}
+
+static void cpmac_check_status(struct net_device *dev)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+
+ u32 macstatus = cpmac_read(priv->regs, CPMAC_MAC_STATUS);
+ int rx_channel = (macstatus >> 8) & 7;
+ int rx_code = (macstatus >> 12) & 15;
+ int tx_channel = (macstatus >> 16) & 7;
+ int tx_code = (macstatus >> 20) & 15;
+
+ if (rx_code || tx_code) {
+ if (netif_msg_drv(priv) && net_ratelimit()) {
+ /* Can't find any documentation on what these
+ *error codes actually are. So just log them and hope..
+ */
+ if (rx_code)
+ printk(KERN_WARNING "%s: host error %d on rx "
+ "channel %d (macstatus %08x), resetting\n",
+ dev->name, rx_code, rx_channel, macstatus);
+ if (tx_code)
+ printk(KERN_WARNING "%s: host error %d on tx "
+ "channel %d (macstatus %08x), resetting\n",
+ dev->name, tx_code, tx_channel, macstatus);
+ }
+
+ netif_stop_queue(dev);
+ cpmac_hw_stop(dev);
+ if (schedule_work(&priv->reset_work))
+ atomic_inc(&priv->reset_pending);
+ if (unlikely(netif_msg_hw(priv)))
+ cpmac_dump_regs(dev);
+ }
+ cpmac_write(priv->regs, CPMAC_MAC_INT_CLEAR, 0xff);
}
static irqreturn_t cpmac_irq(int irq, void *dev_id)
@@ -683,49 +833,32 @@ static irqreturn_t cpmac_irq(int irq, void *dev_id)
cpmac_write(priv->regs, CPMAC_MAC_EOI_VECTOR, 0);
- if (unlikely(status & (MAC_INT_HOST | MAC_INT_STATUS))) {
- if (netif_msg_drv(priv) && net_ratelimit())
- printk(KERN_ERR "%s: hw error, resetting...\n",
- dev->name);
- netif_stop_queue(dev);
- napi_disable(&priv->napi);
- cpmac_hw_stop(dev);
- schedule_work(&priv->reset_work);
- if (unlikely(netif_msg_hw(priv)))
- cpmac_dump_regs(dev);
- }
+ if (unlikely(status & (MAC_INT_HOST | MAC_INT_STATUS)))
+ cpmac_check_status(dev);
return IRQ_HANDLED;
}
static void cpmac_tx_timeout(struct net_device *dev)
{
- struct cpmac_priv *priv = netdev_priv(dev);
int i;
+ struct cpmac_priv *priv = netdev_priv(dev);
spin_lock(&priv->lock);
dev->stats.tx_errors++;
spin_unlock(&priv->lock);
if (netif_msg_tx_err(priv) && net_ratelimit())
printk(KERN_WARNING "%s: transmit timeout\n", dev->name);
- /*
- * FIXME: waking up random queue is not the best thing to
- * do... on the other hand why we got here at all?
- */
-#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+
+ atomic_inc(&priv->reset_pending);
+ barrier();
+ cpmac_clear_tx(dev);
+ barrier();
+ atomic_dec(&priv->reset_pending);
+
+ netif_wake_queue(priv->dev);
for (i = 0; i < CPMAC_QUEUES; i++)
- if (priv->desc_ring[i].skb) {
- priv->desc_ring[i].dataflags = 0;
- dev_kfree_skb_any(priv->desc_ring[i].skb);
- netif_wake_subqueue(dev, i);
- break;
- }
-#else
- priv->desc_ring[0].dataflags = 0;
- if (priv->desc_ring[0].skb)
- dev_kfree_skb_any(priv->desc_ring[0].skb);
- netif_wake_queue(dev);
-#endif
+ netif_wake_subqueue(dev, i);
}
static int cpmac_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -901,9 +1034,12 @@ static int cpmac_open(struct net_device *dev)
desc->buflen = CPMAC_SKB_SIZE;
desc->dataflags = CPMAC_OWN;
desc->next = &priv->rx_head[(i + 1) % priv->ring_size];
+ desc->next->prev = desc;
desc->hw_next = (u32)desc->next->mapping;
}
+ priv->rx_head->prev->hw_next = (u32)0;
+
if ((res = request_irq(dev->irq, cpmac_irq, IRQF_SHARED,
dev->name, dev))) {
if (netif_msg_drv(priv))
@@ -912,6 +1048,7 @@ static int cpmac_open(struct net_device *dev)
goto fail_irq;
}
+ atomic_set(&priv->reset_pending, 0);
INIT_WORK(&priv->reset_work, cpmac_hw_error);
cpmac_hw_start(dev);
@@ -1007,21 +1144,10 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
if (phy_id == PHY_MAX_ADDR) {
if (external_switch || dumb_switch) {
- struct fixed_phy_status status = {};
-
- /*
- * FIXME: this should be in the platform code!
- * Since there is not platform code at all (that is,
- * no mainline users of that driver), place it here
- * for now.
- */
- phy_id = 0;
- status.link = 1;
- status.duplex = 1;
- status.speed = 100;
- fixed_phy_add(PHY_POLL, phy_id, &status);
+ mdio_bus_id = 0; /* fixed phys bus */
+ phy_id = pdev->id;
} else {
- printk(KERN_ERR "cpmac: no PHY present\n");
+ dev_err(&pdev->dev, "no PHY present\n");
return -ENODEV;
}
}
@@ -1064,10 +1190,8 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
priv->msg_enable = netif_msg_init(debug_level, 0xff);
memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr));
- snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id);
-
- priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link, 0,
- PHY_INTERFACE_MODE_MII);
+ priv->phy = phy_connect(dev, cpmac_mii.phy_map[phy_id]->dev.bus_id,
+ &cpmac_adjust_link, 0, PHY_INTERFACE_MODE_MII);
if (IS_ERR(priv->phy)) {
if (netif_msg_drv(priv))
printk(KERN_ERR "%s: Could not attach to PHY\n",
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 348371fda597..fba87abe78ee 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -1394,7 +1394,11 @@ net_open(struct net_device *dev)
#endif
if (!result) {
printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name);
- release_irq:
+release_dma:
+#if ALLOW_DMA
+ free_dma(dev->dma);
+#endif
+release_irq:
#if ALLOW_DMA
release_dma_buff(lp);
#endif
@@ -1442,12 +1446,12 @@ net_open(struct net_device *dev)
if ((result = detect_bnc(dev)) != DETECTED_NONE)
break;
printk(KERN_ERR "%s: no media detected\n", dev->name);
- goto release_irq;
+ goto release_dma;
}
switch(result) {
case DETECTED_NONE:
printk(KERN_ERR "%s: no network cable attached to configured media\n", dev->name);
- goto release_irq;
+ goto release_dma;
case DETECTED_RJ45H:
printk(KERN_INFO "%s: using half-duplex 10Base-T (RJ-45)\n", dev->name);
break;
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index d45bcd2660af..864295e081b6 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -903,7 +903,7 @@ dm9000_stop(struct net_device *ndev)
if (netif_msg_ifdown(db))
dev_dbg(db->dev, "shutting down %s\n", ndev->name);
- cancel_delayed_work(&db->phy_poll);
+ cancel_delayed_work_sync(&db->phy_poll);
netif_stop_queue(ndev);
netif_carrier_off(ndev);
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index f3cba5e24ec5..1037b1332312 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1803,6 +1803,8 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
if (rx->prev->skb) {
struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data;
put_unaligned_le32(rx->dma_addr, &prev_rfd->link);
+ pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
+ sizeof(struct rfd), PCI_DMA_TODEVICE);
}
return 0;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 701531e72e7b..a3f6a9c72ec8 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -347,7 +347,7 @@ e1000_set_tso(struct net_device *netdev, u32 data)
else
netdev->features &= ~NETIF_F_TSO;
- if (data)
+ if (data && (adapter->hw.mac_type > e1000_82547_rev_2))
netdev->features |= NETIF_F_TSO6;
else
netdev->features &= ~NETIF_F_TSO6;
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 8cbb40f3a506..648a87bbf467 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -2535,7 +2535,8 @@ void e1000e_down(struct e1000_adapter *adapter)
adapter->link_speed = 0;
adapter->link_duplex = 0;
- e1000e_reset(adapter);
+ if (!pci_channel_offline(adapter->pdev))
+ e1000e_reset(adapter);
e1000_clean_tx_ring(adapter);
e1000_clean_rx_ring(adapter);
@@ -4201,8 +4202,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
struct e1000_adapter *adapter;
struct e1000_hw *hw;
const struct e1000_info *ei = e1000_info_tbl[ent->driver_data];
- unsigned long mmio_start, mmio_len;
- unsigned long flash_start, flash_len;
+ resource_size_t mmio_start, mmio_len;
+ resource_size_t flash_start, flash_len;
static int cards_found;
int i, err, pci_using_dac;
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index fe872fbd671e..e01926b7b5b7 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -40,7 +40,7 @@
#include <asm/io.h>
#define DRV_NAME "ehea"
-#define DRV_VERSION "EHEA_0091"
+#define DRV_VERSION "EHEA_0092"
/* eHEA capability flags */
#define DLPAR_PORT_ADD_REM 1
@@ -452,7 +452,7 @@ struct ehea_bcmc_reg_entry {
struct ehea_bcmc_reg_array {
struct ehea_bcmc_reg_entry *arr;
int num_entries;
- struct mutex lock;
+ spinlock_t lock;
};
#define EHEA_PORT_UP 1
@@ -478,6 +478,7 @@ struct ehea_port {
int num_add_tx_qps;
int num_mcs;
int resets;
+ u64 flags;
u64 mac_addr;
u32 logical_port_id;
u32 port_speed;
@@ -501,7 +502,8 @@ struct port_res_cfg {
};
enum ehea_flag_bits {
- __EHEA_STOP_XFER
+ __EHEA_STOP_XFER,
+ __EHEA_DISABLE_PORT_RESET
};
void ehea_set_ethtool_ops(struct net_device *netdev);
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index d1b6d4e7495d..0920b796bd78 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -118,6 +118,7 @@ static struct of_device_id ehea_device_table[] = {
},
{},
};
+MODULE_DEVICE_TABLE(of, ehea_device_table);
static struct of_platform_driver ehea_driver = {
.name = "ehea",
@@ -137,6 +138,12 @@ void ehea_dump(void *adr, int len, char *msg)
}
}
+void ehea_schedule_port_reset(struct ehea_port *port)
+{
+ if (!test_bit(__EHEA_DISABLE_PORT_RESET, &port->flags))
+ schedule_work(&port->reset_task);
+}
+
static void ehea_update_firmware_handles(void)
{
struct ehea_fw_handle_entry *arr = NULL;
@@ -241,7 +248,7 @@ static void ehea_update_bcmc_registrations(void)
}
if (num_registrations) {
- arr = kzalloc(num_registrations * sizeof(*arr), GFP_KERNEL);
+ arr = kzalloc(num_registrations * sizeof(*arr), GFP_ATOMIC);
if (!arr)
return; /* Keep the existing array */
} else
@@ -301,7 +308,7 @@ static struct net_device_stats *ehea_get_stats(struct net_device *dev)
memset(stats, 0, sizeof(*stats));
- cb2 = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ cb2 = kzalloc(PAGE_SIZE, GFP_ATOMIC);
if (!cb2) {
ehea_error("no mem for cb2");
goto out;
@@ -587,7 +594,7 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
"Resetting port.", pr->qp->init_attr.qp_nr);
ehea_dump(cqe, sizeof(*cqe), "CQE");
}
- schedule_work(&pr->port->reset_task);
+ ehea_schedule_port_reset(pr->port);
return 1;
}
@@ -616,7 +623,7 @@ static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
*tcph = tcp_hdr(skb);
/* check if ip header and tcp header are complete */
- if (iph->tot_len < ip_len + tcp_hdrlen(skb))
+ if (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb))
return -1;
*hdr_flags = LRO_IPV4 | LRO_TCP;
@@ -765,7 +772,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
ehea_error("Send Completion Error: Resetting port");
if (netif_msg_tx_err(pr->port))
ehea_dump(cqe, sizeof(*cqe), "Send CQE");
- schedule_work(&pr->port->reset_task);
+ ehea_schedule_port_reset(pr->port);
break;
}
@@ -885,7 +892,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
eqe = ehea_poll_eq(port->qp_eq);
}
- schedule_work(&port->reset_task);
+ ehea_schedule_port_reset(port);
return IRQ_HANDLED;
}
@@ -1763,25 +1770,29 @@ static int ehea_set_mac_addr(struct net_device *dev, void *sa)
memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len);
- mutex_lock(&ehea_bcmc_regs.lock);
+ spin_lock(&ehea_bcmc_regs.lock);
/* Deregister old MAC in pHYP */
- ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
- if (ret)
- goto out_upregs;
+ if (port->state == EHEA_PORT_UP) {
+ ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
+ if (ret)
+ goto out_upregs;
+ }
port->mac_addr = cb0->port_mac_addr << 16;
/* Register new MAC in pHYP */
- ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
- if (ret)
- goto out_upregs;
+ if (port->state == EHEA_PORT_UP) {
+ ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
+ if (ret)
+ goto out_upregs;
+ }
ret = 0;
out_upregs:
ehea_update_bcmc_registrations();
- mutex_unlock(&ehea_bcmc_regs.lock);
+ spin_unlock(&ehea_bcmc_regs.lock);
out_free:
kfree(cb0);
out:
@@ -1943,7 +1954,7 @@ static void ehea_set_multicast_list(struct net_device *dev)
}
ehea_promiscuous(dev, 0);
- mutex_lock(&ehea_bcmc_regs.lock);
+ spin_lock(&ehea_bcmc_regs.lock);
if (dev->flags & IFF_ALLMULTI) {
ehea_allmulti(dev, 1);
@@ -1974,7 +1985,7 @@ static void ehea_set_multicast_list(struct net_device *dev)
}
out:
ehea_update_bcmc_registrations();
- mutex_unlock(&ehea_bcmc_regs.lock);
+ spin_unlock(&ehea_bcmc_regs.lock);
return;
}
@@ -2213,8 +2224,6 @@ static void ehea_vlan_rx_register(struct net_device *dev,
goto out;
}
- memset(cb1->vlan_filter, 0, sizeof(cb1->vlan_filter));
-
hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
H_PORT_CB1, H_PORT_CB1_ALL, cb1);
if (hret != H_SUCCESS)
@@ -2495,7 +2504,7 @@ static int ehea_up(struct net_device *dev)
}
}
- mutex_lock(&ehea_bcmc_regs.lock);
+ spin_lock(&ehea_bcmc_regs.lock);
ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
if (ret) {
@@ -2518,7 +2527,7 @@ out:
ehea_info("Failed starting %s. ret=%i", dev->name, ret);
ehea_update_bcmc_registrations();
- mutex_unlock(&ehea_bcmc_regs.lock);
+ spin_unlock(&ehea_bcmc_regs.lock);
ehea_update_firmware_handles();
mutex_unlock(&ehea_fw_handles.lock);
@@ -2573,7 +2582,7 @@ static int ehea_down(struct net_device *dev)
mutex_lock(&ehea_fw_handles.lock);
- mutex_lock(&ehea_bcmc_regs.lock);
+ spin_lock(&ehea_bcmc_regs.lock);
ehea_drop_multicast_list(dev);
ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
@@ -2582,7 +2591,7 @@ static int ehea_down(struct net_device *dev)
port->state = EHEA_PORT_DOWN;
ehea_update_bcmc_registrations();
- mutex_unlock(&ehea_bcmc_regs.lock);
+ spin_unlock(&ehea_bcmc_regs.lock);
ret = ehea_clean_all_portres(port);
if (ret)
@@ -2603,12 +2612,14 @@ static int ehea_stop(struct net_device *dev)
if (netif_msg_ifdown(port))
ehea_info("disabling port %s", dev->name);
- flush_scheduled_work();
+ set_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);
+ cancel_work_sync(&port->reset_task);
mutex_lock(&port->port_lock);
netif_stop_queue(dev);
port_napi_disable(port);
ret = ehea_down(dev);
mutex_unlock(&port->port_lock);
+ clear_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);
return ret;
}
@@ -2938,7 +2949,7 @@ static void ehea_tx_watchdog(struct net_device *dev)
if (netif_carrier_ok(dev) &&
!test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
- schedule_work(&port->reset_task);
+ ehea_schedule_port_reset(port);
}
int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
@@ -3178,11 +3189,12 @@ out_err:
static void ehea_shutdown_single_port(struct ehea_port *port)
{
+ struct ehea_adapter *adapter = port->adapter;
unregister_netdev(port->netdev);
ehea_unregister_port(port);
kfree(port->mc_list);
free_netdev(port->netdev);
- port->adapter->active_ports--;
+ adapter->active_ports--;
}
static int ehea_setup_ports(struct ehea_adapter *adapter)
@@ -3586,7 +3598,7 @@ int __init ehea_module_init(void)
memset(&ehea_bcmc_regs, 0, sizeof(ehea_bcmc_regs));
mutex_init(&ehea_fw_handles.lock);
- mutex_init(&ehea_bcmc_regs.lock);
+ spin_lock_init(&ehea_bcmc_regs.lock);
ret = check_module_parm();
if (ret)
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index 46a90e9ec563..c05cb159c772 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -400,26 +400,31 @@ enc28j60_packet_write(struct enc28j60_net *priv, int len, const u8 *data)
mutex_unlock(&priv->lock);
}
-/*
- * Wait until the PHY operation is complete.
- */
-static int wait_phy_ready(struct enc28j60_net *priv)
+static unsigned long msec20_to_jiffies;
+
+static int poll_ready(struct enc28j60_net *priv, u8 reg, u8 mask, u8 val)
{
- unsigned long timeout = jiffies + 20 * HZ / 1000;
- int ret = 1;
+ unsigned long timeout = jiffies + msec20_to_jiffies;
/* 20 msec timeout read */
- while (nolock_regb_read(priv, MISTAT) & MISTAT_BUSY) {
+ while ((nolock_regb_read(priv, reg) & mask) != val) {
if (time_after(jiffies, timeout)) {
if (netif_msg_drv(priv))
- printk(KERN_DEBUG DRV_NAME
- ": PHY ready timeout!\n");
- ret = 0;
- break;
+ dev_dbg(&priv->spi->dev,
+ "reg %02x ready timeout!\n", reg);
+ return -ETIMEDOUT;
}
cpu_relax();
}
- return ret;
+ return 0;
+}
+
+/*
+ * Wait until the PHY operation is complete.
+ */
+static int wait_phy_ready(struct enc28j60_net *priv)
+{
+ return poll_ready(priv, MISTAT, MISTAT_BUSY, 0) ? 0 : 1;
}
/*
@@ -594,6 +599,32 @@ static void nolock_txfifo_init(struct enc28j60_net *priv, u16 start, u16 end)
nolock_regw_write(priv, ETXNDL, end);
}
+/*
+ * Low power mode shrinks power consumption about 100x, so we'd like
+ * the chip to be in that mode whenever it's inactive. (However, we
+ * can't stay in lowpower mode during suspend with WOL active.)
+ */
+static void enc28j60_lowpower(struct enc28j60_net *priv, bool is_low)
+{
+ if (netif_msg_drv(priv))
+ dev_dbg(&priv->spi->dev, "%s power...\n",
+ is_low ? "low" : "high");
+
+ mutex_lock(&priv->lock);
+ if (is_low) {
+ nolock_reg_bfclr(priv, ECON1, ECON1_RXEN);
+ poll_ready(priv, ESTAT, ESTAT_RXBUSY, 0);
+ poll_ready(priv, ECON1, ECON1_TXRTS, 0);
+ /* ECON2_VRPS was set during initialization */
+ nolock_reg_bfset(priv, ECON2, ECON2_PWRSV);
+ } else {
+ nolock_reg_bfclr(priv, ECON2, ECON2_PWRSV);
+ poll_ready(priv, ESTAT, ESTAT_CLKRDY, ESTAT_CLKRDY);
+ /* caller sets ECON1_RXEN */
+ }
+ mutex_unlock(&priv->lock);
+}
+
static int enc28j60_hw_init(struct enc28j60_net *priv)
{
u8 reg;
@@ -612,8 +643,8 @@ static int enc28j60_hw_init(struct enc28j60_net *priv)
priv->tx_retry_count = 0;
priv->max_pk_counter = 0;
priv->rxfilter = RXFILTER_NORMAL;
- /* enable address auto increment */
- nolock_regb_write(priv, ECON2, ECON2_AUTOINC);
+ /* enable address auto increment and voltage regulator powersave */
+ nolock_regb_write(priv, ECON2, ECON2_AUTOINC | ECON2_VRPS);
nolock_rxfifo_init(priv, RXSTART_INIT, RXEND_INIT);
nolock_txfifo_init(priv, TXSTART_INIT, TXEND_INIT);
@@ -690,7 +721,7 @@ static int enc28j60_hw_init(struct enc28j60_net *priv)
static void enc28j60_hw_enable(struct enc28j60_net *priv)
{
- /* enable interrutps */
+ /* enable interrupts */
if (netif_msg_hw(priv))
printk(KERN_DEBUG DRV_NAME ": %s() enabling interrupts.\n",
__FUNCTION__);
@@ -726,15 +757,12 @@ enc28j60_setlink(struct net_device *ndev, u8 autoneg, u16 speed, u8 duplex)
int ret = 0;
if (!priv->hw_enable) {
- if (autoneg == AUTONEG_DISABLE && speed == SPEED_10) {
+ /* link is in low power mode now; duplex setting
+ * will take effect on next enc28j60_hw_init().
+ */
+ if (autoneg == AUTONEG_DISABLE && speed == SPEED_10)
priv->full_duplex = (duplex == DUPLEX_FULL);
- if (!enc28j60_hw_init(priv)) {
- if (netif_msg_drv(priv))
- dev_err(&ndev->dev,
- "hw_reset() failed\n");
- ret = -EINVAL;
- }
- } else {
+ else {
if (netif_msg_link(priv))
dev_warn(&ndev->dev,
"unsupported link setting\n");
@@ -1307,7 +1335,8 @@ static int enc28j60_net_open(struct net_device *dev)
}
return -EADDRNOTAVAIL;
}
- /* Reset the hardware here */
+ /* Reset the hardware here (and take it out of low power mode) */
+ enc28j60_lowpower(priv, false);
enc28j60_hw_disable(priv);
if (!enc28j60_hw_init(priv)) {
if (netif_msg_ifup(priv))
@@ -1337,6 +1366,7 @@ static int enc28j60_net_close(struct net_device *dev)
printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
enc28j60_hw_disable(priv);
+ enc28j60_lowpower(priv, true);
netif_stop_queue(dev);
return 0;
@@ -1537,6 +1567,8 @@ static int __devinit enc28j60_probe(struct spi_device *spi)
dev->watchdog_timeo = TX_TIMEOUT;
SET_ETHTOOL_OPS(dev, &enc28j60_ethtool_ops);
+ enc28j60_lowpower(priv, true);
+
ret = register_netdev(dev);
if (ret) {
if (netif_msg_probe(priv))
@@ -1556,7 +1588,7 @@ error_alloc:
return ret;
}
-static int enc28j60_remove(struct spi_device *spi)
+static int __devexit enc28j60_remove(struct spi_device *spi)
{
struct enc28j60_net *priv = dev_get_drvdata(&spi->dev);
@@ -1573,15 +1605,16 @@ static int enc28j60_remove(struct spi_device *spi)
static struct spi_driver enc28j60_driver = {
.driver = {
.name = DRV_NAME,
- .bus = &spi_bus_type,
.owner = THIS_MODULE,
- },
+ },
.probe = enc28j60_probe,
.remove = __devexit_p(enc28j60_remove),
};
static int __init enc28j60_init(void)
{
+ msec20_to_jiffies = msecs_to_jiffies(20);
+
return spi_register_driver(&enc28j60_driver);
}
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index 5f9c42e7a7f1..329edd9c08fc 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -78,7 +78,7 @@ module_param_array_named(mac, mpc52xx_fec_mac_addr, byte, NULL, 0);
MODULE_PARM_DESC(mac, "six hex digits, ie. 0x1,0x2,0xc0,0x01,0xba,0xbe");
#define MPC52xx_MESSAGES_DEFAULT ( NETIF_MSG_DRV | NETIF_MSG_PROBE | \
- NETIF_MSG_LINK | NETIF_MSG_IFDOWN | NETIF_MSG_IFDOWN )
+ NETIF_MSG_LINK | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP)
static int debug = -1; /* the above default */
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "debugging messages level");
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 35f66d4a4595..20d4fe96a81c 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -3273,6 +3273,20 @@ static void nv_link_irq(struct net_device *dev)
dprintk(KERN_DEBUG "%s: link change notification done.\n", dev->name);
}
+static void nv_msi_workaround(struct fe_priv *np)
+{
+
+ /* Need to toggle the msi irq mask within the ethernet device,
+ * otherwise, future interrupts will not be detected.
+ */
+ if (np->msi_flags & NV_MSI_ENABLED) {
+ u8 __iomem *base = np->base;
+
+ writel(0, base + NvRegMSIIrqMask);
+ writel(NVREG_MSI_VECTOR_0_ENABLED, base + NvRegMSIIrqMask);
+ }
+}
+
static irqreturn_t nv_nic_irq(int foo, void *data)
{
struct net_device *dev = (struct net_device *) data;
@@ -3295,6 +3309,8 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
if (!(events & np->irqmask))
break;
+ nv_msi_workaround(np);
+
spin_lock(&np->lock);
nv_tx_done(dev);
spin_unlock(&np->lock);
@@ -3410,6 +3426,8 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
if (!(events & np->irqmask))
break;
+ nv_msi_workaround(np);
+
spin_lock(&np->lock);
nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
spin_unlock(&np->lock);
@@ -3750,6 +3768,8 @@ static irqreturn_t nv_nic_irq_test(int foo, void *data)
if (!(events & NVREG_IRQ_TIMER))
return IRQ_RETVAL(0);
+ nv_msi_workaround(np);
+
spin_lock(&np->lock);
np->intr_test = 1;
spin_unlock(&np->lock);
@@ -4174,12 +4194,23 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
netif_carrier_off(dev);
if (netif_running(dev)) {
+ unsigned long flags;
+
nv_disable_irq(dev);
netif_tx_lock_bh(dev);
- spin_lock(&np->lock);
+ /* with plain spinlock lockdep complains */
+ spin_lock_irqsave(&np->lock, flags);
/* stop engines */
+ /* FIXME:
+ * this can take some time, and interrupts are disabled
+ * due to spin_lock_irqsave, but let's hope no daemon
+ * is going to change the settings very often...
+ * Worst case:
+ * NV_RXSTOP_DELAY1MAX + NV_TXSTOP_DELAY1MAX
+ * + some minor delays, which is up to a second approximately
+ */
nv_stop_rxtx(dev);
- spin_unlock(&np->lock);
+ spin_unlock_irqrestore(&np->lock, flags);
netif_tx_unlock_bh(dev);
}
@@ -5823,6 +5854,7 @@ static int nv_resume(struct pci_dev *pdev)
writel(txreg, base + NvRegTransmitPoll);
rc = nv_open(dev);
+ nv_set_multicast(dev);
out:
return rc;
}
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 67b4b0728fce..a5baaf59ff66 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -1093,7 +1093,7 @@ err:
if (registered)
unregister_netdev(ndev);
- if (fep != NULL) {
+ if (fep && fep->ops) {
(*fep->ops->free_bd)(ndev);
(*fep->ops->cleanup_data)(ndev);
}
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index e36321152d50..8268b3535b30 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -463,6 +463,9 @@ static void restart(struct net_device *dev)
else
C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB);
+ /* Restore multicast and promiscuous settings */
+ set_multicast_list(dev);
+
S32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT);
}
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index dde9c7e6408a..00bc7fbb6b37 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -959,7 +959,7 @@ static int epp_close(struct net_device *dev)
unsigned char tmp[1];
bc->work_running = 0;
- flush_scheduled_work();
+ cancel_delayed_work_sync(&bc->run_work);
bc->stat = EPP_DCDBIT;
tmp[0] = 0;
pp->ops->epp_write_addr(pp, tmp, 1, 0);
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 0b94833e23f7..e8cfadefa4b6 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -1077,8 +1077,6 @@ static inline void rx_off(struct scc_priv *priv)
static void start_timer(struct scc_priv *priv, int t, int r15)
{
- unsigned long flags;
-
outb(priv->tmr_mode, priv->tmr_ctrl);
if (t == 0) {
tm_isr(priv);
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index f90515935833..45ae9d1191d7 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -1340,9 +1340,10 @@ static unsigned int scc_set_param(struct scc_channel *scc, unsigned int cmd, uns
case PARAM_RTS:
if ( !(scc->wreg[R5] & RTS) )
{
- if (arg != TX_OFF)
+ if (arg != TX_OFF) {
scc_key_trx(scc, TX_ON);
scc_start_tx_timer(scc, t_txdelay, scc->kiss.txdelay);
+ }
} else {
if (arg == TX_OFF)
{
diff --git a/drivers/net/ibm_newemac/Kconfig b/drivers/net/ibm_newemac/Kconfig
index 0d3e7380bad0..70a3272ee998 100644
--- a/drivers/net/ibm_newemac/Kconfig
+++ b/drivers/net/ibm_newemac/Kconfig
@@ -1,6 +1,7 @@
config IBM_NEW_EMAC
tristate "IBM EMAC Ethernet support"
depends on PPC_DCR && PPC_MERGE
+ select CRC32
help
This driver supports the IBM EMAC family of Ethernet controllers
typically found on 4xx embedded PowerPC chips, but also on the
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index 5d2108c5ac7c..babc79ad490b 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -1636,6 +1636,12 @@ static int emac_poll_rx(void *param, int budget)
goto next;
}
+ if (len < ETH_HLEN) {
+ ++dev->estats.rx_dropped_stack;
+ emac_recycle_rx_skb(dev, slot, len);
+ goto next;
+ }
+
if (len && len < EMAC_RX_COPY_THRESH) {
struct sk_buff *copy_skb =
alloc_skb(len + EMAC_RX_SKB_HEADROOM + 2, GFP_ATOMIC);
@@ -2719,6 +2725,8 @@ static int __devinit emac_probe(struct of_device *ofdev,
/* Clean rings */
memset(dev->tx_desc, 0, NUM_TX_BUFF * sizeof(struct mal_descriptor));
memset(dev->rx_desc, 0, NUM_RX_BUFF * sizeof(struct mal_descriptor));
+ memset(dev->tx_skb, 0, NUM_TX_BUFF * sizeof(struct sk_buff *));
+ memset(dev->rx_skb, 0, NUM_RX_BUFF * sizeof(struct sk_buff *));
/* Attach to ZMII, if needed */
if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII) &&
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index ae398f04c7b4..e79a26a886c8 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -718,7 +718,8 @@ void igb_down(struct igb_adapter *adapter)
adapter->link_speed = 0;
adapter->link_duplex = 0;
- igb_reset(adapter);
+ if (!pci_channel_offline(adapter->pdev))
+ igb_reset(adapter);
igb_clean_all_tx_rings(adapter);
igb_clean_all_rx_rings(adapter);
}
diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c
index 9b358f61ed7f..2c03f4e2ccc4 100644
--- a/drivers/net/ipg.c
+++ b/drivers/net/ipg.c
@@ -577,12 +577,12 @@ static void ipg_nic_set_multicast_list(struct net_device *dev)
/* NIC to be configured in promiscuous mode. */
receivemode = IPG_RM_RECEIVEALLFRAMES;
} else if ((dev->flags & IFF_ALLMULTI) ||
- (dev->flags & IFF_MULTICAST &
+ ((dev->flags & IFF_MULTICAST) &&
(dev->mc_count > IPG_MULTICAST_HASHTABLE_SIZE))) {
/* NIC to be configured to receive all multicast
* frames. */
receivemode |= IPG_RM_RECEIVEMULTICAST;
- } else if (dev->flags & IFF_MULTICAST & (dev->mc_count > 0)) {
+ } else if ((dev->flags & IFF_MULTICAST) && (dev->mc_count > 0)) {
/* NIC to be configured to receive selected
* multicast addresses. */
receivemode |= IPG_RM_RECEIVEMULTICASTHASH;
@@ -1271,7 +1271,7 @@ static void ipg_nic_rx_with_end(struct net_device *dev,
framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
- endframeLen = framelen - jumbo->current_size;
+ endframelen = framelen - jumbo->current_size;
/*
if (framelen > IPG_RXFRAG_SIZE)
framelen=IPG_RXFRAG_SIZE;
@@ -1279,8 +1279,8 @@ static void ipg_nic_rx_with_end(struct net_device *dev,
if (framelen > IPG_RXSUPPORT_SIZE)
dev_kfree_skb_irq(jumbo->skb);
else {
- memcpy(skb_put(jumbo->skb, endframeLen),
- skb->data, endframeLen);
+ memcpy(skb_put(jumbo->skb, endframelen),
+ skb->data, endframelen);
jumbo->skb->protocol =
eth_type_trans(jumbo->skb, dev);
@@ -1352,16 +1352,16 @@ static int ipg_nic_rx(struct net_device *dev)
switch (ipg_nic_rx_check_frame_type(dev)) {
case FRAME_WITH_START_WITH_END:
- ipg_nic_rx_with_start_and_end(dev, tp, rxfd, entry);
+ ipg_nic_rx_with_start_and_end(dev, sp, rxfd, entry);
break;
case FRAME_WITH_START:
- ipg_nic_rx_with_start(dev, tp, rxfd, entry);
+ ipg_nic_rx_with_start(dev, sp, rxfd, entry);
break;
case FRAME_WITH_END:
- ipg_nic_rx_with_end(dev, tp, rxfd, entry);
+ ipg_nic_rx_with_end(dev, sp, rxfd, entry);
break;
case FRAME_NO_START_NO_END:
- ipg_nic_rx_no_start_no_end(dev, tp, rxfd, entry);
+ ipg_nic_rx_no_start_no_end(dev, sp, rxfd, entry);
break;
}
}
@@ -1808,7 +1808,7 @@ static int ipg_nic_open(struct net_device *dev)
/* initialize JUMBO Frame control variable */
sp->jumbo.found_start = 0;
sp->jumbo.current_size = 0;
- sp->jumbo.skb = 0;
+ sp->jumbo.skb = NULL;
dev->mtu = IPG_TXFRAG_SIZE;
#endif
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index ce816ba9c40d..e6317557a531 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -329,6 +329,7 @@ config PXA_FICP
config MCS_FIR
tristate "MosChip MCS7780 IrDA-USB dongle"
depends on IRDA && USB && EXPERIMENTAL
+ select CRC32
help
Say Y or M here if you want to build support for the MosChip
MCS7780 IrDA-USB bridge device driver.
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 9081234ab458..6f50ed7b183f 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -1120,7 +1120,7 @@ static int stir421x_patch_device(struct irda_usb_cb *self)
}
}
- if (self->usbdev->descriptor.bcdDevice == fw_version) {
+ if (self->usbdev->descriptor.bcdDevice == cpu_to_le16(fw_version)) {
/*
* If we're here, we've found a correct patch
* The actual image starts after the "STMP" keyword
diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h
index e846c38224a3..a0ca9c1fe196 100644
--- a/drivers/net/irda/irda-usb.h
+++ b/drivers/net/irda/irda-usb.h
@@ -117,11 +117,11 @@
struct irda_class_desc {
__u8 bLength;
__u8 bDescriptorType;
- __u16 bcdSpecRevision;
+ __le16 bcdSpecRevision;
__u8 bmDataSize;
__u8 bmWindowSize;
__u8 bmMinTurnaroundTime;
- __u16 wBaudRate;
+ __le16 wBaudRate;
__u8 bmAdditionalBOFs;
__u8 bIrdaRateSniff;
__u8 bMaxUnicastList;
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index a7714da7c283..effc1ce8179a 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -152,6 +152,7 @@ static chipio_t pnp_info;
static const struct pnp_device_id nsc_ircc_pnp_table[] = {
{ .id = "NSC6001", .driver_data = 0 },
{ .id = "IBM0071", .driver_data = 0 },
+ { .id = "HWPC224", .driver_data = 0 },
{ }
};
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index 58e128784585..04ad3573b159 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -1546,6 +1546,7 @@ static int via_ircc_net_open(struct net_device *dev)
IRDA_WARNING("%s, unable to allocate dma2=%d\n",
driver_name, self->io.dma2);
free_irq(self->io.irq, self);
+ free_dma(self->io.dma);
return -EAGAIN;
}
}
@@ -1606,6 +1607,8 @@ static int via_ircc_net_close(struct net_device *dev)
EnAllInt(iobase, OFF);
free_irq(self->io.irq, dev);
free_dma(self->io.dma);
+ if (self->io.dma2 != self->io.dma)
+ free_dma(self->io.dma2);
return 0;
}
diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c
index 6321b059ce13..2f38e847e2cd 100644
--- a/drivers/net/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ixgbe/ixgbe_82598.c
@@ -58,8 +58,8 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw);
static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw)
{
- hw->mac.num_rx_queues = IXGBE_82598_MAX_TX_QUEUES;
- hw->mac.num_tx_queues = IXGBE_82598_MAX_RX_QUEUES;
+ hw->mac.num_rx_queues = IXGBE_82598_MAX_RX_QUEUES;
+ hw->mac.num_tx_queues = IXGBE_82598_MAX_TX_QUEUES;
hw->mac.num_rx_addrs = IXGBE_82598_RAR_ENTRIES;
/* PHY ops are filled in by default properly for Fiber only */
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 7b859220c255..8f0460901153 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -1969,7 +1969,8 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
netif_carrier_off(netdev);
netif_stop_queue(netdev);
- ixgbe_reset(adapter);
+ if (!pci_channel_offline(adapter->pdev))
+ ixgbe_reset(adapter);
ixgbe_clean_all_tx_rings(adapter);
ixgbe_clean_all_rx_rings(adapter);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index c91b12ea26ad..e0d76c75aea0 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -75,7 +75,7 @@
#include "myri10ge_mcp.h"
#include "myri10ge_mcp_gen_header.h"
-#define MYRI10GE_VERSION_STR "1.3.2-1.287"
+#define MYRI10GE_VERSION_STR "1.3.99-1.347"
MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
MODULE_AUTHOR("Maintainer: help@myri.com");
@@ -631,7 +631,7 @@ static int myri10ge_adopt_running_firmware(struct myri10ge_priv *mgp)
return status;
}
-int myri10ge_get_firmware_capabilities(struct myri10ge_priv *mgp)
+static int myri10ge_get_firmware_capabilities(struct myri10ge_priv *mgp)
{
struct myri10ge_cmd cmd;
int status;
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index 8cb29f5b1038..da4c4fb97064 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -776,7 +776,6 @@ struct netxen_hardware_context {
u8 revision_id;
u16 board_type;
- u16 max_ports;
struct netxen_board_info boardcfg;
u32 xg_linkup;
u32 qg_linksup;
@@ -863,6 +862,7 @@ struct netxen_adapter {
unsigned char mac_addr[ETH_ALEN];
int mtu;
int portnum;
+ u8 physical_port;
struct work_struct watchdog_task;
struct timer_list watchdog_timer;
@@ -1034,7 +1034,6 @@ int netxen_rom_se(struct netxen_adapter *adapter, int addr);
/* Functions from netxen_nic_isr.c */
void netxen_initialize_adapter_sw(struct netxen_adapter *adapter);
-void netxen_initialize_adapter_hw(struct netxen_adapter *adapter);
void *netxen_alloc(struct pci_dev *pdev, size_t sz, dma_addr_t * ptr,
struct pci_dev **used_dev);
void netxen_initialize_adapter_ops(struct netxen_adapter *adapter);
@@ -1077,20 +1076,6 @@ static const struct netxen_brdinfo netxen_boards[] = {
#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(netxen_boards)
-static inline void get_brd_port_by_type(u32 type, int *ports)
-{
- int i, found = 0;
- for (i = 0; i < NUM_SUPPORTED_BOARDS; ++i) {
- if (netxen_boards[i].brdtype == type) {
- *ports = netxen_boards[i].ports;
- found = 1;
- break;
- }
- }
- if (!found)
- *ports = 0;
-}
-
static inline void get_brd_name_by_type(u32 type, char *name)
{
int i, found = 0;
@@ -1169,5 +1154,4 @@ extern int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr,
extern struct ethtool_ops netxen_nic_ethtool_ops;
-extern int physical_port[]; /* physical port # from virtual port.*/
#endif /* __NETXEN_NIC_H_ */
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index 6e98d830eefb..723487bf200c 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -369,7 +369,7 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
for (i = 3; niu_registers[mode].reg[i - 3] != -1; i++) {
/* GB: port specific registers */
if (mode == 0 && i >= 19)
- window = physical_port[adapter->portnum] *
+ window = adapter->physical_port *
NETXEN_NIC_PORT_WINDOW;
NETXEN_NIC_LOCKED_READ_REG(niu_registers[mode].
@@ -527,7 +527,7 @@ netxen_nic_get_pauseparam(struct net_device *dev,
{
struct netxen_adapter *adapter = netdev_priv(dev);
__u32 val;
- int port = physical_port[adapter->portnum];
+ int port = adapter->physical_port;
if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
@@ -573,7 +573,7 @@ netxen_nic_set_pauseparam(struct net_device *dev,
{
struct netxen_adapter *adapter = netdev_priv(dev);
__u32 val;
- int port = physical_port[adapter->portnum];
+ int port = adapter->physical_port;
/* read mode */
if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index af7356468251..c43d06b8de9b 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -396,11 +396,8 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
}
adapter->intr_scheme = readl(
NETXEN_CRB_NORMALIZE(adapter, CRB_NIC_CAPABILITIES_FW));
- printk(KERN_NOTICE "%s: FW capabilities:0x%x\n", netxen_nic_driver_name,
- adapter->intr_scheme);
adapter->msi_mode = readl(
NETXEN_CRB_NORMALIZE(adapter, CRB_NIC_MSI_MODE_FW));
- DPRINTK(INFO, "Receive Peg ready too. starting stuff\n");
addr = netxen_alloc(adapter->ahw.pdev,
sizeof(struct netxen_ring_ctx) +
@@ -408,8 +405,6 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
(dma_addr_t *) & adapter->ctx_desc_phys_addr,
&adapter->ctx_desc_pdev);
- printk(KERN_INFO "ctx_desc_phys_addr: 0x%llx\n",
- (unsigned long long) adapter->ctx_desc_phys_addr);
if (addr == NULL) {
DPRINTK(ERR, "bad return from pci_alloc_consistent\n");
err = -ENOMEM;
@@ -429,8 +424,6 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
adapter->max_tx_desc_count,
(dma_addr_t *) & hw->cmd_desc_phys_addr,
&adapter->ahw.cmd_desc_pdev);
- printk(KERN_INFO "cmd_desc_phys_addr: 0x%llx\n",
- (unsigned long long) hw->cmd_desc_phys_addr);
if (addr == NULL) {
DPRINTK(ERR, "bad return from pci_alloc_consistent\n");
@@ -1032,15 +1025,15 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter)
int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu)
{
netxen_nic_write_w0(adapter,
- NETXEN_NIU_GB_MAX_FRAME_SIZE(
- physical_port[adapter->portnum]), new_mtu);
+ NETXEN_NIU_GB_MAX_FRAME_SIZE(adapter->physical_port),
+ new_mtu);
return 0;
}
int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu)
{
new_mtu += NETXEN_NIU_HDRSIZE + NETXEN_NIU_TLRSIZE;
- if (physical_port[adapter->portnum] == 0)
+ if (adapter->physical_port == 0)
netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE,
new_mtu);
else
@@ -1051,7 +1044,7 @@ int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu)
void netxen_nic_init_niu_gb(struct netxen_adapter *adapter)
{
- netxen_niu_gbe_init_port(adapter, physical_port[adapter->portnum]);
+ netxen_niu_gbe_init_port(adapter, adapter->physical_port);
}
void
@@ -1127,7 +1120,6 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter)
void netxen_nic_flash_print(struct netxen_adapter *adapter)
{
- int valid = 1;
u32 fw_major = 0;
u32 fw_minor = 0;
u32 fw_build = 0;
@@ -1137,70 +1129,62 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter)
__le32 *ptr32;
struct netxen_board_info *board_info = &(adapter->ahw.boardcfg);
- if (board_info->magic != NETXEN_BDINFO_MAGIC) {
- printk
- ("NetXen Unknown board config, Read 0x%x expected as 0x%x\n",
- board_info->magic, NETXEN_BDINFO_MAGIC);
- valid = 0;
- }
- if (board_info->header_version != NETXEN_BDINFO_VERSION) {
- printk("NetXen Unknown board config version."
- " Read %x, expected %x\n",
- board_info->header_version, NETXEN_BDINFO_VERSION);
- valid = 0;
- }
- if (valid) {
- ptr32 = (u32 *)&serial_num;
- addr = NETXEN_USER_START +
- offsetof(struct netxen_new_user_info, serial_num);
- for (i = 0; i < 8; i++) {
- if (netxen_rom_fast_read(adapter, addr, ptr32) == -1) {
- printk("%s: ERROR reading %s board userarea.\n",
- netxen_nic_driver_name,
- netxen_nic_driver_name);
- return;
- }
- ptr32++;
- addr += sizeof(u32);
+
+ adapter->driver_mismatch = 0;
+
+ ptr32 = (u32 *)&serial_num;
+ addr = NETXEN_USER_START +
+ offsetof(struct netxen_new_user_info, serial_num);
+ for (i = 0; i < 8; i++) {
+ if (netxen_rom_fast_read(adapter, addr, ptr32) == -1) {
+ printk("%s: ERROR reading %s board userarea.\n",
+ netxen_nic_driver_name,
+ netxen_nic_driver_name);
+ adapter->driver_mismatch = 1;
+ return;
}
+ ptr32++;
+ addr += sizeof(u32);
+ }
+
+ fw_major = readl(NETXEN_CRB_NORMALIZE(adapter,
+ NETXEN_FW_VERSION_MAJOR));
+ fw_minor = readl(NETXEN_CRB_NORMALIZE(adapter,
+ NETXEN_FW_VERSION_MINOR));
+ fw_build =
+ readl(NETXEN_CRB_NORMALIZE(adapter, NETXEN_FW_VERSION_SUB));
+ if (adapter->portnum == 0) {
get_brd_name_by_type(board_info->board_type, brd_name);
printk("NetXen %s Board S/N %s Chip id 0x%x\n",
- brd_name, serial_num, board_info->chip_id);
-
- printk("NetXen %s Board #%d, Chip id 0x%x\n",
- board_info->board_type == 0x0b ? "XGB" : "GBE",
- board_info->board_num, board_info->chip_id);
- fw_major = readl(NETXEN_CRB_NORMALIZE(adapter,
- NETXEN_FW_VERSION_MAJOR));
- fw_minor = readl(NETXEN_CRB_NORMALIZE(adapter,
- NETXEN_FW_VERSION_MINOR));
- fw_build =
- readl(NETXEN_CRB_NORMALIZE(adapter, NETXEN_FW_VERSION_SUB));
-
- printk("NetXen Firmware version %d.%d.%d\n", fw_major, fw_minor,
- fw_build);
+ brd_name, serial_num, board_info->chip_id);
+ printk("NetXen Firmware version %d.%d.%d\n", fw_major,
+ fw_minor, fw_build);
}
+
if (fw_major != _NETXEN_NIC_LINUX_MAJOR) {
- printk(KERN_ERR "The mismatch in driver version and firmware "
- "version major number\n"
- "Driver version major number = %d \t"
- "Firmware version major number = %d \n",
- _NETXEN_NIC_LINUX_MAJOR, fw_major);
adapter->driver_mismatch = 1;
}
if (fw_minor != _NETXEN_NIC_LINUX_MINOR &&
fw_minor != (_NETXEN_NIC_LINUX_MINOR + 1)) {
- printk(KERN_ERR "The mismatch in driver version and firmware "
- "version minor number\n"
- "Driver version minor number = %d \t"
- "Firmware version minor number = %d \n",
- _NETXEN_NIC_LINUX_MINOR, fw_minor);
adapter->driver_mismatch = 1;
}
- if (adapter->driver_mismatch)
- printk(KERN_INFO "Use the driver with version no %d.%d.xxx\n",
- fw_major, fw_minor);
+ if (adapter->driver_mismatch) {
+ printk(KERN_ERR "%s: driver and firmware version mismatch\n",
+ adapter->netdev->name);
+ return;
+ }
+
+ switch (adapter->ahw.board_type) {
+ case NETXEN_NIC_GBE:
+ dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n",
+ adapter->netdev->name);
+ break;
+ case NETXEN_NIC_XGBE:
+ dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n",
+ adapter->netdev->name);
+ break;
+ }
}
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 45fa33e0cb90..70d1b22ced22 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -203,21 +203,6 @@ void netxen_initialize_adapter_sw(struct netxen_adapter *adapter)
}
}
-void netxen_initialize_adapter_hw(struct netxen_adapter *adapter)
-{
- int ports = 0;
- struct netxen_board_info *board_info = &(adapter->ahw.boardcfg);
-
- if (netxen_nic_get_board_info(adapter) != 0)
- printk("%s: Error getting board config info.\n",
- netxen_nic_driver_name);
- get_brd_port_by_type(board_info->board_type, &ports);
- if (ports == 0)
- printk(KERN_ERR "%s: Unknown board type\n",
- netxen_nic_driver_name);
- adapter->ahw.max_ports = ports;
-}
-
void netxen_initialize_adapter_ops(struct netxen_adapter *adapter)
{
switch (adapter->ahw.board_type) {
@@ -765,18 +750,13 @@ int netxen_flash_unlock(struct netxen_adapter *adapter)
int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
{
- int addr, val, status;
+ int addr, val;
int n, i;
int init_delay = 0;
struct crb_addr_pair *buf;
u32 off;
/* resetall */
- status = netxen_nic_get_board_info(adapter);
- if (status)
- printk("%s: netxen_pinit_from_rom: Error getting board info\n",
- netxen_nic_driver_name);
-
netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_GLB_SW_RESET,
NETXEN_ROMBUS_RESET);
@@ -860,10 +840,10 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
netxen_nic_pci_change_crbwindow(adapter, 1);
}
if (init_delay == 1) {
- msleep(2000);
+ msleep(1000);
init_delay = 0;
}
- msleep(20);
+ msleep(1);
}
kfree(buf);
@@ -938,12 +918,28 @@ int netxen_initialize_adapter_offload(struct netxen_adapter *adapter)
void netxen_free_adapter_offload(struct netxen_adapter *adapter)
{
+ int i;
+
if (adapter->dummy_dma.addr) {
- pci_free_consistent(adapter->ahw.pdev,
+ i = 100;
+ do {
+ if (dma_watchdog_shutdown_request(adapter) == 1)
+ break;
+ msleep(50);
+ if (dma_watchdog_shutdown_poll_result(adapter) == 1)
+ break;
+ } while (--i);
+
+ if (i) {
+ pci_free_consistent(adapter->ahw.pdev,
NETXEN_HOST_DUMMY_DMA_SIZE,
adapter->dummy_dma.addr,
adapter->dummy_dma.phys_addr);
- adapter->dummy_dma.addr = NULL;
+ adapter->dummy_dma.addr = NULL;
+ } else {
+ printk(KERN_ERR "%s: dma_watchdog_shutdown failed\n",
+ adapter->netdev->name);
+ }
}
}
diff --git a/drivers/net/netxen/netxen_nic_isr.c b/drivers/net/netxen/netxen_nic_isr.c
index f487615f4063..96cec41f9019 100644
--- a/drivers/net/netxen/netxen_nic_isr.c
+++ b/drivers/net/netxen/netxen_nic_isr.c
@@ -145,7 +145,7 @@ static void netxen_nic_isr_other(struct netxen_adapter *adapter)
/* verify the offset */
val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
- val = val >> physical_port[adapter->portnum];
+ val = val >> adapter->physical_port;
if (val == adapter->ahw.qg_linksup)
return;
@@ -199,7 +199,7 @@ void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter)
/* WINDOW = 1 */
val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
- val >>= (physical_port[adapter->portnum] * 8);
+ val >>= (adapter->physical_port * 8);
val &= 0xff;
if (adapter->ahw.xg_linkup == 1 && val != XG_LINK_UP) {
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 7144c255ce54..63cd67b931e7 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -70,17 +70,19 @@ static void netxen_nic_poll_controller(struct net_device *netdev);
static irqreturn_t netxen_intr(int irq, void *data);
static irqreturn_t netxen_msi_intr(int irq, void *data);
-int physical_port[] = {0, 1, 2, 3};
-
/* PCI Device ID Table */
+#define ENTRY(device) \
+ {PCI_DEVICE(0x4040, (device)), \
+ .class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0}
+
static struct pci_device_id netxen_pci_tbl[] __devinitdata = {
- {PCI_DEVICE(0x4040, 0x0001)},
- {PCI_DEVICE(0x4040, 0x0002)},
- {PCI_DEVICE(0x4040, 0x0003)},
- {PCI_DEVICE(0x4040, 0x0004)},
- {PCI_DEVICE(0x4040, 0x0005)},
- {PCI_DEVICE(0x4040, 0x0024)},
- {PCI_DEVICE(0x4040, 0x0025)},
+ ENTRY(0x0001),
+ ENTRY(0x0002),
+ ENTRY(0x0003),
+ ENTRY(0x0004),
+ ENTRY(0x0005),
+ ENTRY(0x0024),
+ ENTRY(0x0025),
{0,}
};
@@ -288,10 +290,11 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
int pci_func_id = PCI_FUNC(pdev->devfn);
DECLARE_MAC_BUF(mac);
- printk(KERN_INFO "%s \n", netxen_nic_driver_string);
+ if (pci_func_id == 0)
+ printk(KERN_INFO "%s \n", netxen_nic_driver_string);
if (pdev->class != 0x020000) {
- printk(KERN_ERR"NetXen function %d, class %x will not "
+ printk(KERN_DEBUG "NetXen function %d, class %x will not "
"be enabled.\n",pci_func_id, pdev->class);
return -ENODEV;
}
@@ -450,8 +453,12 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
*/
adapter->curr_window = 255;
- /* initialize the adapter */
- netxen_initialize_adapter_hw(adapter);
+ if (netxen_nic_get_board_info(adapter) != 0) {
+ printk("%s: Error getting board config info.\n",
+ netxen_nic_driver_name);
+ err = -EIO;
+ goto err_out_iounmap;
+ }
/*
* Adapter in our case is quad port so initialize it before
@@ -530,17 +537,15 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netxen_initialize_adapter_sw(adapter); /* initialize the buffers in adapter */
/* Mezz cards have PCI function 0,2,3 enabled */
- if ((adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ)
- && (pci_func_id >= 2))
+ switch (adapter->ahw.boardcfg.board_type) {
+ case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ:
+ case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ:
+ if (pci_func_id >= 2)
adapter->portnum = pci_func_id - 2;
-
-#ifdef CONFIG_IA64
- if(adapter->portnum == 0) {
- netxen_pinit_from_rom(adapter, 0);
- udelay(500);
- netxen_load_firmware(adapter);
+ break;
+ default:
+ break;
}
-#endif
init_timer(&adapter->watchdog_timer);
adapter->ahw.xg_linkup = 0;
@@ -613,11 +618,18 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = -ENODEV;
goto err_out_free_dev;
}
+ } else {
+ writel(0, NETXEN_CRB_NORMALIZE(adapter,
+ CRB_CMDPEG_STATE));
+ netxen_pinit_from_rom(adapter, 0);
+ msleep(1);
+ netxen_load_firmware(adapter);
+ netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
}
/* clear the register for future unloads/loads */
writel(0, NETXEN_CRB_NORMALIZE(adapter, NETXEN_CAM_RAM(0x1fc)));
- printk(KERN_INFO "State: 0x%0x\n",
+ dev_info(&pdev->dev, "cmdpeg state: 0x%0x\n",
readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)));
/*
@@ -639,9 +651,10 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/*
* See if the firmware gave us a virtual-physical port mapping.
*/
+ adapter->physical_port = adapter->portnum;
i = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_V2P(adapter->portnum)));
if (i != 0x55555555)
- physical_port[adapter->portnum] = i;
+ adapter->physical_port = i;
netif_carrier_off(netdev);
netif_stop_queue(netdev);
@@ -654,22 +667,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_free_dev;
}
+ netxen_nic_flash_print(adapter);
pci_set_drvdata(pdev, adapter);
- switch (adapter->ahw.board_type) {
- case NETXEN_NIC_GBE:
- printk(KERN_INFO "%s: QUAD GbE board initialized\n",
- netxen_nic_driver_name);
- break;
-
- case NETXEN_NIC_XGBE:
- printk(KERN_INFO "%s: XGbE board initialized\n",
- netxen_nic_driver_name);
- break;
- }
-
- adapter->driver_mismatch = 0;
-
return 0;
err_out_free_dev:
@@ -760,55 +760,8 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
vfree(adapter->cmd_buf_arr);
- if (adapter->portnum == 0) {
- if (init_firmware_done) {
- i = 100;
- do {
- if (dma_watchdog_shutdown_request(adapter) == 1)
- break;
- msleep(100);
- if (dma_watchdog_shutdown_poll_result(adapter) == 1)
- break;
- } while (--i);
-
- if (i == 0)
- printk(KERN_ERR "%s: dma_watchdog_shutdown failed\n",
- netdev->name);
-
- /* clear the register for future unloads/loads */
- writel(0, NETXEN_CRB_NORMALIZE(adapter, NETXEN_CAM_RAM(0x1fc)));
- printk(KERN_INFO "State: 0x%0x\n",
- readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)));
-
- /* leave the hw in the same state as reboot */
- writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
- netxen_pinit_from_rom(adapter, 0);
- msleep(1);
- netxen_load_firmware(adapter);
- netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
- }
-
- /* clear the register for future unloads/loads */
- writel(0, NETXEN_CRB_NORMALIZE(adapter, NETXEN_CAM_RAM(0x1fc)));
- printk(KERN_INFO "State: 0x%0x\n",
- readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)));
-
- i = 100;
- do {
- if (dma_watchdog_shutdown_request(adapter) == 1)
- break;
- msleep(100);
- if (dma_watchdog_shutdown_poll_result(adapter) == 1)
- break;
- } while (--i);
-
- if (i) {
- netxen_free_adapter_offload(adapter);
- } else {
- printk(KERN_ERR "%s: dma_watchdog_shutdown failed\n",
- netdev->name);
- }
- }
+ if (adapter->portnum == 0)
+ netxen_free_adapter_offload(adapter);
if (adapter->irq)
free_irq(adapter->irq, adapter);
@@ -840,13 +793,15 @@ static int netxen_nic_open(struct net_device *netdev)
irq_handler_t handler;
unsigned long flags = IRQF_SAMPLE_RANDOM;
+ if (adapter->driver_mismatch)
+ return -EIO;
+
if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) {
err = netxen_init_firmware(adapter);
if (err != 0) {
printk(KERN_ERR "Failed to init firmware\n");
return -EIO;
}
- netxen_nic_flash_print(adapter);
/* setup all the resources for the Phantom... */
/* this include the descriptors for rcv, tx, and status */
@@ -895,14 +850,12 @@ static int netxen_nic_open(struct net_device *netdev)
if (adapter->set_mtu)
adapter->set_mtu(adapter, netdev->mtu);
- if (!adapter->driver_mismatch)
- mod_timer(&adapter->watchdog_timer, jiffies);
+ mod_timer(&adapter->watchdog_timer, jiffies);
napi_enable(&adapter->napi);
netxen_nic_enable_int(adapter);
- if (!adapter->driver_mismatch)
- netif_start_queue(netdev);
+ netif_start_queue(netdev);
return 0;
}
diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c
index 1c852a76c80d..a3bc7cc67a6f 100644
--- a/drivers/net/netxen/netxen_nic_niu.c
+++ b/drivers/net/netxen/netxen_nic_niu.c
@@ -94,7 +94,7 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg,
long timeout = 0;
long result = 0;
long restore = 0;
- long phy = physical_port[adapter->portnum];
+ long phy = adapter->physical_port;
__u32 address;
__u32 command;
__u32 status;
@@ -190,7 +190,7 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg,
long timeout = 0;
long result = 0;
long restore = 0;
- long phy = physical_port[adapter->portnum];
+ long phy = adapter->physical_port;
__u32 address;
__u32 command;
__u32 status;
@@ -456,7 +456,7 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port)
int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port)
{
- u32 portnum = physical_port[adapter->portnum];
+ u32 portnum = adapter->physical_port;
netxen_crb_writelit_adapter(adapter,
NETXEN_NIU_XGE_CONFIG_1+(0x10000*portnum), 0x1447);
@@ -573,7 +573,7 @@ static int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
{
u32 stationhigh;
u32 stationlow;
- int phy = physical_port[adapter->portnum];
+ int phy = adapter->physical_port;
u8 val[8];
if (addr == NULL)
@@ -604,7 +604,7 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter,
{
u8 temp[4];
u32 val;
- int phy = physical_port[adapter->portnum];
+ int phy = adapter->physical_port;
unsigned char mac_addr[6];
int i;
DECLARE_MAC_BUF(mac);
@@ -724,7 +724,7 @@ int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter,
int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter)
{
__u32 mac_cfg0;
- u32 port = physical_port[adapter->portnum];
+ u32 port = adapter->physical_port;
if (port > NETXEN_NIU_MAX_GBE_PORTS)
return -EINVAL;
@@ -740,7 +740,7 @@ int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter)
int netxen_niu_disable_xg_port(struct netxen_adapter *adapter)
{
__u32 mac_cfg;
- u32 port = physical_port[adapter->portnum];
+ u32 port = adapter->physical_port;
if (port > NETXEN_NIU_MAX_XG_PORTS)
return -EINVAL;
@@ -757,7 +757,7 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter,
netxen_niu_prom_mode_t mode)
{
__u32 reg;
- u32 port = physical_port[adapter->portnum];
+ u32 port = adapter->physical_port;
if (port > NETXEN_NIU_MAX_GBE_PORTS)
return -EINVAL;
@@ -814,7 +814,7 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter,
int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter,
netxen_ethernet_macaddr_t addr)
{
- int phy = physical_port[adapter->portnum];
+ int phy = adapter->physical_port;
u8 temp[4];
u32 val;
@@ -867,7 +867,7 @@ int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter,
int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter,
netxen_ethernet_macaddr_t * addr)
{
- int phy = physical_port[adapter->portnum];
+ int phy = adapter->physical_port;
u32 stationhigh;
u32 stationlow;
u8 val[8];
@@ -896,7 +896,7 @@ int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter,
netxen_niu_prom_mode_t mode)
{
__u32 reg;
- u32 port = physical_port[adapter->portnum];
+ u32 port = adapter->physical_port;
if (port > NETXEN_NIU_MAX_XG_PORTS)
return -EINVAL;
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index 3b2a6c598088..993d87c9296f 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -277,7 +277,7 @@ static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
*tcph = tcp_hdr(skb);
/* check if ip header and tcp header are complete */
- if (iph->tot_len < ip_len + tcp_hdrlen(skb))
+ if (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb))
return -1;
*hdr_flags = LRO_IPV4 | LRO_TCP;
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index ce95c5d168fe..70d012e90dcf 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -525,12 +525,14 @@ static int axnet_open(struct net_device *dev)
int ret;
axnet_dev_t *info = PRIV(dev);
struct pcmcia_device *link = info->p_dev;
+ unsigned int nic_base = dev->base_addr;
DEBUG(2, "axnet_open('%s')\n", dev->name);
if (!pcmcia_dev_present(link))
return -ENODEV;
+ outb_p(0xFF, nic_base + EN0_ISR); /* Clear bogus intr. */
ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, "axnet_cs", dev);
if (ret)
return ret;
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 8f328a03847b..a550c9bd126f 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -391,7 +391,9 @@ static int fmvj18x_config(struct pcmcia_device *link)
cardtype = CONTEC;
break;
case MANFID_FUJITSU:
- if (link->card_id == PRODID_FUJITSU_MBH10302)
+ if (link->conf.ConfigBase == 0x0fe0)
+ cardtype = MBH10302;
+ else if (link->card_id == PRODID_FUJITSU_MBH10302)
/* RATOC REX-5588/9822/4886's PRODID are 0004(=MBH10302),
but these are MBH10304 based card. */
cardtype = MBH10304;
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index fd8158a86f64..2d4c4ad89b8d 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -969,6 +969,7 @@ static int pcnet_open(struct net_device *dev)
int ret;
pcnet_dev_t *info = PRIV(dev);
struct pcmcia_device *link = info->p_dev;
+ unsigned int nic_base = dev->base_addr;
DEBUG(2, "pcnet_open('%s')\n", dev->name);
@@ -976,6 +977,8 @@ static int pcnet_open(struct net_device *dev)
return -ENODEV;
set_misc_reg(dev);
+
+ outb_p(0xFF, nic_base + EN0_ISR); /* Clear bogus intr. */
ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, dev_info, dev);
if (ret)
return ret;
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index d041f831a18d..f6c4698ce738 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -1461,22 +1461,25 @@ static void
set_multicast_list(struct net_device *dev)
{
unsigned int ioaddr = dev->base_addr;
+ unsigned value;
SelectPage(0x42);
+ value = GetByte(XIRCREG42_SWC1) & 0xC0;
+
if (dev->flags & IFF_PROMISC) { /* snoop */
- PutByte(XIRCREG42_SWC1, 0x06); /* set MPE and PME */
+ PutByte(XIRCREG42_SWC1, value | 0x06); /* set MPE and PME */
} else if (dev->mc_count > 9 || (dev->flags & IFF_ALLMULTI)) {
- PutByte(XIRCREG42_SWC1, 0x02); /* set MPE */
+ PutByte(XIRCREG42_SWC1, value | 0x02); /* set MPE */
} else if (dev->mc_count) {
/* the chip can filter 9 addresses perfectly */
- PutByte(XIRCREG42_SWC1, 0x01);
+ PutByte(XIRCREG42_SWC1, value | 0x01);
SelectPage(0x40);
PutByte(XIRCREG40_CMD0, Offline);
set_addresses(dev);
SelectPage(0x40);
PutByte(XIRCREG40_CMD0, EnableRecv | Online);
} else { /* standard usage */
- PutByte(XIRCREG42_SWC1, 0x00);
+ PutByte(XIRCREG42_SWC1, value | 0x00);
}
SelectPage(0);
}
@@ -1722,6 +1725,7 @@ do_reset(struct net_device *dev, int full)
/* enable receiver and put the mac online */
if (full) {
+ set_multicast_list(dev);
SelectPage(0x40);
PutByte(XIRCREG40_CMD0, EnableRecv | Online);
}
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index a1c454dbc164..1c89b97f4e09 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -325,7 +325,7 @@ static int pcnet32_get_regs_len(struct net_device *dev);
static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
void *ptr);
static void pcnet32_purge_tx_ring(struct net_device *dev);
-static int pcnet32_alloc_ring(struct net_device *dev, char *name);
+static int pcnet32_alloc_ring(struct net_device *dev, const char *name);
static void pcnet32_free_ring(struct net_device *dev);
static void pcnet32_check_media(struct net_device *dev, int verbose);
@@ -1983,7 +1983,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
}
/* if any allocation fails, caller must also call pcnet32_free_ring */
-static int pcnet32_alloc_ring(struct net_device *dev, char *name)
+static int pcnet32_alloc_ring(struct net_device *dev, const char *name)
{
struct pcnet32_private *lp = netdev_priv(dev);
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 6bf9e76b0a00..6eb2d31d1e34 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -5,7 +5,7 @@
menuconfig PHYLIB
tristate "PHY Device support and infrastructure"
depends on !S390
- depends on NET_ETHERNET && (BROKEN || !S390)
+ depends on NET_ETHERNET
help
Ethernet controllers are usually attached to PHY
devices. This option provides infrastructure for
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index ac3c01d28fdf..16a0e7de5888 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -207,6 +207,7 @@ int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id)
return 0;
}
+EXPORT_SYMBOL(get_phy_id);
/**
* get_phy_device - reads the specified PHY device and returns its @phy_device struct
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 58a26a47af29..fc6f4b8c64b3 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -341,12 +341,6 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
struct pppox_sock *relay_po;
if (sk->sk_state & PPPOX_BOUND) {
- struct pppoe_hdr *ph = pppoe_hdr(skb);
- int len = ntohs(ph->length);
- skb_pull_rcsum(skb, sizeof(struct pppoe_hdr));
- if (pskb_trim_rcsum(skb, len))
- goto abort_kfree;
-
ppp_input(&po->chan, skb);
} else if (sk->sk_state & PPPOX_RELAY) {
relay_po = get_item_by_addr(&po->pppoe_relay);
@@ -357,7 +351,6 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
if ((sk_pppox(relay_po)->sk_state & PPPOX_CONNECTED) == 0)
goto abort_put;
- skb_pull(skb, sizeof(struct pppoe_hdr));
if (!__pppoe_xmit(sk_pppox(relay_po), skb))
goto abort_put;
} else {
@@ -388,6 +381,7 @@ static int pppoe_rcv(struct sk_buff *skb,
{
struct pppoe_hdr *ph;
struct pppox_sock *po;
+ int len;
if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
goto out;
@@ -399,10 +393,21 @@ static int pppoe_rcv(struct sk_buff *skb,
goto drop;
ph = pppoe_hdr(skb);
+ len = ntohs(ph->length);
+
+ skb_pull_rcsum(skb, sizeof(*ph));
+ if (skb->len < len)
+ goto drop;
po = get_item(ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
- if (po != NULL)
- return sk_receive_skb(sk_pppox(po), skb, 0);
+ if (!po)
+ goto drop;
+
+ if (pskb_trim_rcsum(skb, len))
+ goto drop;
+
+ return sk_receive_skb(sk_pppox(po), skb, 0);
+
drop:
kfree_skb(skb);
out:
@@ -427,12 +432,12 @@ static int pppoe_disc_rcv(struct sk_buff *skb,
if (dev_net(dev) != &init_net)
goto abort;
- if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
- goto abort;
-
if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
goto out;
+ if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
+ goto abort;
+
ph = pppoe_hdr(skb);
if (ph->code != PADT_CODE)
goto abort;
@@ -937,12 +942,10 @@ static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock,
m->msg_namelen = 0;
if (skb) {
- struct pppoe_hdr *ph = pppoe_hdr(skb);
- const int len = ntohs(ph->length);
-
- error = memcpy_toiovec(m->msg_iov, (unsigned char *) &ph->tag[0], len);
+ total_len = min_t(size_t, total_len, skb->len);
+ error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len);
if (error == 0)
- error = len;
+ error = total_len;
}
kfree_skb(skb);
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index 79359919335b..f9298827a76c 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -240,12 +240,15 @@ static inline struct pppol2tp_session *pppol2tp_sock_to_session(struct sock *sk)
if (sk == NULL)
return NULL;
+ sock_hold(sk);
session = (struct pppol2tp_session *)(sk->sk_user_data);
- if (session == NULL)
- return NULL;
+ if (session == NULL) {
+ sock_put(sk);
+ goto out;
+ }
BUG_ON(session->magic != L2TP_SESSION_MAGIC);
-
+out:
return session;
}
@@ -256,12 +259,15 @@ static inline struct pppol2tp_tunnel *pppol2tp_sock_to_tunnel(struct sock *sk)
if (sk == NULL)
return NULL;
+ sock_hold(sk);
tunnel = (struct pppol2tp_tunnel *)(sk->sk_user_data);
- if (tunnel == NULL)
- return NULL;
+ if (tunnel == NULL) {
+ sock_put(sk);
+ goto out;
+ }
BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC);
-
+out:
return tunnel;
}
@@ -716,12 +722,14 @@ discard:
session->stats.rx_errors++;
kfree_skb(skb);
sock_put(session->sock);
+ sock_put(sock);
return 0;
error:
/* Put UDP header back */
__skb_push(skb, sizeof(struct udphdr));
+ sock_put(sock);
no_tunnel:
return 1;
@@ -745,10 +753,13 @@ static int pppol2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
"%s: received %d bytes\n", tunnel->name, skb->len);
if (pppol2tp_recv_core(sk, skb))
- goto pass_up;
+ goto pass_up_put;
+ sock_put(sk);
return 0;
+pass_up_put:
+ sock_put(sk);
pass_up:
return 1;
}
@@ -772,14 +783,18 @@ static int pppol2tp_recvmsg(struct kiocb *iocb, struct socket *sock,
err = 0;
skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
flags & MSG_DONTWAIT, &err);
- if (skb) {
- err = memcpy_toiovec(msg->msg_iov, (unsigned char *) skb->data,
- skb->len);
- if (err < 0)
- goto do_skb_free;
- err = skb->len;
- }
-do_skb_free:
+ if (!skb)
+ goto end;
+
+ if (len > skb->len)
+ len = skb->len;
+ else if (len < skb->len)
+ msg->msg_flags |= MSG_TRUNC;
+
+ err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len);
+ if (likely(err == 0))
+ err = len;
+
kfree_skb(skb);
end:
return err;
@@ -858,7 +873,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);
if (tunnel == NULL)
- goto error;
+ goto error_put_sess;
/* What header length is configured for this session? */
hdr_len = pppol2tp_l2tp_header_len(session);
@@ -870,7 +885,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
sizeof(ppph) + total_len,
0, GFP_KERNEL);
if (!skb)
- goto error;
+ goto error_put_sess_tun;
/* Reserve space for headers. */
skb_reserve(skb, NET_SKB_PAD);
@@ -900,7 +915,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
error = memcpy_fromiovec(skb->data, m->msg_iov, total_len);
if (error < 0) {
kfree_skb(skb);
- goto error;
+ goto error_put_sess_tun;
}
skb_put(skb, total_len);
@@ -947,10 +962,33 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
session->stats.tx_errors++;
}
+ return error;
+
+error_put_sess_tun:
+ sock_put(session->tunnel_sock);
+error_put_sess:
+ sock_put(sk);
error:
return error;
}
+/* Automatically called when the skb is freed.
+ */
+static void pppol2tp_sock_wfree(struct sk_buff *skb)
+{
+ sock_put(skb->sk);
+}
+
+/* For data skbs that we transmit, we associate with the tunnel socket
+ * but don't do accounting.
+ */
+static inline void pppol2tp_skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
+{
+ sock_hold(sk);
+ skb->sk = sk;
+ skb->destructor = pppol2tp_sock_wfree;
+}
+
/* Transmit function called by generic PPP driver. Sends PPP frame
* over PPPoL2TP socket.
*
@@ -980,6 +1018,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
__wsum csum = 0;
struct udphdr *uh;
unsigned int len;
+ int old_headroom;
+ int new_headroom;
if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
goto abort;
@@ -991,25 +1031,27 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
sk_tun = session->tunnel_sock;
if (sk_tun == NULL)
- goto abort;
+ goto abort_put_sess;
tunnel = pppol2tp_sock_to_tunnel(sk_tun);
if (tunnel == NULL)
- goto abort;
+ goto abort_put_sess;
/* What header length is configured for this session? */
hdr_len = pppol2tp_l2tp_header_len(session);
/* Check that there's enough headroom in the skb to insert IP,
* UDP and L2TP and PPP headers. If not enough, expand it to
- * make room. Note that a new skb (or a clone) is
- * allocated. If we return an error from this point on, make
- * sure we free the new skb but do not free the original skb
- * since that is done by the caller for the error case.
+ * make room. Adjust truesize.
*/
headroom = NET_SKB_PAD + sizeof(struct iphdr) +
sizeof(struct udphdr) + hdr_len + sizeof(ppph);
+ old_headroom = skb_headroom(skb);
if (skb_cow_head(skb, headroom))
- goto abort;
+ goto abort_put_sess_tun;
+
+ new_headroom = skb_headroom(skb);
+ skb_orphan(skb);
+ skb->truesize += new_headroom - old_headroom;
/* Setup PPP header */
__skb_push(skb, sizeof(ppph));
@@ -1065,8 +1107,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
/* Get routing info from the tunnel socket */
dst_release(skb->dst);
skb->dst = dst_clone(__sk_dst_get(sk_tun));
- skb_orphan(skb);
- skb->sk = sk_tun;
+ pppol2tp_skb_set_owner_w(skb, sk_tun);
/* Queue the packet to IP for output */
len = skb->len;
@@ -1083,8 +1124,14 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
session->stats.tx_errors++;
}
+ sock_put(sk_tun);
+ sock_put(sk);
return 1;
+abort_put_sess_tun:
+ sock_put(sk_tun);
+abort_put_sess:
+ sock_put(sk);
abort:
/* Free the original skb */
kfree_skb(skb);
@@ -1188,7 +1235,7 @@ static void pppol2tp_tunnel_destruct(struct sock *sk)
{
struct pppol2tp_tunnel *tunnel;
- tunnel = pppol2tp_sock_to_tunnel(sk);
+ tunnel = sk->sk_user_data;
if (tunnel == NULL)
goto end;
@@ -1227,10 +1274,12 @@ static void pppol2tp_session_destruct(struct sock *sk)
if (sk->sk_user_data != NULL) {
struct pppol2tp_tunnel *tunnel;
- session = pppol2tp_sock_to_session(sk);
+ session = sk->sk_user_data;
if (session == NULL)
goto out;
+ BUG_ON(session->magic != L2TP_SESSION_MAGIC);
+
/* Don't use pppol2tp_sock_to_tunnel() here to
* get the tunnel context because the tunnel
* socket might have already been closed (its
@@ -1276,6 +1325,7 @@ out:
static int pppol2tp_release(struct socket *sock)
{
struct sock *sk = sock->sk;
+ struct pppol2tp_session *session;
int error;
if (!sk)
@@ -1293,9 +1343,18 @@ static int pppol2tp_release(struct socket *sock)
sock_orphan(sk);
sock->sk = NULL;
+ session = pppol2tp_sock_to_session(sk);
+
/* Purge any queued data */
skb_queue_purge(&sk->sk_receive_queue);
skb_queue_purge(&sk->sk_write_queue);
+ if (session != NULL) {
+ struct sk_buff *skb;
+ while ((skb = skb_dequeue(&session->reorder_q))) {
+ kfree_skb(skb);
+ sock_put(sk);
+ }
+ }
release_sock(sk);
@@ -1598,7 +1657,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
error = ppp_register_channel(&po->chan);
if (error)
- goto end;
+ goto end_put_tun;
/* This is how we get the session context from the socket. */
sk->sk_user_data = session;
@@ -1618,6 +1677,8 @@ out_no_ppp:
PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
"%s: created\n", session->name);
+end_put_tun:
+ sock_put(tunnel_sock);
end:
release_sock(sk);
@@ -1665,6 +1726,7 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
*usockaddr_len = len;
error = 0;
+ sock_put(sock->sk);
end:
return error;
@@ -1903,14 +1965,17 @@ static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
err = -EBADF;
tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);
if (tunnel == NULL)
- goto end;
+ goto end_put_sess;
err = pppol2tp_tunnel_ioctl(tunnel, cmd, arg);
- goto end;
+ sock_put(session->tunnel_sock);
+ goto end_put_sess;
}
err = pppol2tp_session_ioctl(session, cmd, arg);
+end_put_sess:
+ sock_put(sk);
end:
return err;
}
@@ -2056,14 +2121,17 @@ static int pppol2tp_setsockopt(struct socket *sock, int level, int optname,
err = -EBADF;
tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);
if (tunnel == NULL)
- goto end;
+ goto end_put_sess;
err = pppol2tp_tunnel_setsockopt(sk, tunnel, optname, val);
+ sock_put(session->tunnel_sock);
} else
err = pppol2tp_session_setsockopt(sk, session, optname, val);
err = 0;
+end_put_sess:
+ sock_put(sk);
end:
return err;
}
@@ -2178,20 +2246,24 @@ static int pppol2tp_getsockopt(struct socket *sock, int level,
err = -EBADF;
tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);
if (tunnel == NULL)
- goto end;
+ goto end_put_sess;
err = pppol2tp_tunnel_getsockopt(sk, tunnel, optname, &val);
+ sock_put(session->tunnel_sock);
} else
err = pppol2tp_session_getsockopt(sk, session, optname, &val);
err = -EFAULT;
if (put_user(len, (int __user *) optlen))
- goto end;
+ goto end_put_sess;
if (copy_to_user((void __user *) optval, &val, len))
- goto end;
+ goto end_put_sess;
err = 0;
+
+end_put_sess:
+ sock_put(sk);
end:
return err;
}
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index b7f7b2227d56..bccee68bd48a 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -3701,7 +3701,9 @@ static int ql_cycle_adapter(struct ql3_adapter *qdev, int reset)
printk(KERN_ERR PFX
"%s: Driver up/down cycle failed, "
"closing device\n",qdev->ndev->name);
+ rtnl_lock();
dev_close(qdev->ndev);
+ rtnl_unlock();
return -1;
}
return 0;
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index 169edc154928..504a48ff73c8 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -273,7 +273,7 @@ static void r6040_init_ring_desc(struct r6040_descriptor *desc_ring,
dma_addr_t mapping = desc_dma;
while (size-- > 0) {
- mapping += sizeof(sizeof(*desc));
+ mapping += sizeof(*desc);
desc->ndesc = cpu_to_le32(mapping);
desc->vndescp = desc + 1;
desc++;
@@ -733,7 +733,7 @@ static void r6040_timer(unsigned long data)
}
/* Timer active again */
- mod_timer(&lp->timer, jiffies + round_jiffies(HZ));
+ mod_timer(&lp->timer, round_jiffies(jiffies + HZ));
}
/* Read/set MAC address routines */
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index 2109508c047a..f8274f8941ea 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -250,7 +250,7 @@ struct XENA_dev_config {
u64 tx_mat0_n[0x8];
#define TX_MAT_SET(fifo, msi) vBIT(msi, (8 * fifo), 8)
- u8 unused_1[0x8];
+ u64 xmsi_mask_reg;
u64 stat_byte_cnt;
#define STAT_BC(n) vBIT(n,4,12)
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 523478ebfd69..ae7b697456b4 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -86,7 +86,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.26.23"
+#define DRV_VERSION "2.0.26.24"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -1113,9 +1113,10 @@ static int s2io_on_nec_bridge(struct pci_dev *s2io_pdev)
struct pci_dev *tdev = NULL;
while ((tdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, tdev)) != NULL) {
if (tdev->vendor == NEC_VENID && tdev->device == NEC_DEVID) {
- if (tdev->bus == s2io_pdev->bus->parent)
+ if (tdev->bus == s2io_pdev->bus->parent) {
pci_dev_put(tdev);
return 1;
+ }
}
}
return 0;
@@ -1219,15 +1220,33 @@ static int init_tti(struct s2io_nic *nic, int link)
TTI_DATA1_MEM_TX_URNG_B(0x10) |
TTI_DATA1_MEM_TX_URNG_C(0x30) |
TTI_DATA1_MEM_TX_TIMER_AC_EN;
-
- if (use_continuous_tx_intrs && (link == LINK_UP))
- val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN;
+ if (i == 0)
+ if (use_continuous_tx_intrs && (link == LINK_UP))
+ val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN;
writeq(val64, &bar0->tti_data1_mem);
- val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
- TTI_DATA2_MEM_TX_UFC_B(0x20) |
- TTI_DATA2_MEM_TX_UFC_C(0x40) |
- TTI_DATA2_MEM_TX_UFC_D(0x80);
+ if (nic->config.intr_type == MSI_X) {
+ val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
+ TTI_DATA2_MEM_TX_UFC_B(0x100) |
+ TTI_DATA2_MEM_TX_UFC_C(0x200) |
+ TTI_DATA2_MEM_TX_UFC_D(0x300);
+ } else {
+ if ((nic->config.tx_steering_type ==
+ TX_DEFAULT_STEERING) &&
+ (config->tx_fifo_num > 1) &&
+ (i >= nic->udp_fifo_idx) &&
+ (i < (nic->udp_fifo_idx +
+ nic->total_udp_fifos)))
+ val64 = TTI_DATA2_MEM_TX_UFC_A(0x50) |
+ TTI_DATA2_MEM_TX_UFC_B(0x80) |
+ TTI_DATA2_MEM_TX_UFC_C(0x100) |
+ TTI_DATA2_MEM_TX_UFC_D(0x120);
+ else
+ val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
+ TTI_DATA2_MEM_TX_UFC_B(0x20) |
+ TTI_DATA2_MEM_TX_UFC_C(0x40) |
+ TTI_DATA2_MEM_TX_UFC_D(0x80);
+ }
writeq(val64, &bar0->tti_data2_mem);
@@ -2606,9 +2625,7 @@ static int fill_rx_buffers(struct ring_info *ring)
rxdp1->Buffer0_ptr = pci_map_single
(ring->pdev, skb->data, size - NET_IP_ALIGN,
PCI_DMA_FROMDEVICE);
- if( (rxdp1->Buffer0_ptr == 0) ||
- (rxdp1->Buffer0_ptr ==
- DMA_ERROR_CODE))
+ if(pci_dma_mapping_error(rxdp1->Buffer0_ptr))
goto pci_map_failed;
rxdp->Control_2 =
@@ -2638,6 +2655,7 @@ static int fill_rx_buffers(struct ring_info *ring)
skb->data = (void *) (unsigned long)tmp;
skb_reset_tail_pointer(skb);
+ /* AK: check is wrong. 0 can be valid dma address */
if (!(rxdp3->Buffer0_ptr))
rxdp3->Buffer0_ptr =
pci_map_single(ring->pdev, ba->ba_0,
@@ -2646,8 +2664,7 @@ static int fill_rx_buffers(struct ring_info *ring)
pci_dma_sync_single_for_device(ring->pdev,
(dma_addr_t) rxdp3->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
- if( (rxdp3->Buffer0_ptr == 0) ||
- (rxdp3->Buffer0_ptr == DMA_ERROR_CODE))
+ if (pci_dma_mapping_error(rxdp3->Buffer0_ptr))
goto pci_map_failed;
rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
@@ -2662,18 +2679,17 @@ static int fill_rx_buffers(struct ring_info *ring)
(ring->pdev, skb->data, ring->mtu + 4,
PCI_DMA_FROMDEVICE);
- if( (rxdp3->Buffer2_ptr == 0) ||
- (rxdp3->Buffer2_ptr == DMA_ERROR_CODE))
+ if (pci_dma_mapping_error(rxdp3->Buffer2_ptr))
goto pci_map_failed;
+ /* AK: check is wrong */
if (!rxdp3->Buffer1_ptr)
rxdp3->Buffer1_ptr =
pci_map_single(ring->pdev,
ba->ba_1, BUF1_LEN,
PCI_DMA_FROMDEVICE);
- if( (rxdp3->Buffer1_ptr == 0) ||
- (rxdp3->Buffer1_ptr == DMA_ERROR_CODE)) {
+ if (pci_dma_mapping_error(rxdp3->Buffer1_ptr)) {
pci_unmap_single
(ring->pdev,
(dma_addr_t)(unsigned long)
@@ -2813,6 +2829,15 @@ static void free_rx_buffers(struct s2io_nic *sp)
}
}
+static int s2io_chk_rx_buffers(struct ring_info *ring)
+{
+ if (fill_rx_buffers(ring) == -ENOMEM) {
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", ring->dev->name);
+ DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
+ }
+ return 0;
+}
+
/**
* s2io_poll - Rx interrupt handler for NAPI support
* @napi : pointer to the napi structure.
@@ -2826,57 +2851,73 @@ static void free_rx_buffers(struct s2io_nic *sp)
* 0 on success and 1 if there are No Rx packets to be processed.
*/
-static int s2io_poll(struct napi_struct *napi, int budget)
+static int s2io_poll_msix(struct napi_struct *napi, int budget)
{
- struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi);
- struct net_device *dev = nic->dev;
- int pkt_cnt = 0, org_pkts_to_process;
- struct mac_info *mac_control;
+ struct ring_info *ring = container_of(napi, struct ring_info, napi);
+ struct net_device *dev = ring->dev;
struct config_param *config;
+ struct mac_info *mac_control;
+ int pkts_processed = 0;
+ u8 __iomem *addr = NULL;
+ u8 val8 = 0;
+ struct s2io_nic *nic = dev->priv;
struct XENA_dev_config __iomem *bar0 = nic->bar0;
- int i;
+ int budget_org = budget;
- mac_control = &nic->mac_control;
config = &nic->config;
+ mac_control = &nic->mac_control;
- nic->pkts_to_process = budget;
- org_pkts_to_process = nic->pkts_to_process;
+ if (unlikely(!is_s2io_card_up(nic)))
+ return 0;
- writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
- readl(&bar0->rx_traffic_int);
+ pkts_processed = rx_intr_handler(ring, budget);
+ s2io_chk_rx_buffers(ring);
- for (i = 0; i < config->rx_ring_num; i++) {
- rx_intr_handler(&mac_control->rings[i]);
- pkt_cnt = org_pkts_to_process - nic->pkts_to_process;
- if (!nic->pkts_to_process) {
- /* Quota for the current iteration has been met */
- goto no_rx;
- }
+ if (pkts_processed < budget_org) {
+ netif_rx_complete(dev, napi);
+ /*Re Enable MSI-Rx Vector*/
+ addr = (u8 __iomem *)&bar0->xmsi_mask_reg;
+ addr += 7 - ring->ring_no;
+ val8 = (ring->ring_no == 0) ? 0x3f : 0xbf;
+ writeb(val8, addr);
+ val8 = readb(addr);
}
+ return pkts_processed;
+}
+static int s2io_poll_inta(struct napi_struct *napi, int budget)
+{
+ struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi);
+ struct ring_info *ring;
+ struct net_device *dev = nic->dev;
+ struct config_param *config;
+ struct mac_info *mac_control;
+ int pkts_processed = 0;
+ int ring_pkts_processed, i;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
+ int budget_org = budget;
- netif_rx_complete(dev, napi);
+ config = &nic->config;
+ mac_control = &nic->mac_control;
- for (i = 0; i < config->rx_ring_num; i++) {
- if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) {
- DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
- DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
- break;
- }
- }
- /* Re enable the Rx interrupts. */
- writeq(0x0, &bar0->rx_traffic_mask);
- readl(&bar0->rx_traffic_mask);
- return pkt_cnt;
+ if (unlikely(!is_s2io_card_up(nic)))
+ return 0;
-no_rx:
for (i = 0; i < config->rx_ring_num; i++) {
- if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) {
- DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
- DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
+ ring = &mac_control->rings[i];
+ ring_pkts_processed = rx_intr_handler(ring, budget);
+ s2io_chk_rx_buffers(ring);
+ pkts_processed += ring_pkts_processed;
+ budget -= ring_pkts_processed;
+ if (budget <= 0)
break;
- }
}
- return pkt_cnt;
+ if (pkts_processed < budget_org) {
+ netif_rx_complete(dev, napi);
+ /* Re enable the Rx interrupts for the ring */
+ writeq(0, &bar0->rx_traffic_mask);
+ readl(&bar0->rx_traffic_mask);
+ }
+ return pkts_processed;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2918,7 +2959,7 @@ static void s2io_netpoll(struct net_device *dev)
/* check for received packet and indicate up to network */
for (i = 0; i < config->rx_ring_num; i++)
- rx_intr_handler(&mac_control->rings[i]);
+ rx_intr_handler(&mac_control->rings[i], 0);
for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) {
@@ -2934,7 +2975,8 @@ static void s2io_netpoll(struct net_device *dev)
/**
* rx_intr_handler - Rx interrupt handler
- * @nic: device private variable.
+ * @ring_info: per ring structure.
+ * @budget: budget for napi processing.
* Description:
* If the interrupt is because of a received frame or if the
* receive ring contains fresh as yet un-processed frames,this function is
@@ -2942,15 +2984,15 @@ static void s2io_netpoll(struct net_device *dev)
* stopped and sends the skb to the OSM's Rx handler and then increments
* the offset.
* Return Value:
- * NONE.
+ * No. of napi packets processed.
*/
-static void rx_intr_handler(struct ring_info *ring_data)
+static int rx_intr_handler(struct ring_info *ring_data, int budget)
{
int get_block, put_block;
struct rx_curr_get_info get_info, put_info;
struct RxD_t *rxdp;
struct sk_buff *skb;
- int pkt_cnt = 0;
+ int pkt_cnt = 0, napi_pkts = 0;
int i;
struct RxD1* rxdp1;
struct RxD3* rxdp3;
@@ -2977,7 +3019,7 @@ static void rx_intr_handler(struct ring_info *ring_data)
DBG_PRINT(ERR_DBG, "%s: The skb is ",
ring_data->dev->name);
DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
- return;
+ return 0;
}
if (ring_data->rxd_mode == RXD_MODE_1) {
rxdp1 = (struct RxD1*)rxdp;
@@ -3014,9 +3056,10 @@ static void rx_intr_handler(struct ring_info *ring_data)
rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
}
- if(ring_data->nic->config.napi){
- ring_data->nic->pkts_to_process -= 1;
- if (!ring_data->nic->pkts_to_process)
+ if (ring_data->nic->config.napi) {
+ budget--;
+ napi_pkts++;
+ if (!budget)
break;
}
pkt_cnt++;
@@ -3034,6 +3077,7 @@ static void rx_intr_handler(struct ring_info *ring_data)
}
}
}
+ return(napi_pkts);
}
/**
@@ -3730,14 +3774,19 @@ static void restore_xmsi_data(struct s2io_nic *nic)
{
struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64;
- int i;
+ int i, msix_index;
+
+
+ if (nic->device_type == XFRAME_I_DEVICE)
+ return;
for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
+ msix_index = (i) ? ((i-1) * 8 + 1): 0;
writeq(nic->msix_info[i].addr, &bar0->xmsi_address);
writeq(nic->msix_info[i].data, &bar0->xmsi_data);
- val64 = (s2BIT(7) | s2BIT(15) | vBIT(i, 26, 6));
+ val64 = (s2BIT(7) | s2BIT(15) | vBIT(msix_index, 26, 6));
writeq(val64, &bar0->xmsi_access);
- if (wait_for_msix_trans(nic, i)) {
+ if (wait_for_msix_trans(nic, msix_index)) {
DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
continue;
}
@@ -3748,13 +3797,17 @@ static void store_xmsi_data(struct s2io_nic *nic)
{
struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64, addr, data;
- int i;
+ int i, msix_index;
+
+ if (nic->device_type == XFRAME_I_DEVICE)
+ return;
/* Store and display */
for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
- val64 = (s2BIT(15) | vBIT(i, 26, 6));
+ msix_index = (i) ? ((i-1) * 8 + 1): 0;
+ val64 = (s2BIT(15) | vBIT(msix_index, 26, 6));
writeq(val64, &bar0->xmsi_access);
- if (wait_for_msix_trans(nic, i)) {
+ if (wait_for_msix_trans(nic, msix_index)) {
DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
continue;
}
@@ -3770,11 +3823,11 @@ static void store_xmsi_data(struct s2io_nic *nic)
static int s2io_enable_msi_x(struct s2io_nic *nic)
{
struct XENA_dev_config __iomem *bar0 = nic->bar0;
- u64 tx_mat, rx_mat;
+ u64 rx_mat;
u16 msi_control; /* Temp variable */
int ret, i, j, msix_indx = 1;
- nic->entries = kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct msix_entry),
+ nic->entries = kmalloc(nic->num_entries * sizeof(struct msix_entry),
GFP_KERNEL);
if (!nic->entries) {
DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \
@@ -3783,10 +3836,12 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
return -ENOMEM;
}
nic->mac_control.stats_info->sw_stat.mem_allocated
- += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
+ += (nic->num_entries * sizeof(struct msix_entry));
+
+ memset(nic->entries, 0, nic->num_entries * sizeof(struct msix_entry));
nic->s2io_entries =
- kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct s2io_msix_entry),
+ kmalloc(nic->num_entries * sizeof(struct s2io_msix_entry),
GFP_KERNEL);
if (!nic->s2io_entries) {
DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n",
@@ -3794,60 +3849,52 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
kfree(nic->entries);
nic->mac_control.stats_info->sw_stat.mem_freed
- += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
+ += (nic->num_entries * sizeof(struct msix_entry));
return -ENOMEM;
}
nic->mac_control.stats_info->sw_stat.mem_allocated
- += (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
-
- for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
- nic->entries[i].entry = i;
- nic->s2io_entries[i].entry = i;
+ += (nic->num_entries * sizeof(struct s2io_msix_entry));
+ memset(nic->s2io_entries, 0,
+ nic->num_entries * sizeof(struct s2io_msix_entry));
+
+ nic->entries[0].entry = 0;
+ nic->s2io_entries[0].entry = 0;
+ nic->s2io_entries[0].in_use = MSIX_FLG;
+ nic->s2io_entries[0].type = MSIX_ALARM_TYPE;
+ nic->s2io_entries[0].arg = &nic->mac_control.fifos;
+
+ for (i = 1; i < nic->num_entries; i++) {
+ nic->entries[i].entry = ((i - 1) * 8) + 1;
+ nic->s2io_entries[i].entry = ((i - 1) * 8) + 1;
nic->s2io_entries[i].arg = NULL;
nic->s2io_entries[i].in_use = 0;
}
- tx_mat = readq(&bar0->tx_mat0_n[0]);
- for (i=0; i<nic->config.tx_fifo_num; i++, msix_indx++) {
- tx_mat |= TX_MAT_SET(i, msix_indx);
- nic->s2io_entries[msix_indx].arg = &nic->mac_control.fifos[i];
- nic->s2io_entries[msix_indx].type = MSIX_FIFO_TYPE;
- nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
- }
- writeq(tx_mat, &bar0->tx_mat0_n[0]);
-
rx_mat = readq(&bar0->rx_mat);
- for (j = 0; j < nic->config.rx_ring_num; j++, msix_indx++) {
+ for (j = 0; j < nic->config.rx_ring_num; j++) {
rx_mat |= RX_MAT_SET(j, msix_indx);
- nic->s2io_entries[msix_indx].arg
- = &nic->mac_control.rings[j];
- nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
- nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
+ nic->s2io_entries[j+1].arg = &nic->mac_control.rings[j];
+ nic->s2io_entries[j+1].type = MSIX_RING_TYPE;
+ nic->s2io_entries[j+1].in_use = MSIX_FLG;
+ msix_indx += 8;
}
writeq(rx_mat, &bar0->rx_mat);
+ readq(&bar0->rx_mat);
- nic->avail_msix_vectors = 0;
- ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X);
+ ret = pci_enable_msix(nic->pdev, nic->entries, nic->num_entries);
/* We fail init if error or we get less vectors than min required */
- if (ret >= (nic->config.tx_fifo_num + nic->config.rx_ring_num + 1)) {
- nic->avail_msix_vectors = ret;
- ret = pci_enable_msix(nic->pdev, nic->entries, ret);
- }
if (ret) {
DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name);
kfree(nic->entries);
nic->mac_control.stats_info->sw_stat.mem_freed
- += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
+ += (nic->num_entries * sizeof(struct msix_entry));
kfree(nic->s2io_entries);
nic->mac_control.stats_info->sw_stat.mem_freed
- += (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
+ += (nic->num_entries * sizeof(struct s2io_msix_entry));
nic->entries = NULL;
nic->s2io_entries = NULL;
- nic->avail_msix_vectors = 0;
return -ENOMEM;
}
- if (!nic->avail_msix_vectors)
- nic->avail_msix_vectors = MAX_REQUESTED_MSI_X;
/*
* To enable MSI-X, MSI also needs to be enabled, due to a bug
@@ -3919,7 +3966,7 @@ static void remove_msix_isr(struct s2io_nic *sp)
int i;
u16 msi_control;
- for (i = 0; i < MAX_REQUESTED_MSI_X; i++) {
+ for (i = 0; i < sp->num_entries; i++) {
if (sp->s2io_entries[i].in_use ==
MSIX_REGISTERED_SUCCESS) {
int vector = sp->entries[i].vector;
@@ -3975,29 +4022,6 @@ static int s2io_open(struct net_device *dev)
netif_carrier_off(dev);
sp->last_link_state = 0;
- if (sp->config.intr_type == MSI_X) {
- int ret = s2io_enable_msi_x(sp);
-
- if (!ret) {
- ret = s2io_test_msi(sp);
- /* rollback MSI-X, will re-enable during add_isr() */
- remove_msix_isr(sp);
- }
- if (ret) {
-
- DBG_PRINT(ERR_DBG,
- "%s: MSI-X requested but failed to enable\n",
- dev->name);
- sp->config.intr_type = INTA;
- }
- }
-
- /* NAPI doesn't work well with MSI(X) */
- if (sp->config.intr_type != INTA) {
- if(sp->config.napi)
- sp->config.napi = 0;
- }
-
/* Initialize H/W and enable interrupts */
err = s2io_card_up(sp);
if (err) {
@@ -4020,12 +4044,12 @@ hw_init_failed:
if (sp->entries) {
kfree(sp->entries);
sp->mac_control.stats_info->sw_stat.mem_freed
- += (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
+ += (sp->num_entries * sizeof(struct msix_entry));
}
if (sp->s2io_entries) {
kfree(sp->s2io_entries);
sp->mac_control.stats_info->sw_stat.mem_freed
- += (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
+ += (sp->num_entries * sizeof(struct s2io_msix_entry));
}
}
return err;
@@ -4237,16 +4261,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
txdp->Buffer_Pointer = pci_map_single(sp->pdev,
fifo->ufo_in_band_v,
sizeof(u64), PCI_DMA_TODEVICE);
- if((txdp->Buffer_Pointer == 0) ||
- (txdp->Buffer_Pointer == DMA_ERROR_CODE))
+ if (pci_dma_mapping_error(txdp->Buffer_Pointer))
goto pci_map_failed;
txdp++;
}
txdp->Buffer_Pointer = pci_map_single
(sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
- if((txdp->Buffer_Pointer == 0) ||
- (txdp->Buffer_Pointer == DMA_ERROR_CODE))
+ if (pci_dma_mapping_error(txdp->Buffer_Pointer))
goto pci_map_failed;
txdp->Host_Control = (unsigned long) skb;
@@ -4327,40 +4349,65 @@ s2io_alarm_handle(unsigned long data)
mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
}
-static int s2io_chk_rx_buffers(struct ring_info *ring)
-{
- if (fill_rx_buffers(ring) == -ENOMEM) {
- DBG_PRINT(INFO_DBG, "%s:Out of memory", ring->dev->name);
- DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
- }
- return 0;
-}
-
static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
{
struct ring_info *ring = (struct ring_info *)dev_id;
struct s2io_nic *sp = ring->nic;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
+ struct net_device *dev = sp->dev;
- if (!is_s2io_card_up(sp))
+ if (unlikely(!is_s2io_card_up(sp)))
return IRQ_HANDLED;
- rx_intr_handler(ring);
- s2io_chk_rx_buffers(ring);
+ if (sp->config.napi) {
+ u8 __iomem *addr = NULL;
+ u8 val8 = 0;
+
+ addr = (u8 __iomem *)&bar0->xmsi_mask_reg;
+ addr += (7 - ring->ring_no);
+ val8 = (ring->ring_no == 0) ? 0x7f : 0xff;
+ writeb(val8, addr);
+ val8 = readb(addr);
+ netif_rx_schedule(dev, &ring->napi);
+ } else {
+ rx_intr_handler(ring, 0);
+ s2io_chk_rx_buffers(ring);
+ }
return IRQ_HANDLED;
}
static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id)
{
- struct fifo_info *fifo = (struct fifo_info *)dev_id;
- struct s2io_nic *sp = fifo->nic;
+ int i;
+ struct fifo_info *fifos = (struct fifo_info *)dev_id;
+ struct s2io_nic *sp = fifos->nic;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
+ struct config_param *config = &sp->config;
+ u64 reason;
- if (!is_s2io_card_up(sp))
+ if (unlikely(!is_s2io_card_up(sp)))
+ return IRQ_NONE;
+
+ reason = readq(&bar0->general_int_status);
+ if (unlikely(reason == S2IO_MINUS_ONE))
+ /* Nothing much can be done. Get out */
return IRQ_HANDLED;
- tx_intr_handler(fifo);
+ writeq(S2IO_MINUS_ONE, &bar0->general_int_mask);
+
+ if (reason & GEN_INTR_TXTRAFFIC)
+ writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
+
+ for (i = 0; i < config->tx_fifo_num; i++)
+ tx_intr_handler(&fifos[i]);
+
+ writeq(sp->general_int_mask, &bar0->general_int_mask);
+ readl(&bar0->general_int_status);
+
return IRQ_HANDLED;
}
+
static void s2io_txpic_intr_handle(struct s2io_nic *sp)
{
struct XENA_dev_config __iomem *bar0 = sp->bar0;
@@ -4762,14 +4809,10 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
if (config->napi) {
if (reason & GEN_INTR_RXTRAFFIC) {
- if (likely(netif_rx_schedule_prep(dev,
- &sp->napi))) {
- __netif_rx_schedule(dev, &sp->napi);
- writeq(S2IO_MINUS_ONE,
- &bar0->rx_traffic_mask);
- } else
- writeq(S2IO_MINUS_ONE,
- &bar0->rx_traffic_int);
+ netif_rx_schedule(dev, &sp->napi);
+ writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
+ writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+ readl(&bar0->rx_traffic_int);
}
} else {
/*
@@ -4781,7 +4824,7 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
for (i = 0; i < config->rx_ring_num; i++)
- rx_intr_handler(&mac_control->rings[i]);
+ rx_intr_handler(&mac_control->rings[i], 0);
}
/*
@@ -6836,10 +6879,8 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
pci_map_single( sp->pdev, (*skb)->data,
size - NET_IP_ALIGN,
PCI_DMA_FROMDEVICE);
- if( (rxdp1->Buffer0_ptr == 0) ||
- (rxdp1->Buffer0_ptr == DMA_ERROR_CODE)) {
+ if (pci_dma_mapping_error(rxdp1->Buffer0_ptr))
goto memalloc_failed;
- }
rxdp->Host_Control = (unsigned long) (*skb);
}
} else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
@@ -6865,15 +6906,12 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
pci_map_single(sp->pdev, (*skb)->data,
dev->mtu + 4,
PCI_DMA_FROMDEVICE);
- if( (rxdp3->Buffer2_ptr == 0) ||
- (rxdp3->Buffer2_ptr == DMA_ERROR_CODE)) {
+ if (pci_dma_mapping_error(rxdp3->Buffer2_ptr))
goto memalloc_failed;
- }
rxdp3->Buffer0_ptr = *temp0 =
pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
PCI_DMA_FROMDEVICE);
- if( (rxdp3->Buffer0_ptr == 0) ||
- (rxdp3->Buffer0_ptr == DMA_ERROR_CODE)) {
+ if (pci_dma_mapping_error(rxdp3->Buffer0_ptr)) {
pci_unmap_single (sp->pdev,
(dma_addr_t)rxdp3->Buffer2_ptr,
dev->mtu + 4, PCI_DMA_FROMDEVICE);
@@ -6885,8 +6923,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
rxdp3->Buffer1_ptr = *temp1 =
pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
PCI_DMA_FROMDEVICE);
- if( (rxdp3->Buffer1_ptr == 0) ||
- (rxdp3->Buffer1_ptr == DMA_ERROR_CODE)) {
+ if (pci_dma_mapping_error(rxdp3->Buffer1_ptr)) {
pci_unmap_single (sp->pdev,
(dma_addr_t)rxdp3->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
@@ -6984,62 +7021,62 @@ static int s2io_add_isr(struct s2io_nic * sp)
/* After proper initialization of H/W, register ISR */
if (sp->config.intr_type == MSI_X) {
- int i, msix_tx_cnt=0,msix_rx_cnt=0;
-
- for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
- if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
- sprintf(sp->desc[i], "%s:MSI-X-%d-TX",
+ int i, msix_rx_cnt = 0;
+
+ for (i = 0; i < sp->num_entries; i++) {
+ if (sp->s2io_entries[i].in_use == MSIX_FLG) {
+ if (sp->s2io_entries[i].type ==
+ MSIX_RING_TYPE) {
+ sprintf(sp->desc[i], "%s:MSI-X-%d-RX",
+ dev->name, i);
+ err = request_irq(sp->entries[i].vector,
+ s2io_msix_ring_handle, 0,
+ sp->desc[i],
+ sp->s2io_entries[i].arg);
+ } else if (sp->s2io_entries[i].type ==
+ MSIX_ALARM_TYPE) {
+ sprintf(sp->desc[i], "%s:MSI-X-%d-TX",
dev->name, i);
- err = request_irq(sp->entries[i].vector,
- s2io_msix_fifo_handle, 0, sp->desc[i],
- sp->s2io_entries[i].arg);
- /* If either data or addr is zero print it */
- if(!(sp->msix_info[i].addr &&
- sp->msix_info[i].data)) {
- DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx "
- "Data:0x%llx\n",sp->desc[i],
- (unsigned long long)
- sp->msix_info[i].addr,
- (unsigned long long)
- sp->msix_info[i].data);
- } else {
- msix_tx_cnt++;
+ err = request_irq(sp->entries[i].vector,
+ s2io_msix_fifo_handle, 0,
+ sp->desc[i],
+ sp->s2io_entries[i].arg);
+
}
- } else {
- sprintf(sp->desc[i], "%s:MSI-X-%d-RX",
- dev->name, i);
- err = request_irq(sp->entries[i].vector,
- s2io_msix_ring_handle, 0, sp->desc[i],
- sp->s2io_entries[i].arg);
- /* If either data or addr is zero print it */
- if(!(sp->msix_info[i].addr &&
+ /* if either data or addr is zero print it. */
+ if (!(sp->msix_info[i].addr &&
sp->msix_info[i].data)) {
- DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx "
- "Data:0x%llx\n",sp->desc[i],
+ DBG_PRINT(ERR_DBG,
+ "%s @Addr:0x%llx Data:0x%llx\n",
+ sp->desc[i],
(unsigned long long)
sp->msix_info[i].addr,
(unsigned long long)
- sp->msix_info[i].data);
- } else {
+ ntohl(sp->msix_info[i].data));
+ } else
msix_rx_cnt++;
+ if (err) {
+ remove_msix_isr(sp);
+
+ DBG_PRINT(ERR_DBG,
+ "%s:MSI-X-%d registration "
+ "failed\n", dev->name, i);
+
+ DBG_PRINT(ERR_DBG,
+ "%s: Defaulting to INTA\n",
+ dev->name);
+ sp->config.intr_type = INTA;
+ break;
}
+ sp->s2io_entries[i].in_use =
+ MSIX_REGISTERED_SUCCESS;
}
- if (err) {
- remove_msix_isr(sp);
- DBG_PRINT(ERR_DBG,"%s:MSI-X-%d registration "
- "failed\n", dev->name, i);
- DBG_PRINT(ERR_DBG, "%s: defaulting to INTA\n",
- dev->name);
- sp->config.intr_type = INTA;
- break;
- }
- sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
}
if (!err) {
- printk(KERN_INFO "MSI-X-TX %d entries enabled\n",
- msix_tx_cnt);
printk(KERN_INFO "MSI-X-RX %d entries enabled\n",
- msix_rx_cnt);
+ --msix_rx_cnt);
+ DBG_PRINT(INFO_DBG, "MSI-X-TX entries enabled"
+ " through alarm vector\n");
}
}
if (sp->config.intr_type == INTA) {
@@ -7080,8 +7117,15 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
clear_bit(__S2IO_STATE_CARD_UP, &sp->state);
/* Disable napi */
- if (config->napi)
- napi_disable(&sp->napi);
+ if (sp->config.napi) {
+ int off = 0;
+ if (config->intr_type == MSI_X) {
+ for (; off < sp->config.rx_ring_num; off++)
+ napi_disable(&sp->mac_control.rings[off].napi);
+ }
+ else
+ napi_disable(&sp->napi);
+ }
/* disable Tx and Rx traffic on the NIC */
if (do_io)
@@ -7173,8 +7217,15 @@ static int s2io_card_up(struct s2io_nic * sp)
}
/* Initialise napi */
- if (config->napi)
- napi_enable(&sp->napi);
+ if (config->napi) {
+ int i;
+ if (config->intr_type == MSI_X) {
+ for (i = 0; i < sp->config.rx_ring_num; i++)
+ napi_enable(&sp->mac_control.rings[i].napi);
+ } else {
+ napi_enable(&sp->napi);
+ }
+ }
/* Maintain the state prior to the open */
if (sp->promisc_flg)
@@ -7217,7 +7268,7 @@ static int s2io_card_up(struct s2io_nic * sp)
/* Enable select interrupts */
en_dis_err_alarms(sp, ENA_ALL_INTRS, ENABLE_INTRS);
if (sp->config.intr_type != INTA)
- en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS);
+ en_dis_able_nic_intrs(sp, TX_TRAFFIC_INTR, ENABLE_INTRS);
else {
interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
interruptible |= TX_PIC_INTR;
@@ -7615,9 +7666,6 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type,
rx_ring_num = MAX_RX_RINGS;
}
- if (*dev_intr_type != INTA)
- napi = 0;
-
if ((*dev_intr_type != INTA) && (*dev_intr_type != MSI_X)) {
DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. "
"Defaulting to INTA\n");
@@ -7918,8 +7966,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
* will use eth_mac_addr() for dev->set_mac_address
* mac address will be set every time dev->open() is called
*/
- netif_napi_add(dev, &sp->napi, s2io_poll, 32);
-
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = s2io_netpoll;
#endif
@@ -7963,6 +8009,32 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
}
}
+ if (sp->config.intr_type == MSI_X) {
+ sp->num_entries = config->rx_ring_num + 1;
+ ret = s2io_enable_msi_x(sp);
+
+ if (!ret) {
+ ret = s2io_test_msi(sp);
+ /* rollback MSI-X, will re-enable during add_isr() */
+ remove_msix_isr(sp);
+ }
+ if (ret) {
+
+ DBG_PRINT(ERR_DBG,
+ "%s: MSI-X requested but failed to enable\n",
+ dev->name);
+ sp->config.intr_type = INTA;
+ }
+ }
+
+ if (config->intr_type == MSI_X) {
+ for (i = 0; i < config->rx_ring_num ; i++)
+ netif_napi_add(dev, &mac_control->rings[i].napi,
+ s2io_poll_msix, 64);
+ } else {
+ netif_napi_add(dev, &sp->napi, s2io_poll_inta, 64);
+ }
+
/* Not needed for Herc */
if (sp->device_type & XFRAME_I_DEVICE) {
/*
@@ -8013,6 +8085,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* store mac addresses from CAM to s2io_nic structure */
do_s2io_store_unicast_mc(sp);
+ /* Configure MSIX vector for number of rings configured plus one */
+ if ((sp->device_type == XFRAME_II_DEVICE) &&
+ (config->intr_type == MSI_X))
+ sp->num_entries = config->rx_ring_num + 1;
+
/* Store the values of the MSIX table in the s2io_nic structure */
store_xmsi_data(sp);
/* reset Nic and bring it to known state */
@@ -8078,8 +8155,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
break;
}
- if (napi)
+ switch (sp->config.napi) {
+ case 0:
+ DBG_PRINT(ERR_DBG, "%s: NAPI disabled\n", dev->name);
+ break;
+ case 1:
DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
+ break;
+ }
DBG_PRINT(ERR_DBG, "%s: Using %d Tx fifo(s)\n", dev->name,
sp->config.tx_fifo_num);
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 0709ebae9139..1827b6686c98 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -75,10 +75,6 @@ static int debug_level = ERR_DBG;
/* DEBUG message print. */
#define DBG_PRINT(dbg_level, args...) if(!(debug_level<dbg_level)) printk(args)
-#ifndef DMA_ERROR_CODE
-#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
-#endif
-
/* Protocol assist features of the NIC */
#define L3_CKSUM_OK 0xFFFF
#define L4_CKSUM_OK 0xFFFF
@@ -706,7 +702,7 @@ struct ring_info {
/* per-ring buffer counter */
u32 rx_bufs_left;
- #define MAX_LRO_SESSIONS 32
+#define MAX_LRO_SESSIONS 32
struct lro lro0_n[MAX_LRO_SESSIONS];
u8 lro;
@@ -725,6 +721,11 @@ struct ring_info {
/* copy of sp->pdev pointer */
struct pci_dev *pdev;
+ /* Per ring napi struct */
+ struct napi_struct napi;
+
+ unsigned long interrupt_count;
+
/*
* Place holders for the virtual and physical addresses of
* all the Rx Blocks
@@ -841,7 +842,7 @@ struct usr_addr {
* Structure to keep track of the MSI-X vectors and the corresponding
* argument registered against each vector
*/
-#define MAX_REQUESTED_MSI_X 17
+#define MAX_REQUESTED_MSI_X 9
struct s2io_msix_entry
{
u16 vector;
@@ -849,8 +850,8 @@ struct s2io_msix_entry
void *arg;
u8 type;
-#define MSIX_FIFO_TYPE 1
-#define MSIX_RING_TYPE 2
+#define MSIX_ALARM_TYPE 1
+#define MSIX_RING_TYPE 2
u8 in_use;
#define MSIX_REGISTERED_SUCCESS 0xAA
@@ -877,7 +878,6 @@ struct s2io_nic {
*/
int pkts_to_process;
struct net_device *dev;
- struct napi_struct napi;
struct mac_info mac_control;
struct config_param config;
struct pci_dev *pdev;
@@ -948,6 +948,7 @@ struct s2io_nic {
*/
u8 other_fifo_idx;
+ struct napi_struct napi;
/* after blink, the adapter must be restored with original
* values.
*/
@@ -962,6 +963,7 @@ struct s2io_nic {
unsigned long long start_time;
struct vlan_group *vlgrp;
#define MSIX_FLG 0xA5
+ int num_entries;
struct msix_entry *entries;
int msi_detected;
wait_queue_head_t msi_wait;
@@ -982,6 +984,7 @@ struct s2io_nic {
u16 lro_max_aggr_per_sess;
volatile unsigned long state;
u64 general_int_mask;
+
#define VPD_STRING_LEN 80
u8 product_name[VPD_STRING_LEN];
u8 serial_num[VPD_STRING_LEN];
@@ -1103,7 +1106,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev);
static int init_shared_mem(struct s2io_nic *sp);
static void free_shared_mem(struct s2io_nic *sp);
static int init_nic(struct s2io_nic *nic);
-static void rx_intr_handler(struct ring_info *ring_data);
+static int rx_intr_handler(struct ring_info *ring_data, int budget);
static void tx_intr_handler(struct fifo_info *fifo_data);
static void s2io_handle_errors(void * dev_id);
@@ -1114,7 +1117,8 @@ static void s2io_set_multicast(struct net_device *dev);
static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp);
static void s2io_link(struct s2io_nic * sp, int link);
static void s2io_reset(struct s2io_nic * sp);
-static int s2io_poll(struct napi_struct *napi, int budget);
+static int s2io_poll_msix(struct napi_struct *napi, int budget);
+static int s2io_poll_inta(struct napi_struct *napi, int budget);
static void s2io_init_pci(struct s2io_nic * sp);
static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr);
static void s2io_alarm_handle(unsigned long data);
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index 888b7dec9866..33bb18f810fb 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -179,8 +179,7 @@ enum sbmac_state {
#define SBMAC_MAX_TXDESCR 256
#define SBMAC_MAX_RXDESCR 256
-#define ETHER_ALIGN 2
-#define ETHER_ADDR_LEN 6
+#define ETHER_ADDR_LEN 6
#define ENET_PACKET_SIZE 1518
/*#define ENET_PACKET_SIZE 9216 */
@@ -262,8 +261,6 @@ struct sbmac_softc {
spinlock_t sbm_lock; /* spin lock */
int sbm_devflags; /* current device flags */
- int sbm_buffersize;
-
/*
* Controller-specific things
*/
@@ -305,10 +302,11 @@ struct sbmac_softc {
static void sbdma_initctx(struct sbmacdma *d, struct sbmac_softc *s, int chan,
int txrx, int maxdescr);
static void sbdma_channel_start(struct sbmacdma *d, int rxtx);
-static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *m);
+static int sbdma_add_rcvbuffer(struct sbmac_softc *sc, struct sbmacdma *d,
+ struct sk_buff *m);
static int sbdma_add_txbuffer(struct sbmacdma *d, struct sk_buff *m);
static void sbdma_emptyring(struct sbmacdma *d);
-static void sbdma_fillring(struct sbmacdma *d);
+static void sbdma_fillring(struct sbmac_softc *sc, struct sbmacdma *d);
static int sbdma_rx_process(struct sbmac_softc *sc, struct sbmacdma *d,
int work_to_do, int poll);
static void sbdma_tx_process(struct sbmac_softc *sc, struct sbmacdma *d,
@@ -777,16 +775,13 @@ static void sbdma_channel_stop(struct sbmacdma *d)
d->sbdma_remptr = NULL;
}
-static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset)
+static inline void sbdma_align_skb(struct sk_buff *skb,
+ unsigned int power2, unsigned int offset)
{
- unsigned long addr;
- unsigned long newaddr;
-
- addr = (unsigned long) skb->data;
-
- newaddr = (addr + power2 - 1) & ~(power2 - 1);
+ unsigned char *addr = skb->data;
+ unsigned char *newaddr = PTR_ALIGN(addr, power2);
- skb_reserve(skb,newaddr-addr+offset);
+ skb_reserve(skb, newaddr - addr + offset);
}
@@ -797,7 +792,8 @@ static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset)
* this queues a buffer for inbound packets.
*
* Input parameters:
- * d - DMA channel descriptor
+ * sc - softc structure
+ * d - DMA channel descriptor
* sb - sk_buff to add, or NULL if we should allocate one
*
* Return value:
@@ -806,8 +802,10 @@ static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset)
********************************************************************* */
-static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *sb)
+static int sbdma_add_rcvbuffer(struct sbmac_softc *sc, struct sbmacdma *d,
+ struct sk_buff *sb)
{
+ struct net_device *dev = sc->sbm_dev;
struct sbdmadscr *dsc;
struct sbdmadscr *nextdsc;
struct sk_buff *sb_new = NULL;
@@ -848,14 +846,16 @@ static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *sb)
*/
if (sb == NULL) {
- sb_new = dev_alloc_skb(ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN);
+ sb_new = netdev_alloc_skb(dev, ENET_PACKET_SIZE +
+ SMP_CACHE_BYTES * 2 +
+ NET_IP_ALIGN);
if (sb_new == NULL) {
pr_info("%s: sk_buff allocation failed\n",
d->sbdma_eth->sbm_dev->name);
return -ENOBUFS;
}
- sbdma_align_skb(sb_new, SMP_CACHE_BYTES, ETHER_ALIGN);
+ sbdma_align_skb(sb_new, SMP_CACHE_BYTES, NET_IP_ALIGN);
}
else {
sb_new = sb;
@@ -874,10 +874,10 @@ static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *sb)
* Do not interrupt per DMA transfer.
*/
dsc->dscr_a = virt_to_phys(sb_new->data) |
- V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | 0;
+ V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize + NET_IP_ALIGN)) | 0;
#else
dsc->dscr_a = virt_to_phys(sb_new->data) |
- V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) |
+ V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize + NET_IP_ALIGN)) |
M_DMA_DSCRA_INTERRUPT;
#endif
@@ -1032,18 +1032,19 @@ static void sbdma_emptyring(struct sbmacdma *d)
* with sk_buffs
*
* Input parameters:
- * d - DMA channel
+ * sc - softc structure
+ * d - DMA channel
*
* Return value:
* nothing
********************************************************************* */
-static void sbdma_fillring(struct sbmacdma *d)
+static void sbdma_fillring(struct sbmac_softc *sc, struct sbmacdma *d)
{
int idx;
- for (idx = 0; idx < SBMAC_MAX_RXDESCR-1; idx++) {
- if (sbdma_add_rcvbuffer(d,NULL) != 0)
+ for (idx = 0; idx < SBMAC_MAX_RXDESCR - 1; idx++) {
+ if (sbdma_add_rcvbuffer(sc, d, NULL) != 0)
break;
}
}
@@ -1159,10 +1160,11 @@ again:
* packet and put it right back on the receive ring.
*/
- if (unlikely (sbdma_add_rcvbuffer(d,NULL) ==
- -ENOBUFS)) {
+ if (unlikely(sbdma_add_rcvbuffer(sc, d, NULL) ==
+ -ENOBUFS)) {
dev->stats.rx_dropped++;
- sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */
+ /* Re-add old buffer */
+ sbdma_add_rcvbuffer(sc, d, sb);
/* No point in continuing at the moment */
printk(KERN_ERR "dropped packet (1)\n");
d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
@@ -1212,7 +1214,7 @@ again:
* put it back on the receive ring.
*/
dev->stats.rx_errors++;
- sbdma_add_rcvbuffer(d,sb);
+ sbdma_add_rcvbuffer(sc, d, sb);
}
@@ -1570,7 +1572,7 @@ static void sbmac_channel_start(struct sbmac_softc *s)
* Fill the receive ring
*/
- sbdma_fillring(&(s->sbm_rxdma));
+ sbdma_fillring(s, &(s->sbm_rxdma));
/*
* Turn on the rest of the bits in the enable register
@@ -2312,13 +2314,6 @@ static int sbmac_init(struct platform_device *pldev, long long base)
dev->dev_addr[i] = eaddr[i];
}
-
- /*
- * Init packet size
- */
-
- sc->sbm_buffersize = ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN;
-
/*
* Initialize context (get pointers to registers and stuff), then
* allocate the memory for the descriptor tables.
diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c
index f64a860029b7..61955f8d8011 100644
--- a/drivers/net/sc92031.c
+++ b/drivers/net/sc92031.c
@@ -953,9 +953,6 @@ static int sc92031_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned entry;
u32 tx_status;
- if (skb_padto(skb, ETH_ZLEN))
- return NETDEV_TX_OK;
-
if (unlikely(skb->len > TX_BUF_SIZE)) {
dev->stats.tx_dropped++;
goto out;
@@ -975,6 +972,11 @@ static int sc92031_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb_copy_and_csum_dev(skb, priv->tx_bufs + entry * TX_BUF_SIZE);
len = skb->len;
+ if (len < ETH_ZLEN) {
+ memset(priv->tx_bufs + entry * TX_BUF_SIZE + len,
+ 0, ETH_ZLEN - len);
+ len = ETH_ZLEN;
+ }
wmb();
diff --git a/drivers/net/sfc/bitfield.h b/drivers/net/sfc/bitfield.h
index 2806201644cc..2c79d27404e0 100644
--- a/drivers/net/sfc/bitfield.h
+++ b/drivers/net/sfc/bitfield.h
@@ -483,7 +483,7 @@ typedef union efx_oword {
#endif
#define EFX_SET_OWORD_FIELD_VER(efx, oword, field, value) do { \
- if (FALCON_REV(efx) >= FALCON_REV_B0) { \
+ if (falcon_rev(efx) >= FALCON_REV_B0) { \
EFX_SET_OWORD_FIELD((oword), field##_B0, (value)); \
} else { \
EFX_SET_OWORD_FIELD((oword), field##_A1, (value)); \
@@ -491,7 +491,7 @@ typedef union efx_oword {
} while (0)
#define EFX_QWORD_FIELD_VER(efx, qword, field) \
- (FALCON_REV(efx) >= FALCON_REV_B0 ? \
+ (falcon_rev(efx) >= FALCON_REV_B0 ? \
EFX_QWORD_FIELD((qword), field##_B0) : \
EFX_QWORD_FIELD((qword), field##_A1))
@@ -501,8 +501,5 @@ typedef union efx_oword {
#define DMA_ADDR_T_WIDTH (8 * sizeof(dma_addr_t))
#define EFX_DMA_TYPE_WIDTH(width) \
(((width) < DMA_ADDR_T_WIDTH) ? (width) : DMA_ADDR_T_WIDTH)
-#define EFX_DMA_MAX_MASK ((DMA_ADDR_T_WIDTH == 64) ? \
- ~((u64) 0) : ~((u32) 0))
-#define EFX_DMA_MASK(mask) ((mask) & EFX_DMA_MAX_MASK)
#endif /* EFX_BITFIELD_H */
diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c
index eecaa6d58584..7fc0328dc055 100644
--- a/drivers/net/sfc/boards.c
+++ b/drivers/net/sfc/boards.c
@@ -27,10 +27,8 @@ static void blink_led_timer(unsigned long context)
struct efx_blinker *bl = &efx->board_info.blinker;
efx->board_info.set_fault_led(efx, bl->state);
bl->state = !bl->state;
- if (bl->resubmit) {
- bl->timer.expires = jiffies + BLINK_INTERVAL;
- add_timer(&bl->timer);
- }
+ if (bl->resubmit)
+ mod_timer(&bl->timer, jiffies + BLINK_INTERVAL);
}
static void board_blink(struct efx_nic *efx, int blink)
@@ -44,8 +42,7 @@ static void board_blink(struct efx_nic *efx, int blink)
blinker->state = 0;
setup_timer(&blinker->timer, blink_led_timer,
(unsigned long)efx);
- blinker->timer.expires = jiffies + BLINK_INTERVAL;
- add_timer(&blinker->timer);
+ mod_timer(&blinker->timer, jiffies + BLINK_INTERVAL);
} else {
blinker->resubmit = 0;
if (blinker->timer.function)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 418f2e53a95b..449760642e31 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -199,11 +199,12 @@ static inline int efx_process_channel(struct efx_channel *channel, int rx_quota)
*/
static inline void efx_channel_processed(struct efx_channel *channel)
{
- /* Write to EVQ_RPTR_REG. If a new event arrived in a race
- * with finishing processing, a new interrupt will be raised.
- */
+ /* The interrupt handler for this channel may set work_pending
+ * as soon as we acknowledge the events we've seen. Make sure
+ * it's cleared before then. */
channel->work_pending = 0;
- smp_wmb(); /* Ensure channel updated before any new interrupt. */
+ smp_wmb();
+
falcon_eventq_read_ack(channel);
}
@@ -265,7 +266,7 @@ void efx_process_channel_now(struct efx_channel *channel)
napi_disable(&channel->napi_str);
/* Poll the channel */
- (void) efx_process_channel(channel, efx->type->evq_size);
+ efx_process_channel(channel, efx->type->evq_size);
/* Ack the eventq. This may cause an interrupt to be generated
* when they are reenabled */
@@ -317,26 +318,6 @@ static void efx_remove_eventq(struct efx_channel *channel)
*
*************************************************************************/
-/* Setup per-NIC RX buffer parameters.
- * Calculate the rx buffer allocation parameters required to support
- * the current MTU, including padding for header alignment and overruns.
- */
-static void efx_calc_rx_buffer_params(struct efx_nic *efx)
-{
- unsigned int order, len;
-
- len = (max(EFX_PAGE_IP_ALIGN, NET_IP_ALIGN) +
- EFX_MAX_FRAME_LEN(efx->net_dev->mtu) +
- efx->type->rx_buffer_padding);
-
- /* Calculate page-order */
- for (order = 0; ((1u << order) * PAGE_SIZE) < len; ++order)
- ;
-
- efx->rx_buffer_len = len;
- efx->rx_buffer_order = order;
-}
-
static int efx_probe_channel(struct efx_channel *channel)
{
struct efx_tx_queue *tx_queue;
@@ -387,7 +368,14 @@ static int efx_init_channels(struct efx_nic *efx)
struct efx_channel *channel;
int rc = 0;
- efx_calc_rx_buffer_params(efx);
+ /* Calculate the rx buffer allocation parameters required to
+ * support the current MTU, including padding for header
+ * alignment and overruns.
+ */
+ efx->rx_buffer_len = (max(EFX_PAGE_IP_ALIGN, NET_IP_ALIGN) +
+ EFX_MAX_FRAME_LEN(efx->net_dev->mtu) +
+ efx->type->rx_buffer_padding);
+ efx->rx_buffer_order = get_order(efx->rx_buffer_len);
/* Initialise the channels */
efx_for_each_channel(channel, efx) {
@@ -440,9 +428,12 @@ static void efx_start_channel(struct efx_channel *channel)
netif_napi_add(channel->napi_dev, &channel->napi_str,
efx_poll, napi_weight);
+ /* The interrupt handler for this channel may set work_pending
+ * as soon as we enable it. Make sure it's cleared before
+ * then. Similarly, make sure it sees the enabled flag set. */
channel->work_pending = 0;
channel->enabled = 1;
- smp_wmb(); /* ensure channel updated before first interrupt */
+ smp_wmb();
napi_enable(&channel->napi_str);
@@ -704,7 +695,7 @@ static void efx_stop_port(struct efx_nic *efx)
mutex_unlock(&efx->mac_lock);
/* Serialise against efx_set_multicast_list() */
- if (NET_DEV_REGISTERED(efx)) {
+ if (efx_dev_registered(efx)) {
netif_tx_lock_bh(efx->net_dev);
netif_tx_unlock_bh(efx->net_dev);
}
@@ -791,22 +782,23 @@ static int efx_init_io(struct efx_nic *efx)
efx->membase = ioremap_nocache(efx->membase_phys,
efx->type->mem_map_size);
if (!efx->membase) {
- EFX_ERR(efx, "could not map memory BAR %d at %lx+%x\n",
- efx->type->mem_bar, efx->membase_phys,
+ EFX_ERR(efx, "could not map memory BAR %d at %llx+%x\n",
+ efx->type->mem_bar,
+ (unsigned long long)efx->membase_phys,
efx->type->mem_map_size);
rc = -ENOMEM;
goto fail4;
}
- EFX_LOG(efx, "memory BAR %u at %lx+%x (virtual %p)\n",
- efx->type->mem_bar, efx->membase_phys, efx->type->mem_map_size,
- efx->membase);
+ EFX_LOG(efx, "memory BAR %u at %llx+%x (virtual %p)\n",
+ efx->type->mem_bar, (unsigned long long)efx->membase_phys,
+ efx->type->mem_map_size, efx->membase);
return 0;
fail4:
release_mem_region(efx->membase_phys, efx->type->mem_map_size);
fail3:
- efx->membase_phys = 0UL;
+ efx->membase_phys = 0;
fail2:
pci_disable_device(efx->pci_dev);
fail1:
@@ -824,7 +816,7 @@ static void efx_fini_io(struct efx_nic *efx)
if (efx->membase_phys) {
pci_release_region(efx->pci_dev, efx->type->mem_bar);
- efx->membase_phys = 0UL;
+ efx->membase_phys = 0;
}
pci_disable_device(efx->pci_dev);
@@ -1043,7 +1035,7 @@ static void efx_start_all(struct efx_nic *efx)
return;
if ((efx->state != STATE_RUNNING) && (efx->state != STATE_INIT))
return;
- if (NET_DEV_REGISTERED(efx) && !netif_running(efx->net_dev))
+ if (efx_dev_registered(efx) && !netif_running(efx->net_dev))
return;
/* Mark the port as enabled so port reconfigurations can start, then
@@ -1073,9 +1065,8 @@ static void efx_flush_all(struct efx_nic *efx)
cancel_delayed_work_sync(&efx->monitor_work);
/* Ensure that all RX slow refills are complete. */
- efx_for_each_rx_queue(rx_queue, efx) {
+ efx_for_each_rx_queue(rx_queue, efx)
cancel_delayed_work_sync(&rx_queue->work);
- }
/* Stop scheduled port reconfigurations */
cancel_work_sync(&efx->reconfigure_work);
@@ -1101,9 +1092,10 @@ static void efx_stop_all(struct efx_nic *efx)
falcon_disable_interrupts(efx);
if (efx->legacy_irq)
synchronize_irq(efx->legacy_irq);
- efx_for_each_channel_with_interrupt(channel, efx)
+ efx_for_each_channel_with_interrupt(channel, efx) {
if (channel->irq)
synchronize_irq(channel->irq);
+ }
/* Stop all NAPI processing and synchronous rx refills */
efx_for_each_channel(channel, efx)
@@ -1125,7 +1117,7 @@ static void efx_stop_all(struct efx_nic *efx)
/* Stop the kernel transmit interface late, so the watchdog
* timer isn't ticking over the flush */
efx_stop_queue(efx);
- if (NET_DEV_REGISTERED(efx)) {
+ if (efx_dev_registered(efx)) {
netif_tx_lock_bh(efx->net_dev);
netif_tx_unlock_bh(efx->net_dev);
}
@@ -1344,13 +1336,17 @@ static int efx_net_stop(struct net_device *net_dev)
return 0;
}
-/* Context: process, dev_base_lock held, non-blocking. */
+/* Context: process, dev_base_lock or RTNL held, non-blocking. */
static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
{
struct efx_nic *efx = net_dev->priv;
struct efx_mac_stats *mac_stats = &efx->mac_stats;
struct net_device_stats *stats = &net_dev->stats;
+ /* Update stats if possible, but do not wait if another thread
+ * is updating them (or resetting the NIC); slightly stale
+ * stats are acceptable.
+ */
if (!spin_trylock(&efx->stats_lock))
return stats;
if (efx->state == STATE_RUNNING) {
@@ -1494,7 +1490,7 @@ static void efx_set_multicast_list(struct net_device *net_dev)
static int efx_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
- struct net_device *net_dev = (struct net_device *)ptr;
+ struct net_device *net_dev = ptr;
if (net_dev->open == efx_net_open && event == NETDEV_CHANGENAME) {
struct efx_nic *efx = net_dev->priv;
@@ -1563,7 +1559,7 @@ static void efx_unregister_netdev(struct efx_nic *efx)
efx_for_each_tx_queue(tx_queue, efx)
efx_release_tx_buffers(tx_queue);
- if (NET_DEV_REGISTERED(efx)) {
+ if (efx_dev_registered(efx)) {
strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name));
unregister_netdev(efx->net_dev);
}
@@ -1688,7 +1684,7 @@ static int efx_reset(struct efx_nic *efx)
if (method == RESET_TYPE_DISABLE) {
/* Reinitialise the device anyway so the driver unload sequence
* can talk to the external SRAM */
- (void) falcon_init_nic(efx);
+ falcon_init_nic(efx);
rc = -EIO;
goto fail4;
}
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index b57cc68058c0..790db89db345 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -116,17 +116,8 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
**************************************************************************
*/
-/* DMA address mask (up to 46-bit, avoiding compiler warnings)
- *
- * Note that it is possible to have a platform with 64-bit longs and
- * 32-bit DMA addresses, or vice versa. EFX_DMA_MASK takes care of the
- * platform DMA mask.
- */
-#if BITS_PER_LONG == 64
-#define FALCON_DMA_MASK EFX_DMA_MASK(0x00003fffffffffffUL)
-#else
-#define FALCON_DMA_MASK EFX_DMA_MASK(0x00003fffffffffffULL)
-#endif
+/* DMA address mask */
+#define FALCON_DMA_MASK DMA_BIT_MASK(46)
/* TX DMA length mask (13-bit) */
#define FALCON_TX_DMA_MASK (4096 - 1)
@@ -145,7 +136,7 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
#define PCI_EXP_LNKSTA_LNK_WID_LBN 4
#define FALCON_IS_DUAL_FUNC(efx) \
- (FALCON_REV(efx) < FALCON_REV_B0)
+ (falcon_rev(efx) < FALCON_REV_B0)
/**************************************************************************
*
@@ -465,7 +456,7 @@ int falcon_init_tx(struct efx_tx_queue *tx_queue)
TX_DESCQ_TYPE, 0,
TX_NON_IP_DROP_DIS_B0, 1);
- if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ if (falcon_rev(efx) >= FALCON_REV_B0) {
int csum = !(efx->net_dev->features & NETIF_F_IP_CSUM);
EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, csum);
EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, csum);
@@ -474,7 +465,7 @@ int falcon_init_tx(struct efx_tx_queue *tx_queue)
falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
tx_queue->queue);
- if (FALCON_REV(efx) < FALCON_REV_B0) {
+ if (falcon_rev(efx) < FALCON_REV_B0) {
efx_oword_t reg;
BUG_ON(tx_queue->queue >= 128); /* HW limit */
@@ -635,7 +626,7 @@ int falcon_init_rx(struct efx_rx_queue *rx_queue)
efx_oword_t rx_desc_ptr;
struct efx_nic *efx = rx_queue->efx;
int rc;
- int is_b0 = FALCON_REV(efx) >= FALCON_REV_B0;
+ int is_b0 = falcon_rev(efx) >= FALCON_REV_B0;
int iscsi_digest_en = is_b0;
EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n",
@@ -742,8 +733,10 @@ void falcon_fini_rx(struct efx_rx_queue *rx_queue)
continue;
break;
}
- if (rc)
+ if (rc) {
EFX_ERR(efx, "failed to flush rx queue %d\n", rx_queue->queue);
+ efx_schedule_reset(efx, RESET_TYPE_INVISIBLE);
+ }
/* Remove RX descriptor ring from card */
EFX_ZERO_OWORD(rx_desc_ptr);
@@ -822,10 +815,10 @@ static inline void falcon_handle_tx_event(struct efx_channel *channel,
tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL);
tx_queue = &efx->tx_queue[tx_ev_q_label];
- if (NET_DEV_REGISTERED(efx))
+ if (efx_dev_registered(efx))
netif_tx_lock(efx->net_dev);
falcon_notify_tx_desc(tx_queue);
- if (NET_DEV_REGISTERED(efx))
+ if (efx_dev_registered(efx))
netif_tx_unlock(efx->net_dev);
} else if (EFX_QWORD_FIELD(*event, TX_EV_PKT_ERR) &&
EFX_WORKAROUND_10727(efx)) {
@@ -884,7 +877,7 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
RX_EV_TCP_UDP_CHKSUM_ERR);
rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, RX_EV_ETH_CRC_ERR);
rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, RX_EV_FRM_TRUNC);
- rx_ev_drib_nib = ((FALCON_REV(efx) >= FALCON_REV_B0) ?
+ rx_ev_drib_nib = ((falcon_rev(efx) >= FALCON_REV_B0) ?
0 : EFX_QWORD_FIELD(*event, RX_EV_DRIB_NIB));
rx_ev_pause_frm = EFX_QWORD_FIELD(*event, RX_EV_PAUSE_FRM_ERR);
@@ -1065,7 +1058,7 @@ static void falcon_handle_global_event(struct efx_channel *channel,
EFX_QWORD_FIELD(*event, XG_PHY_INTR))
is_phy_event = 1;
- if ((FALCON_REV(efx) >= FALCON_REV_B0) &&
+ if ((falcon_rev(efx) >= FALCON_REV_B0) &&
EFX_OWORD_FIELD(*event, XG_MNT_INTR_B0))
is_phy_event = 1;
@@ -1405,7 +1398,7 @@ static inline void falcon_irq_ack_a1(struct efx_nic *efx)
static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx)
{
struct falcon_nic_data *nic_data = efx->nic_data;
- efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
+ efx_oword_t *int_ker = efx->irq_status.addr;
efx_oword_t fatal_intr;
int error, mem_perr;
static int n_int_errors;
@@ -1451,8 +1444,8 @@ out:
*/
static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id)
{
- struct efx_nic *efx = (struct efx_nic *)dev_id;
- efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
+ struct efx_nic *efx = dev_id;
+ efx_oword_t *int_ker = efx->irq_status.addr;
struct efx_channel *channel;
efx_dword_t reg;
u32 queues;
@@ -1489,8 +1482,8 @@ static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id)
static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
{
- struct efx_nic *efx = (struct efx_nic *)dev_id;
- efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
+ struct efx_nic *efx = dev_id;
+ efx_oword_t *int_ker = efx->irq_status.addr;
struct efx_channel *channel;
int syserr;
int queues;
@@ -1542,9 +1535,9 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
*/
static irqreturn_t falcon_msi_interrupt(int irq, void *dev_id)
{
- struct efx_channel *channel = (struct efx_channel *)dev_id;
+ struct efx_channel *channel = dev_id;
struct efx_nic *efx = channel->efx;
- efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
+ efx_oword_t *int_ker = efx->irq_status.addr;
int syserr;
efx->last_irq_cpu = raw_smp_processor_id();
@@ -1572,7 +1565,7 @@ static void falcon_setup_rss_indir_table(struct efx_nic *efx)
unsigned long offset;
efx_dword_t dword;
- if (FALCON_REV(efx) < FALCON_REV_B0)
+ if (falcon_rev(efx) < FALCON_REV_B0)
return;
for (offset = RX_RSS_INDIR_TBL_B0;
@@ -1595,7 +1588,7 @@ int falcon_init_interrupt(struct efx_nic *efx)
if (!EFX_INT_MODE_USE_MSI(efx)) {
irq_handler_t handler;
- if (FALCON_REV(efx) >= FALCON_REV_B0)
+ if (falcon_rev(efx) >= FALCON_REV_B0)
handler = falcon_legacy_interrupt_b0;
else
handler = falcon_legacy_interrupt_a1;
@@ -1636,12 +1629,13 @@ void falcon_fini_interrupt(struct efx_nic *efx)
efx_oword_t reg;
/* Disable MSI/MSI-X interrupts */
- efx_for_each_channel_with_interrupt(channel, efx)
+ efx_for_each_channel_with_interrupt(channel, efx) {
if (channel->irq)
free_irq(channel->irq, channel);
+ }
/* ACK legacy interrupt */
- if (FALCON_REV(efx) >= FALCON_REV_B0)
+ if (falcon_rev(efx) >= FALCON_REV_B0)
falcon_read(efx, &reg, INT_ISR0_B0);
else
falcon_irq_ack_a1(efx);
@@ -1732,7 +1726,7 @@ void falcon_drain_tx_fifo(struct efx_nic *efx)
efx_oword_t temp;
int count;
- if ((FALCON_REV(efx) < FALCON_REV_B0) ||
+ if ((falcon_rev(efx) < FALCON_REV_B0) ||
(efx->loopback_mode != LOOPBACK_NONE))
return;
@@ -1785,7 +1779,7 @@ void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
{
efx_oword_t temp;
- if (FALCON_REV(efx) < FALCON_REV_B0)
+ if (falcon_rev(efx) < FALCON_REV_B0)
return;
/* Isolate the MAC -> RX */
@@ -1823,7 +1817,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
MAC_SPEED, link_speed);
/* On B0, MAC backpressure can be disabled and packets get
* discarded. */
- if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ if (falcon_rev(efx) >= FALCON_REV_B0) {
EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0,
!efx->link_up);
}
@@ -1841,7 +1835,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc);
/* Unisolate the MAC -> RX */
- if (FALCON_REV(efx) >= FALCON_REV_B0)
+ if (falcon_rev(efx) >= FALCON_REV_B0)
EFX_SET_OWORD_FIELD(reg, RX_INGR_EN_B0, 1);
falcon_write(efx, &reg, RX_CFG_REG_KER);
}
@@ -1856,7 +1850,7 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
return 0;
/* Statistics fetch will fail if the MAC is in TX drain */
- if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ if (falcon_rev(efx) >= FALCON_REV_B0) {
efx_oword_t temp;
falcon_read(efx, &temp, MAC0_CTRL_REG_KER);
if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0))
@@ -1940,7 +1934,7 @@ static int falcon_gmii_wait(struct efx_nic *efx)
static void falcon_mdio_write(struct net_device *net_dev, int phy_id,
int addr, int value)
{
- struct efx_nic *efx = (struct efx_nic *)net_dev->priv;
+ struct efx_nic *efx = net_dev->priv;
unsigned int phy_id2 = phy_id & FALCON_PHY_ID_ID_MASK;
efx_oword_t reg;
@@ -2008,7 +2002,7 @@ static void falcon_mdio_write(struct net_device *net_dev, int phy_id,
* could be read, -1 will be returned. */
static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr)
{
- struct efx_nic *efx = (struct efx_nic *)net_dev->priv;
+ struct efx_nic *efx = net_dev->priv;
unsigned int phy_addr = phy_id & FALCON_PHY_ID_ID_MASK;
efx_oword_t reg;
int value = -1;
@@ -2113,7 +2107,7 @@ int falcon_probe_port(struct efx_nic *efx)
falcon_init_mdio(&efx->mii);
/* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */
- if (FALCON_REV(efx) >= FALCON_REV_B0)
+ if (falcon_rev(efx) >= FALCON_REV_B0)
efx->flow_control = EFX_FC_RX | EFX_FC_TX;
else
efx->flow_control = EFX_FC_RX;
@@ -2373,7 +2367,7 @@ static int falcon_probe_nic_variant(struct efx_nic *efx)
return -ENODEV;
}
- switch (FALCON_REV(efx)) {
+ switch (falcon_rev(efx)) {
case FALCON_REV_A0:
case 0xff:
EFX_ERR(efx, "Falcon rev A0 not supported\n");
@@ -2399,7 +2393,7 @@ static int falcon_probe_nic_variant(struct efx_nic *efx)
break;
default:
- EFX_ERR(efx, "Unknown Falcon rev %d\n", FALCON_REV(efx));
+ EFX_ERR(efx, "Unknown Falcon rev %d\n", falcon_rev(efx));
return -ENODEV;
}
@@ -2419,7 +2413,7 @@ int falcon_probe_nic(struct efx_nic *efx)
/* Allocate storage for hardware specific data */
nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL);
- efx->nic_data = (void *) nic_data;
+ efx->nic_data = nic_data;
/* Determine number of ports etc. */
rc = falcon_probe_nic_variant(efx);
@@ -2489,13 +2483,10 @@ int falcon_probe_nic(struct efx_nic *efx)
*/
int falcon_init_nic(struct efx_nic *efx)
{
- struct falcon_nic_data *data;
efx_oword_t temp;
unsigned thresh;
int rc;
- data = (struct falcon_nic_data *)efx->nic_data;
-
/* Set up the address region register. This is only needed
* for the B0 FPGA, but since we are just pushing in the
* reset defaults this may as well be unconditional. */
@@ -2562,7 +2553,7 @@ int falcon_init_nic(struct efx_nic *efx)
/* Set number of RSS queues for receive path. */
falcon_read(efx, &temp, RX_FILTER_CTL_REG);
- if (FALCON_REV(efx) >= FALCON_REV_B0)
+ if (falcon_rev(efx) >= FALCON_REV_B0)
EFX_SET_OWORD_FIELD(temp, NUM_KER, 0);
else
EFX_SET_OWORD_FIELD(temp, NUM_KER, efx->rss_queues - 1);
@@ -2600,7 +2591,7 @@ int falcon_init_nic(struct efx_nic *efx)
/* Prefetch threshold 2 => fetch when descriptor cache half empty */
EFX_SET_OWORD_FIELD(temp, TX_PREF_THRESHOLD, 2);
/* Squash TX of packets of 16 bytes or less */
- if (FALCON_REV(efx) >= FALCON_REV_B0 && EFX_WORKAROUND_9141(efx))
+ if (falcon_rev(efx) >= FALCON_REV_B0 && EFX_WORKAROUND_9141(efx))
EFX_SET_OWORD_FIELD(temp, TX_FLUSH_MIN_LEN_EN_B0, 1);
falcon_write(efx, &temp, TX_CFG2_REG_KER);
@@ -2617,7 +2608,7 @@ int falcon_init_nic(struct efx_nic *efx)
if (EFX_WORKAROUND_7575(efx))
EFX_SET_OWORD_FIELD_VER(efx, temp, RX_USR_BUF_SIZE,
(3 * 4096) / 32);
- if (FALCON_REV(efx) >= FALCON_REV_B0)
+ if (falcon_rev(efx) >= FALCON_REV_B0)
EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 1);
/* RX FIFO flow control thresholds */
@@ -2633,7 +2624,7 @@ int falcon_init_nic(struct efx_nic *efx)
falcon_write(efx, &temp, RX_CFG_REG_KER);
/* Set destination of both TX and RX Flush events */
- if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ if (falcon_rev(efx) >= FALCON_REV_B0) {
EFX_POPULATE_OWORD_1(temp, FLS_EVQ_ID, 0);
falcon_write(efx, &temp, DP_CTRL_REG);
}
@@ -2647,7 +2638,7 @@ void falcon_remove_nic(struct efx_nic *efx)
falcon_free_buffer(efx, &efx->irq_status);
- (void) falcon_reset_hw(efx, RESET_TYPE_ALL);
+ falcon_reset_hw(efx, RESET_TYPE_ALL);
/* Release the second function after the reset */
if (nic_data->pci_dev2) {
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
index 6117403b0c03..492f9bc28840 100644
--- a/drivers/net/sfc/falcon.h
+++ b/drivers/net/sfc/falcon.h
@@ -23,7 +23,10 @@ enum falcon_revision {
FALCON_REV_B0 = 2,
};
-#define FALCON_REV(efx) ((efx)->pci_dev->revision)
+static inline int falcon_rev(struct efx_nic *efx)
+{
+ return efx->pci_dev->revision;
+}
extern struct efx_nic_type falcon_a_nic_type;
extern struct efx_nic_type falcon_b_nic_type;
diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h
index 06e2d68fc3d1..6d003114eeab 100644
--- a/drivers/net/sfc/falcon_hwdefs.h
+++ b/drivers/net/sfc/falcon_hwdefs.h
@@ -1125,7 +1125,7 @@ struct falcon_nvconfig_board_v2 {
u8 port1_phy_type;
__le16 asic_sub_revision;
__le16 board_revision;
-} __attribute__ ((packed));
+} __packed;
#define NVCONFIG_BASE 0x300
#define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C
@@ -1144,6 +1144,6 @@ struct falcon_nvconfig {
__le16 board_struct_ver;
__le16 board_checksum;
struct falcon_nvconfig_board_v2 board_v2;
-} __attribute__ ((packed));
+} __packed;
#endif /* EFX_FALCON_HWDEFS_H */
diff --git a/drivers/net/sfc/falcon_io.h b/drivers/net/sfc/falcon_io.h
index ea08184ddfa9..6670cdfc41ab 100644
--- a/drivers/net/sfc/falcon_io.h
+++ b/drivers/net/sfc/falcon_io.h
@@ -56,14 +56,27 @@
#define FALCON_USE_QWORD_IO 1
#endif
-#define _falcon_writeq(efx, value, reg) \
- __raw_writeq((__force u64) (value), (efx)->membase + (reg))
-#define _falcon_writel(efx, value, reg) \
- __raw_writel((__force u32) (value), (efx)->membase + (reg))
-#define _falcon_readq(efx, reg) \
- ((__force __le64) __raw_readq((efx)->membase + (reg)))
-#define _falcon_readl(efx, reg) \
- ((__force __le32) __raw_readl((efx)->membase + (reg)))
+#ifdef FALCON_USE_QWORD_IO
+static inline void _falcon_writeq(struct efx_nic *efx, __le64 value,
+ unsigned int reg)
+{
+ __raw_writeq((__force u64)value, efx->membase + reg);
+}
+static inline __le64 _falcon_readq(struct efx_nic *efx, unsigned int reg)
+{
+ return (__force __le64)__raw_readq(efx->membase + reg);
+}
+#endif
+
+static inline void _falcon_writel(struct efx_nic *efx, __le32 value,
+ unsigned int reg)
+{
+ __raw_writel((__force u32)value, efx->membase + reg);
+}
+static inline __le32 _falcon_readl(struct efx_nic *efx, unsigned int reg)
+{
+ return (__force __le32)__raw_readl(efx->membase + reg);
+}
/* Writes to a normal 16-byte Falcon register, locking as appropriate. */
static inline void falcon_write(struct efx_nic *efx, efx_oword_t *value,
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index a74b7931a3c4..55c0d9760be8 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -221,7 +221,7 @@ static int falcon_xgmii_status(struct efx_nic *efx)
{
efx_dword_t reg;
- if (FALCON_REV(efx) < FALCON_REV_B0)
+ if (falcon_rev(efx) < FALCON_REV_B0)
return 1;
/* The ISR latches, so clear it and re-read */
@@ -241,7 +241,7 @@ static void falcon_mask_status_intr(struct efx_nic *efx, int enable)
{
efx_dword_t reg;
- if ((FALCON_REV(efx) < FALCON_REV_B0) || LOOPBACK_INTERNAL(efx))
+ if ((falcon_rev(efx) < FALCON_REV_B0) || LOOPBACK_INTERNAL(efx))
return;
/* Flush the ISR */
@@ -454,12 +454,12 @@ static int falcon_check_xaui_link_up(struct efx_nic *efx)
EFX_LOG(efx, "%s Clobbering XAUI (%d tries left).\n",
__func__, tries);
- (void) falcon_reset_xaui(efx);
+ falcon_reset_xaui(efx);
udelay(200);
tries--;
}
- EFX_ERR(efx, "Failed to bring XAUI link back up in %d tries!\n",
+ EFX_LOG(efx, "Failed to bring XAUI link back up in %d tries!\n",
max_tries);
return 0;
}
@@ -572,7 +572,7 @@ int falcon_check_xmac(struct efx_nic *efx)
xaui_link_ok = falcon_xaui_link_ok(efx);
if (EFX_WORKAROUND_5147(efx) && !xaui_link_ok)
- (void) falcon_reset_xaui(efx);
+ falcon_reset_xaui(efx);
/* Call the PHY check_hw routine */
rc = efx->phy_op->check_hw(efx);
@@ -639,7 +639,7 @@ int falcon_xmac_set_pause(struct efx_nic *efx, enum efx_fc_type flow_control)
reset = ((flow_control & EFX_FC_TX) &&
!(efx->flow_control & EFX_FC_TX));
if (EFX_WORKAROUND_11482(efx) && reset) {
- if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ if (falcon_rev(efx) >= FALCON_REV_B0) {
/* Recover by resetting the EM block */
if (efx->link_up)
falcon_drain_tx_fifo(efx);
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 59f261b4171f..5e20e7551dae 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -42,7 +42,7 @@
#ifndef EFX_DRIVER_NAME
#define EFX_DRIVER_NAME "sfc"
#endif
-#define EFX_DRIVER_VERSION "2.2.0136"
+#define EFX_DRIVER_VERSION "2.2"
#ifdef EFX_ENABLE_DEBUG
#define EFX_BUG_ON_PARANOID(x) BUG_ON(x)
@@ -52,28 +52,19 @@
#define EFX_WARN_ON_PARANOID(x) do {} while (0)
#endif
-#define NET_DEV_REGISTERED(efx) \
- ((efx)->net_dev->reg_state == NETREG_REGISTERED)
-
-/* Include net device name in log messages if it has been registered.
- * Use efx->name not efx->net_dev->name so that races with (un)registration
- * are harmless.
- */
-#define NET_DEV_NAME(efx) (NET_DEV_REGISTERED(efx) ? (efx)->name : "")
-
/* Un-rate-limited logging */
#define EFX_ERR(efx, fmt, args...) \
-dev_err(&((efx)->pci_dev->dev), "ERR: %s " fmt, NET_DEV_NAME(efx), ##args)
+dev_err(&((efx)->pci_dev->dev), "ERR: %s " fmt, efx_dev_name(efx), ##args)
#define EFX_INFO(efx, fmt, args...) \
-dev_info(&((efx)->pci_dev->dev), "INFO: %s " fmt, NET_DEV_NAME(efx), ##args)
+dev_info(&((efx)->pci_dev->dev), "INFO: %s " fmt, efx_dev_name(efx), ##args)
#ifdef EFX_ENABLE_DEBUG
#define EFX_LOG(efx, fmt, args...) \
-dev_info(&((efx)->pci_dev->dev), "DBG: %s " fmt, NET_DEV_NAME(efx), ##args)
+dev_info(&((efx)->pci_dev->dev), "DBG: %s " fmt, efx_dev_name(efx), ##args)
#else
#define EFX_LOG(efx, fmt, args...) \
-dev_dbg(&((efx)->pci_dev->dev), "DBG: %s " fmt, NET_DEV_NAME(efx), ##args)
+dev_dbg(&((efx)->pci_dev->dev), "DBG: %s " fmt, efx_dev_name(efx), ##args)
#endif
#define EFX_TRACE(efx, fmt, args...) do {} while (0)
@@ -90,11 +81,6 @@ do {if (net_ratelimit()) EFX_INFO(efx, fmt, ##args); } while (0)
#define EFX_LOG_RL(efx, fmt, args...) \
do {if (net_ratelimit()) EFX_LOG(efx, fmt, ##args); } while (0)
-/* Kernel headers may redefine inline anyway */
-#ifndef inline
-#define inline inline __attribute__ ((always_inline))
-#endif
-
/**************************************************************************
*
* Efx data structures
@@ -695,7 +681,7 @@ struct efx_nic {
struct workqueue_struct *workqueue;
struct work_struct reset_work;
struct delayed_work monitor_work;
- unsigned long membase_phys;
+ resource_size_t membase_phys;
void __iomem *membase;
spinlock_t biu_lock;
enum efx_int_mode interrupt_mode;
@@ -719,7 +705,7 @@ struct efx_nic {
unsigned n_rx_nodesc_drop_cnt;
- void *nic_data;
+ struct falcon_nic_data *nic_data;
struct mutex mac_lock;
int port_enabled;
@@ -760,6 +746,20 @@ struct efx_nic {
void *loopback_selftest;
};
+static inline int efx_dev_registered(struct efx_nic *efx)
+{
+ return efx->net_dev->reg_state == NETREG_REGISTERED;
+}
+
+/* Net device name, for inclusion in log messages if it has been registered.
+ * Use efx->name not efx->net_dev->name so that races with (un)registration
+ * are harmless.
+ */
+static inline const char *efx_dev_name(struct efx_nic *efx)
+{
+ return efx_dev_registered(efx) ? efx->name : "";
+}
+
/**
* struct efx_nic_type - Efx device type definition
* @mem_bar: Memory BAR number
@@ -795,7 +795,7 @@ struct efx_nic_type {
unsigned int txd_ring_mask;
unsigned int rxd_ring_mask;
unsigned int evq_size;
- dma_addr_t max_dma_mask;
+ u64 max_dma_mask;
unsigned int tx_dma_mask;
unsigned bug5391_mask;
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index 670622373ddf..601b001437c0 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -86,14 +86,17 @@ static unsigned int rx_refill_limit = 95;
*/
#define EFX_RXD_HEAD_ROOM 2
-/* Macros for zero-order pages (potentially) containing multiple RX buffers */
-#define RX_DATA_OFFSET(_data) \
- (((unsigned long) (_data)) & (PAGE_SIZE-1))
-#define RX_BUF_OFFSET(_rx_buf) \
- RX_DATA_OFFSET((_rx_buf)->data)
-
-#define RX_PAGE_SIZE(_efx) \
- (PAGE_SIZE * (1u << (_efx)->rx_buffer_order))
+static inline unsigned int efx_rx_buf_offset(struct efx_rx_buffer *buf)
+{
+ /* Offset is always within one page, so we don't need to consider
+ * the page order.
+ */
+ return (__force unsigned long) buf->data & (PAGE_SIZE - 1);
+}
+static inline unsigned int efx_rx_buf_size(struct efx_nic *efx)
+{
+ return PAGE_SIZE << efx->rx_buffer_order;
+}
/**************************************************************************
@@ -106,7 +109,7 @@ static unsigned int rx_refill_limit = 95;
static int efx_lro_get_skb_hdr(struct sk_buff *skb, void **ip_hdr,
void **tcpudp_hdr, u64 *hdr_flags, void *priv)
{
- struct efx_channel *channel = (struct efx_channel *)priv;
+ struct efx_channel *channel = priv;
struct iphdr *iph;
struct tcphdr *th;
@@ -131,12 +134,12 @@ static int efx_get_frag_hdr(struct skb_frag_struct *frag, void **mac_hdr,
void **ip_hdr, void **tcpudp_hdr, u64 *hdr_flags,
void *priv)
{
- struct efx_channel *channel = (struct efx_channel *)priv;
+ struct efx_channel *channel = priv;
struct ethhdr *eh;
struct iphdr *iph;
/* We support EtherII and VLAN encapsulated IPv4 */
- eh = (struct ethhdr *)(page_address(frag->page) + frag->page_offset);
+ eh = page_address(frag->page) + frag->page_offset;
*mac_hdr = eh;
if (eh->h_proto == htons(ETH_P_IP)) {
@@ -269,7 +272,7 @@ static inline int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
return -ENOMEM;
dma_addr = pci_map_page(efx->pci_dev, rx_buf->page,
- 0, RX_PAGE_SIZE(efx),
+ 0, efx_rx_buf_size(efx),
PCI_DMA_FROMDEVICE);
if (unlikely(pci_dma_mapping_error(dma_addr))) {
@@ -280,14 +283,14 @@ static inline int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
rx_queue->buf_page = rx_buf->page;
rx_queue->buf_dma_addr = dma_addr;
- rx_queue->buf_data = ((char *) page_address(rx_buf->page) +
+ rx_queue->buf_data = (page_address(rx_buf->page) +
EFX_PAGE_IP_ALIGN);
}
- offset = RX_DATA_OFFSET(rx_queue->buf_data);
rx_buf->len = bytes;
- rx_buf->dma_addr = rx_queue->buf_dma_addr + offset;
rx_buf->data = rx_queue->buf_data;
+ offset = efx_rx_buf_offset(rx_buf);
+ rx_buf->dma_addr = rx_queue->buf_dma_addr + offset;
/* Try to pack multiple buffers per page */
if (efx->rx_buffer_order == 0) {
@@ -295,7 +298,7 @@ static inline int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
rx_queue->buf_data += ((bytes + 0x1ff) & ~0x1ff);
offset += ((bytes + 0x1ff) & ~0x1ff);
- space = RX_PAGE_SIZE(efx) - offset;
+ space = efx_rx_buf_size(efx) - offset;
if (space >= bytes) {
/* Refs dropped on kernel releasing each skb */
get_page(rx_queue->buf_page);
@@ -344,7 +347,8 @@ static inline void efx_unmap_rx_buffer(struct efx_nic *efx,
EFX_BUG_ON_PARANOID(rx_buf->skb);
if (rx_buf->unmap_addr) {
pci_unmap_page(efx->pci_dev, rx_buf->unmap_addr,
- RX_PAGE_SIZE(efx), PCI_DMA_FROMDEVICE);
+ efx_rx_buf_size(efx),
+ PCI_DMA_FROMDEVICE);
rx_buf->unmap_addr = 0;
}
} else if (likely(rx_buf->skb)) {
@@ -400,9 +404,10 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
return 0;
/* Record minimum fill level */
- if (unlikely(fill_level < rx_queue->min_fill))
+ if (unlikely(fill_level < rx_queue->min_fill)) {
if (fill_level)
rx_queue->min_fill = fill_level;
+ }
/* Acquire RX add lock. If this lock is contended, then a fast
* fill must already be in progress (e.g. in the refill
@@ -552,7 +557,7 @@ static inline void efx_rx_packet_lro(struct efx_channel *channel,
struct skb_frag_struct frags;
frags.page = rx_buf->page;
- frags.page_offset = RX_BUF_OFFSET(rx_buf);
+ frags.page_offset = efx_rx_buf_offset(rx_buf);
frags.size = rx_buf->len;
lro_receive_frags(lro_mgr, &frags, rx_buf->len,
@@ -597,7 +602,7 @@ static inline struct sk_buff *efx_rx_mk_skb(struct efx_rx_buffer *rx_buf,
if (unlikely(rx_buf->len > hdr_len)) {
struct skb_frag_struct *frag = skb_shinfo(skb)->frags;
frag->page = rx_buf->page;
- frag->page_offset = RX_BUF_OFFSET(rx_buf) + hdr_len;
+ frag->page_offset = efx_rx_buf_offset(rx_buf) + hdr_len;
frag->size = skb->len - hdr_len;
skb_shinfo(skb)->nr_frags = 1;
skb->data_len = frag->size;
@@ -851,7 +856,8 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
/* For a page that is part-way through splitting into RX buffers */
if (rx_queue->buf_page != NULL) {
pci_unmap_page(rx_queue->efx->pci_dev, rx_queue->buf_dma_addr,
- RX_PAGE_SIZE(rx_queue->efx), PCI_DMA_FROMDEVICE);
+ efx_rx_buf_size(rx_queue->efx),
+ PCI_DMA_FROMDEVICE);
__free_pages(rx_queue->buf_page,
rx_queue->efx->rx_buffer_order);
rx_queue->buf_page = NULL;
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index cbda15946e8f..3b2de9fe7f27 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -290,7 +290,7 @@ void efx_loopback_rx_packet(struct efx_nic *efx,
payload = &state->payload;
- received = (struct efx_loopback_payload *)(char *) buf_ptr;
+ received = (struct efx_loopback_payload *) buf_ptr;
received->ip.saddr = payload->ip.saddr;
received->ip.check = payload->ip.check;
@@ -424,10 +424,10 @@ static int efx_tx_loopback(struct efx_tx_queue *tx_queue)
* interrupt handler. */
smp_wmb();
- if (NET_DEV_REGISTERED(efx))
+ if (efx_dev_registered(efx))
netif_tx_lock_bh(efx->net_dev);
rc = efx_xmit(efx, tx_queue, skb);
- if (NET_DEV_REGISTERED(efx))
+ if (efx_dev_registered(efx))
netif_tx_unlock_bh(efx->net_dev);
if (rc != NETDEV_TX_OK) {
@@ -453,7 +453,7 @@ static int efx_rx_loopback(struct efx_tx_queue *tx_queue,
int tx_done = 0, rx_good, rx_bad;
int i, rc = 0;
- if (NET_DEV_REGISTERED(efx))
+ if (efx_dev_registered(efx))
netif_tx_lock_bh(efx->net_dev);
/* Count the number of tx completions, and decrement the refcnt. Any
@@ -465,7 +465,7 @@ static int efx_rx_loopback(struct efx_tx_queue *tx_queue,
dev_kfree_skb_any(skb);
}
- if (NET_DEV_REGISTERED(efx))
+ if (efx_dev_registered(efx))
netif_tx_unlock_bh(efx->net_dev);
/* Check TX completion and received packet counts */
@@ -517,6 +517,8 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
state->packet_count = min(1 << (i << 2), state->packet_count);
state->skbs = kzalloc(sizeof(state->skbs[0]) *
state->packet_count, GFP_KERNEL);
+ if (!state->skbs)
+ return -ENOMEM;
state->flush = 0;
EFX_LOG(efx, "TX queue %d testing %s loopback with %d "
@@ -700,7 +702,7 @@ int efx_offline_test(struct efx_nic *efx,
* "flushing" so all inflight packets are dropped */
BUG_ON(efx->loopback_selftest);
state->flush = 1;
- efx->loopback_selftest = (void *)state;
+ efx->loopback_selftest = state;
rc = efx_test_loopbacks(efx, tests, loopback_modes);
diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c
index 725d1a539c49..66a0d1442aba 100644
--- a/drivers/net/sfc/sfe4001.c
+++ b/drivers/net/sfc/sfe4001.c
@@ -116,18 +116,18 @@ void sfe4001_poweroff(struct efx_nic *efx)
/* Turn off all power rails */
out = 0xff;
- (void) efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+ efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
/* Disable port 1 outputs on IO expander */
cfg = 0xff;
- (void) efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
+ efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
/* Disable port 0 outputs on IO expander */
cfg = 0xff;
- (void) efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
+ efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
/* Clear any over-temperature alert */
- (void) efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
+ efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
}
/* The P0_EN_3V3X line on SFE4001 boards (from A2 onward) is connected
@@ -253,14 +253,14 @@ done:
fail3:
/* Turn off all power rails */
out = 0xff;
- (void) efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+ efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
/* Disable port 1 outputs on IO expander */
out = 0xff;
- (void) efx_i2c_write(i2c, PCA9539, P1_CONFIG, &out, 1);
+ efx_i2c_write(i2c, PCA9539, P1_CONFIG, &out, 1);
fail2:
/* Disable port 0 outputs on IO expander */
out = 0xff;
- (void) efx_i2c_write(i2c, PCA9539, P0_CONFIG, &out, 1);
+ efx_i2c_write(i2c, PCA9539, P0_CONFIG, &out, 1);
fail1:
return rc;
}
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index b1cd6deec01f..c0146061c326 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -211,6 +211,8 @@ static int tenxpress_phy_init(struct efx_nic *efx)
int rc = 0;
phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
+ if (!phy_data)
+ return -ENOMEM;
efx->phy_data = phy_data;
tenxpress_set_state(efx, TENXPRESS_STATUS_NORMAL);
@@ -376,7 +378,7 @@ static void tenxpress_phy_reconfigure(struct efx_nic *efx)
* perform a special software reset */
if ((phy_data->tx_disabled && !efx->tx_disabled) ||
loop_change) {
- (void) tenxpress_special_reset(efx);
+ tenxpress_special_reset(efx);
falcon_reset_xaui(efx);
}
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c
index 9b436f5b4888..5cdd082ab8f6 100644
--- a/drivers/net/sfc/tx.c
+++ b/drivers/net/sfc/tx.c
@@ -387,7 +387,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
if (unlikely(tx_queue->stopped)) {
fill_level = tx_queue->insert_count - tx_queue->read_count;
if (fill_level < EFX_NETDEV_TX_THRESHOLD(tx_queue)) {
- EFX_BUG_ON_PARANOID(!NET_DEV_REGISTERED(efx));
+ EFX_BUG_ON_PARANOID(!efx_dev_registered(efx));
/* Do this under netif_tx_lock(), to avoid racing
* with efx_xmit(). */
@@ -639,11 +639,12 @@ static void efx_tsoh_block_free(struct efx_tx_queue *tx_queue,
base_dma = tsoh->dma_addr & PAGE_MASK;
p = &tx_queue->tso_headers_free;
- while (*p != NULL)
+ while (*p != NULL) {
if (((unsigned long)*p & PAGE_MASK) == base_kva)
*p = (*p)->next;
else
p = &(*p)->next;
+ }
pci_free_consistent(pci_dev, PAGE_SIZE, (void *)base_kva, base_dma);
}
@@ -939,9 +940,10 @@ static inline int tso_start_new_packet(struct efx_tx_queue *tx_queue,
/* Allocate a DMA-mapped header buffer. */
if (likely(TSOH_SIZE(st->p.header_length) <= TSOH_STD_SIZE)) {
- if (tx_queue->tso_headers_free == NULL)
+ if (tx_queue->tso_headers_free == NULL) {
if (efx_tsoh_block_alloc(tx_queue))
return -1;
+ }
EFX_BUG_ON_PARANOID(!tx_queue->tso_headers_free);
tsoh = tx_queue->tso_headers_free;
tx_queue->tso_headers_free = tsoh->next;
@@ -1106,9 +1108,10 @@ static void efx_fini_tso(struct efx_tx_queue *tx_queue)
{
unsigned i;
- if (tx_queue->buffer)
+ if (tx_queue->buffer) {
for (i = 0; i <= tx_queue->efx->type->txd_ring_mask; ++i)
efx_tsoh_free(tx_queue, &tx_queue->buffer[i]);
+ }
while (tx_queue->tso_headers_free != NULL)
efx_tsoh_block_free(tx_queue, tx_queue->tso_headers_free,
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index dca62f190198..35ab19c27f8d 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -16,7 +16,7 @@
*/
#define EFX_WORKAROUND_ALWAYS(efx) 1
-#define EFX_WORKAROUND_FALCON_A(efx) (FALCON_REV(efx) <= FALCON_REV_A1)
+#define EFX_WORKAROUND_FALCON_A(efx) (falcon_rev(efx) <= FALCON_REV_A1)
/* XAUI resets if link not detected */
#define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS
diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c
index 3b9f9ddbc372..f3684ad28887 100644
--- a/drivers/net/sfc/xfp_phy.c
+++ b/drivers/net/sfc/xfp_phy.c
@@ -85,7 +85,9 @@ static int xfp_phy_init(struct efx_nic *efx)
int rc;
phy_data = kzalloc(sizeof(struct xfp_phy_data), GFP_KERNEL);
- efx->phy_data = (void *) phy_data;
+ if (!phy_data)
+ return -ENOMEM;
+ efx->phy_data = phy_data;
EFX_INFO(efx, "XFP: PHY ID reg %x (OUI %x model %x revision"
" %x)\n", devid, MDIO_ID_OUI(devid), MDIO_ID_MODEL(devid),
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index f226bcac7d17..c8a5ef2d75f4 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -118,6 +118,7 @@ static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4352) }, /* 88E8038 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4353) }, /* 88E8039 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4354) }, /* 88E8040 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4355) }, /* 88E8040T */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4356) }, /* 88EC033 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4357) }, /* 88E8042 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x435A) }, /* 88E8048 */
@@ -1159,17 +1160,9 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
#ifdef SKY2_VLAN_TAG_USED
-static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+static void sky2_set_vlan_mode(struct sky2_hw *hw, u16 port, bool onoff)
{
- struct sky2_port *sky2 = netdev_priv(dev);
- struct sky2_hw *hw = sky2->hw;
- u16 port = sky2->port;
-
- netif_tx_lock_bh(dev);
- napi_disable(&hw->napi);
-
- sky2->vlgrp = grp;
- if (grp) {
+ if (onoff) {
sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
RX_VLAN_STRIP_ON);
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
@@ -1180,6 +1173,19 @@ static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
TX_VLAN_TAG_OFF);
}
+}
+
+static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+{
+ struct sky2_port *sky2 = netdev_priv(dev);
+ struct sky2_hw *hw = sky2->hw;
+ u16 port = sky2->port;
+
+ netif_tx_lock_bh(dev);
+ napi_disable(&hw->napi);
+
+ sky2->vlgrp = grp;
+ sky2_set_vlan_mode(hw, port, grp != NULL);
sky2_read32(hw, B0_Y2_SP_LISR);
napi_enable(&hw->napi);
@@ -1418,6 +1424,10 @@ static int sky2_up(struct net_device *dev)
sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map,
TX_RING_SIZE - 1);
+#ifdef SKY2_VLAN_TAG_USED
+ sky2_set_vlan_mode(hw, port, sky2->vlgrp != NULL);
+#endif
+
err = sky2_rx_start(sky2);
if (err)
goto err_out;
@@ -4395,7 +4405,9 @@ static int sky2_resume(struct pci_dev *pdev)
if (err) {
printk(KERN_ERR PFX "%s: could not up: %d\n",
dev->name, err);
+ rtnl_lock();
dev_close(dev);
+ rtnl_unlock();
goto out;
}
}
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 4e2800205189..e2ee91a6ae7e 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -136,7 +136,6 @@ struct smc911x_local {
/* work queue */
struct work_struct phy_configure;
- int work_pending;
int tx_throttle;
spinlock_t lock;
@@ -960,11 +959,11 @@ static void smc911x_phy_configure(struct work_struct *work)
* We should not be called if phy_type is zero.
*/
if (lp->phy_type == 0)
- goto smc911x_phy_configure_exit_nolock;
+ return;
if (smc911x_phy_reset(dev, phyaddr)) {
printk("%s: PHY reset timed out\n", dev->name);
- goto smc911x_phy_configure_exit_nolock;
+ return;
}
spin_lock_irqsave(&lp->lock, flags);
@@ -1033,8 +1032,6 @@ static void smc911x_phy_configure(struct work_struct *work)
smc911x_phy_configure_exit:
spin_unlock_irqrestore(&lp->lock, flags);
-smc911x_phy_configure_exit_nolock:
- lp->work_pending = 0;
}
/*
@@ -1356,11 +1353,8 @@ static void smc911x_timeout(struct net_device *dev)
* smc911x_phy_configure() calls msleep() which calls schedule_timeout()
* which calls schedule(). Hence we use a work queue.
*/
- if (lp->phy_type != 0) {
- if (schedule_work(&lp->phy_configure)) {
- lp->work_pending = 1;
- }
- }
+ if (lp->phy_type != 0)
+ schedule_work(&lp->phy_configure);
/* We can accept TX packets again */
dev->trans_start = jiffies;
@@ -1531,16 +1525,8 @@ static int smc911x_close(struct net_device *dev)
if (lp->phy_type != 0) {
/* We need to ensure that no calls to
* smc911x_phy_configure are pending.
-
- * flush_scheduled_work() cannot be called because we
- * are running with the netlink semaphore held (from
- * devinet_ioctl()) and the pending work queue
- * contains linkwatch_event() (scheduled by
- * netif_carrier_off() above). linkwatch_event() also
- * wants the netlink semaphore.
*/
- while (lp->work_pending)
- schedule();
+ cancel_work_sync(&lp->phy_configure);
smc911x_phy_powerdown(dev, lp->mii.phy_id);
}
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index a188e33484e6..f2051b209da2 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -1016,15 +1016,8 @@ static void smc_phy_powerdown(struct net_device *dev)
/* We need to ensure that no calls to smc_phy_configure are
pending.
-
- flush_scheduled_work() cannot be called because we are
- running with the netlink semaphore held (from
- devinet_ioctl()) and the pending work queue contains
- linkwatch_event() (scheduled by netif_carrier_off()
- above). linkwatch_event() also wants the netlink semaphore.
*/
- while(lp->work_pending)
- yield();
+ cancel_work_sync(&lp->phy_configure);
bmcr = smc_phy_read(dev, phy, MII_BMCR);
smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN);
@@ -1161,7 +1154,6 @@ static void smc_phy_configure(struct work_struct *work)
smc_phy_configure_exit:
SMC_SELECT_BANK(lp, 2);
spin_unlock_irq(&lp->lock);
- lp->work_pending = 0;
}
/*
@@ -1389,11 +1381,8 @@ static void smc_timeout(struct net_device *dev)
* smc_phy_configure() calls msleep() which calls schedule_timeout()
* which calls schedule(). Hence we use a work queue.
*/
- if (lp->phy_type != 0) {
- if (schedule_work(&lp->phy_configure)) {
- lp->work_pending = 1;
- }
- }
+ if (lp->phy_type != 0)
+ schedule_work(&lp->phy_configure);
/* We can accept TX packets again */
dev->trans_start = jiffies;
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index 69e97a1cb1c4..8606818653f8 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -93,14 +93,14 @@
#define SMC_insw(a, r, p, l) insw ((unsigned long *)((a) + (r)), p, l)
# endif
/* check if the mac in reg is valid */
-#define SMC_GET_MAC_ADDR(addr) \
+#define SMC_GET_MAC_ADDR(lp, addr) \
do { \
unsigned int __v; \
- __v = SMC_inw(ioaddr, ADDR0_REG); \
+ __v = SMC_inw(ioaddr, ADDR0_REG(lp)); \
addr[0] = __v; addr[1] = __v >> 8; \
- __v = SMC_inw(ioaddr, ADDR1_REG); \
+ __v = SMC_inw(ioaddr, ADDR1_REG(lp)); \
addr[2] = __v; addr[3] = __v >> 8; \
- __v = SMC_inw(ioaddr, ADDR2_REG); \
+ __v = SMC_inw(ioaddr, ADDR2_REG(lp)); \
addr[4] = __v; addr[5] = __v >> 8; \
if (*(u32 *)(&addr[0]) == 0xFFFFFFFF) { \
random_ether_addr(addr); \
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index b4e7f30ea4e8..1aa425be3067 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -111,7 +111,7 @@ static __inline__ void tx_add_log(struct happy_meal *hp, unsigned int a, unsigne
struct hme_tx_logent *tlp;
unsigned long flags;
- save_and_cli(flags);
+ local_irq_save(flags);
tlp = &tx_log[txlog_cur_entry];
tlp->tstamp = (unsigned int)jiffies;
tlp->tx_new = hp->tx_new;
@@ -119,7 +119,7 @@ static __inline__ void tx_add_log(struct happy_meal *hp, unsigned int a, unsigne
tlp->action = a;
tlp->status = s;
txlog_cur_entry = (txlog_cur_entry + 1) & (TX_LOG_LEN - 1);
- restore_flags(flags);
+ local_irq_restore(flags);
}
static __inline__ void tx_dump_log(void)
{
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index 10e4e85da3fc..b07b8cbadeaf 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -1394,6 +1394,7 @@ tc35815_open(struct net_device *dev)
tc35815_chip_init(dev);
spin_unlock_irq(&lp->lock);
+ netif_carrier_off(dev);
/* schedule a link state check */
phy_start(lp->phy_dev);
@@ -1735,7 +1736,6 @@ tc35815_rx(struct net_device *dev)
skb = lp->rx_skbs[cur_bd].skb;
prefetch(skb->data);
lp->rx_skbs[cur_bd].skb = NULL;
- lp->fbl_count--;
pci_unmap_single(lp->pci_dev,
lp->rx_skbs[cur_bd].skb_dma,
RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
@@ -1791,6 +1791,7 @@ tc35815_rx(struct net_device *dev)
#ifdef TC35815_USE_PACKEDBUFFER
while (lp->fbl_curid != id)
#else
+ lp->fbl_count--;
while (lp->fbl_count < RX_BUF_NUM)
#endif
{
@@ -2453,6 +2454,7 @@ static int tc35815_resume(struct pci_dev *pdev)
return 0;
pci_set_power_state(pdev, PCI_D0);
tc35815_restart(dev);
+ netif_carrier_off(dev);
if (lp->phy_dev)
phy_start(lp->phy_dev);
netif_device_attach(dev);
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 07b3f77e7626..cc4bde852542 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -64,8 +64,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.92"
-#define DRV_MODULE_RELDATE "May 2, 2008"
+#define DRV_MODULE_VERSION "3.92.1"
+#define DRV_MODULE_RELDATE "June 9, 2008"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -1295,6 +1295,21 @@ static void tg3_frob_aux_power(struct tg3 *tp)
GRC_LCLCTRL_GPIO_OUTPUT0 |
GRC_LCLCTRL_GPIO_OUTPUT1),
100);
+ } else if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761) {
+ /* The 5761 non-e device swaps GPIO 0 and GPIO 2. */
+ u32 grc_local_ctrl = GRC_LCLCTRL_GPIO_OE0 |
+ GRC_LCLCTRL_GPIO_OE1 |
+ GRC_LCLCTRL_GPIO_OE2 |
+ GRC_LCLCTRL_GPIO_OUTPUT0 |
+ GRC_LCLCTRL_GPIO_OUTPUT1 |
+ tp->grc_local_ctrl;
+ tw32_wait_f(GRC_LOCAL_CTRL, grc_local_ctrl, 100);
+
+ grc_local_ctrl |= GRC_LCLCTRL_GPIO_OUTPUT2;
+ tw32_wait_f(GRC_LOCAL_CTRL, grc_local_ctrl, 100);
+
+ grc_local_ctrl &= ~GRC_LCLCTRL_GPIO_OUTPUT0;
+ tw32_wait_f(GRC_LOCAL_CTRL, grc_local_ctrl, 100);
} else {
u32 no_gpio2;
u32 grc_local_ctrl = 0;
@@ -3168,8 +3183,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
err |= tg3_readphy(tp, MII_BMCR, &bmcr);
if ((tp->link_config.autoneg == AUTONEG_ENABLE) && !force_reset &&
- (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
- tp->link_config.flowctrl == tp->link_config.active_flowctrl) {
+ (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT)) {
/* do nothing, just check for link up at the end */
} else if (tp->link_config.autoneg == AUTONEG_ENABLE) {
u32 adv, new_adv;
@@ -8599,7 +8613,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
(cmd->speed == SPEED_1000))
return -EINVAL;
else if ((cmd->speed == SPEED_1000) &&
- (tp->tg3_flags2 & TG3_FLAG_10_100_ONLY))
+ (tp->tg3_flags & TG3_FLAG_10_100_ONLY))
return -EINVAL;
tg3_full_lock(tp, 0);
@@ -11768,6 +11782,15 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL;
+ if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761) {
+ /* Turn off the debug UART. */
+ tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL;
+ if (tp->tg3_flags2 & TG3_FLG2_IS_NIC)
+ /* Keep VMain power. */
+ tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE0 |
+ GRC_LCLCTRL_GPIO_OUTPUT0;
+ }
+
/* Force the chip into D0. */
err = tg3_set_power_state(tp, PCI_D0);
if (err) {
diff --git a/drivers/net/tokenring/3c359.h b/drivers/net/tokenring/3c359.h
index b880cba0f6fd..74cf8e1a181b 100644
--- a/drivers/net/tokenring/3c359.h
+++ b/drivers/net/tokenring/3c359.h
@@ -264,7 +264,7 @@ struct xl_private {
u16 asb;
u8 __iomem *xl_mmio;
- char *xl_card_name;
+ const char *xl_card_name;
struct pci_dev *pdev ;
spinlock_t xl_lock ;
diff --git a/drivers/net/tokenring/olympic.h b/drivers/net/tokenring/olympic.h
index c91956310fb2..10fbba08978f 100644
--- a/drivers/net/tokenring/olympic.h
+++ b/drivers/net/tokenring/olympic.h
@@ -254,7 +254,7 @@ struct olympic_private {
u8 __iomem *olympic_mmio;
u8 __iomem *olympic_lap;
struct pci_dev *pdev ;
- char *olympic_card_name ;
+ const char *olympic_card_name;
spinlock_t olympic_lock ;
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index f9d13fa05d64..af8d2c436efd 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -731,7 +731,7 @@ static void tulip_down (struct net_device *dev)
void __iomem *ioaddr = tp->base_addr;
unsigned long flags;
- flush_scheduled_work();
+ cancel_work_sync(&tp->media_work);
#ifdef CONFIG_TULIP_NAPI
napi_disable(&tp->napi);
@@ -1729,12 +1729,15 @@ static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
if (!dev)
return -EINVAL;
- if (netif_running(dev))
- tulip_down(dev);
+ if (!netif_running(dev))
+ goto save_state;
+
+ tulip_down(dev);
netif_device_detach(dev);
free_irq(dev->irq, dev);
+save_state:
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -1754,6 +1757,9 @@ static int tulip_resume(struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
+ if (!netif_running(dev))
+ return 0;
+
if ((retval = pci_enable_device(pdev))) {
printk (KERN_ERR "tulip: pci_enable_device failed in resume\n");
return retval;
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index 2511ca7a12aa..e9e628621639 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -225,6 +225,9 @@ static void uli526x_set_filter_mode(struct net_device *);
static const struct ethtool_ops netdev_ethtool_ops;
static u16 read_srom_word(long, int);
static irqreturn_t uli526x_interrupt(int, void *);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void uli526x_poll(struct net_device *dev);
+#endif
static void uli526x_descriptor_init(struct uli526x_board_info *, unsigned long);
static void allocate_rx_buffer(struct uli526x_board_info *);
static void update_cr6(u32, unsigned long);
@@ -339,6 +342,9 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
dev->get_stats = &uli526x_get_stats;
dev->set_multicast_list = &uli526x_set_filter_mode;
dev->ethtool_ops = &netdev_ethtool_ops;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = &uli526x_poll;
+#endif
spin_lock_init(&db->lock);
@@ -681,8 +687,9 @@ static irqreturn_t uli526x_interrupt(int irq, void *dev_id)
db->cr5_data = inl(ioaddr + DCR5);
outl(db->cr5_data, ioaddr + DCR5);
if ( !(db->cr5_data & 0x180c1) ) {
- spin_unlock_irqrestore(&db->lock, flags);
+ /* Restore CR7 to enable interrupt mask */
outl(db->cr7_data, ioaddr + DCR7);
+ spin_unlock_irqrestore(&db->lock, flags);
return IRQ_HANDLED;
}
@@ -715,6 +722,13 @@ static irqreturn_t uli526x_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void uli526x_poll(struct net_device *dev)
+{
+ /* ISR grabs the irqsave lock, so this should be safe */
+ uli526x_interrupt(dev->irq, dev);
+}
+#endif
/*
* Free TX resource after TX complete
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 4c0c5972a489..eba1271b9735 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -314,6 +314,21 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv,
switch (tun->flags & TUN_TYPE_MASK) {
case TUN_TUN_DEV:
+ if (tun->flags & TUN_NO_PI) {
+ switch (skb->data[0] & 0xf0) {
+ case 0x40:
+ pi.proto = htons(ETH_P_IP);
+ break;
+ case 0x60:
+ pi.proto = htons(ETH_P_IPV6);
+ break;
+ default:
+ tun->dev->stats.rx_dropped++;
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+ }
+
skb_reset_mac_header(skb);
skb->protocol = pi.proto;
skb->dev = tun->dev;
@@ -588,6 +603,12 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
tun->attached = 1;
get_net(dev_net(tun->dev));
+ /* Make sure persistent devices do not get stuck in
+ * xoff state.
+ */
+ if (netif_running(tun->dev))
+ netif_wake_queue(tun->dev);
+
strcpy(ifr->ifr_name, tun->dev->name);
return 0;
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index ca0bdac07a78..fb0b918e5ccb 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -237,7 +237,7 @@ static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth,
skb->dev = ugeth->dev;
out_be32(&((struct qe_bd __iomem *)bd)->buf,
- dma_map_single(NULL,
+ dma_map_single(&ugeth->dev->dev,
skb->data,
ugeth->ug_info->uf_info.max_rx_buf_length +
UCC_GETH_RX_DATA_BUF_ALIGNMENT,
@@ -2158,7 +2158,7 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
continue;
for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) {
if (ugeth->tx_skbuff[i][j]) {
- dma_unmap_single(NULL,
+ dma_unmap_single(&ugeth->dev->dev,
in_be32(&((struct qe_bd __iomem *)bd)->buf),
(in_be32((u32 __iomem *)bd) &
BD_LENGTH_MASK),
@@ -2186,7 +2186,7 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
bd = ugeth->p_rx_bd_ring[i];
for (j = 0; j < ugeth->ug_info->bdRingLenRx[i]; j++) {
if (ugeth->rx_skbuff[i][j]) {
- dma_unmap_single(NULL,
+ dma_unmap_single(&ugeth->dev->dev,
in_be32(&((struct qe_bd __iomem *)bd)->buf),
ugeth->ug_info->
uf_info.max_rx_buf_length +
@@ -3406,7 +3406,8 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* set up the buffer descriptor */
out_be32(&((struct qe_bd __iomem *)bd)->buf,
- dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE));
+ dma_map_single(&ugeth->dev->dev, skb->data,
+ skb->len, DMA_TO_DEVICE));
/* printk(KERN_DEBUG"skb->data is 0x%x\n",skb->data); */
diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c
index 299b7f176950..f5839c4a5cbd 100644
--- a/drivers/net/ucc_geth_ethtool.c
+++ b/drivers/net/ucc_geth_ethtool.c
@@ -73,6 +73,7 @@ static char tx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
"tx-frames-ok",
"tx-excessive-differ-frames",
"tx-256-511-frames",
+ "tx-512-1023-frames",
"tx-1024-1518-frames",
"tx-jumbo-frames",
};
@@ -308,7 +309,7 @@ static void uec_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
buf += UEC_TX_FW_STATS_LEN * ETH_GSTRING_LEN;
}
if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
- memcpy(buf, tx_fw_stat_gstrings, UEC_RX_FW_STATS_LEN *
+ memcpy(buf, rx_fw_stat_gstrings, UEC_RX_FW_STATS_LEN *
ETH_GSTRING_LEN);
}
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index dc6f097062df..37ecf845edfe 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -1440,6 +1440,10 @@ static const struct usb_device_id products [] = {
// Belkin F5D5055
USB_DEVICE(0x050d, 0x5055),
.driver_info = (unsigned long) &ax88178_info,
+}, {
+ // Apple USB Ethernet Adapter
+ USB_DEVICE(0x05ac, 0x1402),
+ .driver_info = (unsigned long) &ax88772_info,
},
{ }, // END
};
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index 76752d84a30f..22c17bbacb69 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -423,7 +423,10 @@ static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
catc->tx_ptr = (((catc->tx_ptr - 1) >> 6) + 1) << 6;
tx_buf = catc->tx_buf[catc->tx_idx] + catc->tx_ptr;
- *((u16*)tx_buf) = (catc->is_f5u011) ? cpu_to_be16((u16)skb->len) : cpu_to_le16((u16)skb->len);
+ if (catc->is_f5u011)
+ *(__be16 *)tx_buf = cpu_to_be16(skb->len);
+ else
+ *(__le16 *)tx_buf = cpu_to_le16(skb->len);
skb_copy_from_linear_data(skb, tx_buf + 2, skb->len);
catc->tx_ptr += skb->len + 2;
diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c
index 0ec7936cbe21..c66b9c324f54 100644
--- a/drivers/net/usb/cdc_subset.c
+++ b/drivers/net/usb/cdc_subset.c
@@ -218,7 +218,7 @@ static const struct driver_info blob_info = {
/*-------------------------------------------------------------------------*/
#ifndef HAVE_HARDWARE
-#error You need to configure some hardware for this driver
+#warning You need to configure some hardware for this driver
#endif
/*
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index 0dcfc0310264..7c66b052f55a 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -706,7 +706,7 @@ static void kaweth_kill_urbs(struct kaweth_device *kaweth)
usb_kill_urb(kaweth->rx_urb);
usb_kill_urb(kaweth->tx_urb);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&kaweth->lowmem_work);
/* a scheduled work may have resubmitted,
we hit them again */
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index 21a7785cb8b6..ae467f182c40 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -194,7 +194,7 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
dev_dbg(&info->control->dev,
"rndis response error, code %d\n", retval);
}
- msleep(2);
+ msleep(20);
}
dev_dbg(&info->control->dev, "rndis response timeout\n");
return -ETIMEDOUT;
@@ -283,8 +283,8 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags)
struct rndis_set_c *set_c;
struct rndis_halt *halt;
} u;
- u32 tmp, phym_unspec;
- __le32 *phym;
+ u32 tmp;
+ __le32 phym_unspec, *phym;
int reply_len;
unsigned char *bp;
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index f926b5ab3d09..4452306d5328 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -44,9 +44,16 @@ struct virtnet_info
/* The skb we couldn't send because buffers were full. */
struct sk_buff *last_xmit_skb;
+ /* If we need to free in a timer, this is it. */
+ struct timer_list xmit_free_timer;
+
/* Number of input buffers, and max we've ever had. */
unsigned int num, max;
+ /* For cleaning up after transmission. */
+ struct tasklet_struct tasklet;
+ bool free_in_tasklet;
+
/* Receive & send queues. */
struct sk_buff_head recv;
struct sk_buff_head send;
@@ -68,8 +75,13 @@ static void skb_xmit_done(struct virtqueue *svq)
/* Suppress further interrupts. */
svq->vq_ops->disable_cb(svq);
- /* We were waiting for more output buffers. */
+
+ /* We were probably waiting for more output buffers. */
netif_wake_queue(vi->dev);
+
+ /* Make sure we re-xmit last_xmit_skb: if there are no more packets
+ * queued, start_xmit won't be called. */
+ tasklet_schedule(&vi->tasklet);
}
static void receive_skb(struct net_device *dev, struct sk_buff *skb,
@@ -86,9 +98,7 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
BUG_ON(len > MAX_PACKET_LEN);
skb_trim(skb, len);
- skb->protocol = eth_type_trans(skb, dev);
- pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
- ntohs(skb->protocol), skb->len, skb->pkt_type);
+
dev->stats.rx_bytes += skb->len;
dev->stats.rx_packets++;
@@ -98,6 +108,10 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
goto frame_err;
}
+ skb->protocol = eth_type_trans(skb, dev);
+ pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
+ ntohs(skb->protocol), skb->len, skb->pkt_type);
+
if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
pr_debug("GSO!\n");
switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
@@ -230,9 +244,25 @@ static void free_old_xmit_skbs(struct virtnet_info *vi)
}
}
+/* If the virtio transport doesn't always notify us when all in-flight packets
+ * are consumed, we fall back to using this function on a timer to free them. */
+static void xmit_free(unsigned long data)
+{
+ struct virtnet_info *vi = (void *)data;
+
+ netif_tx_lock(vi->dev);
+
+ free_old_xmit_skbs(vi);
+
+ if (!skb_queue_empty(&vi->send))
+ mod_timer(&vi->xmit_free_timer, jiffies + (HZ/10));
+
+ netif_tx_unlock(vi->dev);
+}
+
static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
{
- int num;
+ int num, err;
struct scatterlist sg[2+MAX_SKB_FRAGS];
struct virtio_net_hdr *hdr;
const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
@@ -275,7 +305,25 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
vnet_hdr_to_sg(sg, skb);
num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
- return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
+ err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
+ if (!err && !vi->free_in_tasklet)
+ mod_timer(&vi->xmit_free_timer, jiffies + (HZ/10));
+
+ return err;
+}
+
+static void xmit_tasklet(unsigned long data)
+{
+ struct virtnet_info *vi = (void *)data;
+
+ netif_tx_lock_bh(vi->dev);
+ if (vi->last_xmit_skb && xmit_skb(vi, vi->last_xmit_skb) == 0) {
+ vi->svq->vq_ops->kick(vi->svq);
+ vi->last_xmit_skb = NULL;
+ }
+ if (vi->free_in_tasklet)
+ free_old_xmit_skbs(vi);
+ netif_tx_unlock_bh(vi->dev);
}
static int start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -287,21 +335,25 @@ again:
free_old_xmit_skbs(vi);
/* If we has a buffer left over from last time, send it now. */
- if (vi->last_xmit_skb) {
+ if (unlikely(vi->last_xmit_skb)) {
if (xmit_skb(vi, vi->last_xmit_skb) != 0) {
/* Drop this skb: we only queue one. */
vi->dev->stats.tx_dropped++;
kfree_skb(skb);
+ skb = NULL;
goto stop_queue;
}
vi->last_xmit_skb = NULL;
}
/* Put new one in send queue and do transmit */
- __skb_queue_head(&vi->send, skb);
- if (xmit_skb(vi, skb) != 0) {
- vi->last_xmit_skb = skb;
- goto stop_queue;
+ if (likely(skb)) {
+ __skb_queue_head(&vi->send, skb);
+ if (xmit_skb(vi, skb) != 0) {
+ vi->last_xmit_skb = skb;
+ skb = NULL;
+ goto stop_queue;
+ }
}
done:
vi->svq->vq_ops->kick(vi->svq);
@@ -411,6 +463,10 @@ static int virtnet_probe(struct virtio_device *vdev)
vi->vdev = vdev;
vdev->priv = vi;
+ /* If they give us a callback when all buffers are done, we don't need
+ * the timer. */
+ vi->free_in_tasklet = virtio_has_feature(vdev,VIRTIO_F_NOTIFY_ON_EMPTY);
+
/* We expect two virtqueues, receive then send. */
vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done);
if (IS_ERR(vi->rvq)) {
@@ -428,6 +484,11 @@ static int virtnet_probe(struct virtio_device *vdev)
skb_queue_head_init(&vi->recv);
skb_queue_head_init(&vi->send);
+ tasklet_init(&vi->tasklet, xmit_tasklet, (unsigned long)vi);
+
+ if (!vi->free_in_tasklet)
+ setup_timer(&vi->xmit_free_timer, xmit_free, (unsigned long)vi);
+
err = register_netdev(dev);
if (err) {
pr_debug("virtio_net: registering device failed\n");
@@ -465,13 +526,15 @@ static void virtnet_remove(struct virtio_device *vdev)
/* Stop all the virtqueues. */
vdev->config->reset(vdev);
+ if (!vi->free_in_tasklet)
+ del_timer_sync(&vi->xmit_free_timer);
+
/* Free our skbs in send and recv queues, if any. */
while ((skb = __skb_dequeue(&vi->recv)) != NULL) {
kfree_skb(skb);
vi->num--;
}
- while ((skb = __skb_dequeue(&vi->send)) != NULL)
- kfree_skb(skb);
+ __skb_queue_purge(&vi->send);
BUG_ON(vi->num != 0);
@@ -489,7 +552,7 @@ static struct virtio_device_id id_table[] = {
static unsigned int features[] = {
VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
- VIRTIO_NET_F_HOST_ECN,
+ VIRTIO_NET_F_HOST_ECN, VIRTIO_F_NOTIFY_ON_EMPTY,
};
static struct virtio_driver virtio_net = {
diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
index 9a83c9d5b8cf..7f984895b0d5 100644
--- a/drivers/net/wan/hdlc.c
+++ b/drivers/net/wan/hdlc.c
@@ -43,8 +43,7 @@ static const char* version = "HDLC support module revision 1.22";
#undef DEBUG_LINK
-static struct hdlc_proto *first_proto = NULL;
-
+static struct hdlc_proto *first_proto;
static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
{
@@ -314,21 +313,25 @@ void detach_hdlc_protocol(struct net_device *dev)
void register_hdlc_protocol(struct hdlc_proto *proto)
{
+ rtnl_lock();
proto->next = first_proto;
first_proto = proto;
+ rtnl_unlock();
}
void unregister_hdlc_protocol(struct hdlc_proto *proto)
{
- struct hdlc_proto **p = &first_proto;
- while (*p) {
- if (*p == proto) {
- *p = proto->next;
- return;
- }
+ struct hdlc_proto **p;
+
+ rtnl_lock();
+ p = &first_proto;
+ while (*p != proto) {
+ BUG_ON(!*p);
p = &((*p)->next);
}
+ *p = proto->next;
+ rtnl_unlock();
}
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index 7133c688cf20..762d21c1c703 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -56,6 +56,7 @@ struct cisco_state {
cisco_proto settings;
struct timer_list timer;
+ spinlock_t lock;
unsigned long last_poll;
int up;
int request_sent;
@@ -158,6 +159,7 @@ static int cisco_rx(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
hdlc_device *hdlc = dev_to_hdlc(dev);
+ struct cisco_state *st = state(hdlc);
struct hdlc_header *data = (struct hdlc_header*)skb->data;
struct cisco_packet *cisco_data;
struct in_device *in_dev;
@@ -220,11 +222,12 @@ static int cisco_rx(struct sk_buff *skb)
goto rx_error;
case CISCO_KEEPALIVE_REQ:
- state(hdlc)->rxseq = ntohl(cisco_data->par1);
- if (state(hdlc)->request_sent &&
- ntohl(cisco_data->par2) == state(hdlc)->txseq) {
- state(hdlc)->last_poll = jiffies;
- if (!state(hdlc)->up) {
+ spin_lock(&st->lock);
+ st->rxseq = ntohl(cisco_data->par1);
+ if (st->request_sent &&
+ ntohl(cisco_data->par2) == st->txseq) {
+ st->last_poll = jiffies;
+ if (!st->up) {
u32 sec, min, hrs, days;
sec = ntohl(cisco_data->time) / 1000;
min = sec / 60; sec -= min * 60;
@@ -232,12 +235,12 @@ static int cisco_rx(struct sk_buff *skb)
days = hrs / 24; hrs -= days * 24;
printk(KERN_INFO "%s: Link up (peer "
"uptime %ud%uh%um%us)\n",
- dev->name, days, hrs,
- min, sec);
+ dev->name, days, hrs, min, sec);
netif_dormant_off(dev);
- state(hdlc)->up = 1;
+ st->up = 1;
}
}
+ spin_unlock(&st->lock);
dev_kfree_skb_any(skb);
return NET_RX_SUCCESS;
@@ -261,24 +264,25 @@ static void cisco_timer(unsigned long arg)
{
struct net_device *dev = (struct net_device *)arg;
hdlc_device *hdlc = dev_to_hdlc(dev);
+ struct cisco_state *st = state(hdlc);
- if (state(hdlc)->up &&
- time_after(jiffies, state(hdlc)->last_poll +
- state(hdlc)->settings.timeout * HZ)) {
- state(hdlc)->up = 0;
+ spin_lock(&st->lock);
+ if (st->up &&
+ time_after(jiffies, st->last_poll + st->settings.timeout * HZ)) {
+ st->up = 0;
printk(KERN_INFO "%s: Link down\n", dev->name);
netif_dormant_on(dev);
}
- cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ,
- htonl(++state(hdlc)->txseq),
- htonl(state(hdlc)->rxseq));
- state(hdlc)->request_sent = 1;
- state(hdlc)->timer.expires = jiffies +
- state(hdlc)->settings.interval * HZ;
- state(hdlc)->timer.function = cisco_timer;
- state(hdlc)->timer.data = arg;
- add_timer(&state(hdlc)->timer);
+ cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, htonl(++st->txseq),
+ htonl(st->rxseq));
+ st->request_sent = 1;
+ spin_unlock(&st->lock);
+
+ st->timer.expires = jiffies + st->settings.interval * HZ;
+ st->timer.function = cisco_timer;
+ st->timer.data = arg;
+ add_timer(&st->timer);
}
@@ -286,15 +290,20 @@ static void cisco_timer(unsigned long arg)
static void cisco_start(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- state(hdlc)->up = 0;
- state(hdlc)->request_sent = 0;
- state(hdlc)->txseq = state(hdlc)->rxseq = 0;
-
- init_timer(&state(hdlc)->timer);
- state(hdlc)->timer.expires = jiffies + HZ; /*First poll after 1s*/
- state(hdlc)->timer.function = cisco_timer;
- state(hdlc)->timer.data = (unsigned long)dev;
- add_timer(&state(hdlc)->timer);
+ struct cisco_state *st = state(hdlc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&st->lock, flags);
+ st->up = 0;
+ st->request_sent = 0;
+ st->txseq = st->rxseq = 0;
+ spin_unlock_irqrestore(&st->lock, flags);
+
+ init_timer(&st->timer);
+ st->timer.expires = jiffies + HZ; /* First poll after 1 s */
+ st->timer.function = cisco_timer;
+ st->timer.data = (unsigned long)dev;
+ add_timer(&st->timer);
}
@@ -302,10 +311,16 @@ static void cisco_start(struct net_device *dev)
static void cisco_stop(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- del_timer_sync(&state(hdlc)->timer);
+ struct cisco_state *st = state(hdlc);
+ unsigned long flags;
+
+ del_timer_sync(&st->timer);
+
+ spin_lock_irqsave(&st->lock, flags);
netif_dormant_on(dev);
- state(hdlc)->up = 0;
- state(hdlc)->request_sent = 0;
+ st->up = 0;
+ st->request_sent = 0;
+ spin_unlock_irqrestore(&st->lock, flags);
}
@@ -367,6 +382,7 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
return result;
memcpy(&state(hdlc)->settings, &new_settings, size);
+ spin_lock_init(&state(hdlc)->lock);
dev->hard_start_xmit = hdlc->xmit;
dev->header_ops = &cisco_header_ops;
dev->type = ARPHRD_CISCO;
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index 520bb0b1a9a2..6d35155c7145 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -1008,6 +1008,7 @@ static int fr_rx(struct sk_buff *skb)
stats->rx_bytes += skb->len;
if (pvc->state.becn)
stats->rx_compressed++;
+ skb->dev = dev;
netif_rx(skb);
return NET_RX_SUCCESS;
} else {
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 249e18053d5f..069f8bb0a99f 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -32,6 +32,7 @@
#include <linux/x25.h>
#include <linux/lapb.h>
#include <linux/init.h>
+#include <linux/rtnetlink.h>
#include "x25_asy.h"
#include <net/x25device.h>
@@ -601,8 +602,10 @@ static void x25_asy_close_tty(struct tty_struct *tty)
if (!sl || sl->magic != X25_ASY_MAGIC)
return;
+ rtnl_lock();
if (sl->dev->flags & IFF_UP)
dev_close(sl->dev);
+ rtnl_unlock();
tty->disc_data = NULL;
sl->tty = NULL;
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 45f47c1c0a35..32019fb878d8 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -2668,6 +2668,7 @@ static struct net_device *init_wifidev(struct airo_info *ai,
dev->irq = ethdev->irq;
dev->base_addr = ethdev->base_addr;
dev->wireless_data = ethdev->wireless_data;
+ SET_NETDEV_DEV(dev, ethdev->dev.parent);
memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len);
err = register_netdev(dev);
if (err<0) {
@@ -2904,7 +2905,7 @@ EXPORT_SYMBOL(init_airo_card);
static int waitbusy (struct airo_info *ai) {
int delay = 0;
- while ((IN4500 (ai, COMMAND) & COMMAND_BUSY) & (delay < 10000)) {
+ while ((IN4500(ai, COMMAND) & COMMAND_BUSY) && (delay < 10000)) {
udelay (10);
if ((++delay % 20) == 0)
OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index 4e5c8fc35200..635b9ac9aaa1 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -1787,6 +1787,8 @@ ath5k_tasklet_rx(unsigned long data)
spin_lock(&sc->rxbuflock);
do {
+ rxs.flag = 0;
+
if (unlikely(list_empty(&sc->rxbuf))) {
ATH5K_WARN(sc, "empty rx buf pool\n");
break;
diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c
index 5fb1ae6ad3e2..77990b56860b 100644
--- a/drivers/net/wireless/ath5k/hw.c
+++ b/drivers/net/wireless/ath5k/hw.c
@@ -4119,6 +4119,7 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
rs->rs_status = 0;
+ rs->rs_phyerr = 0;
/*
* Key table status
@@ -4145,7 +4146,7 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
if (rx_status->rx_status_1 &
AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) {
rs->rs_status |= AR5K_RXERR_PHY;
- rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1,
+ rs->rs_phyerr |= AR5K_REG_MS(rx_status->rx_status_1,
AR5K_5210_RX_DESC_STATUS1_PHY_ERROR);
}
@@ -4193,6 +4194,7 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
rs->rs_status = 0;
+ rs->rs_phyerr = 0;
/*
* Key table status
@@ -4215,7 +4217,7 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
if (rx_status->rx_status_1 &
AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
rs->rs_status |= AR5K_RXERR_PHY;
- rs->rs_phyerr = AR5K_REG_MS(rx_err->rx_error_1,
+ rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1,
AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE);
}
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index f51b2d9b085b..1fa043d1802c 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -1,6 +1,6 @@
config B43
tristate "Broadcom 43xx wireless support (mac80211 stack)"
- depends on SSB_POSSIBLE && MAC80211 && WLAN_80211
+ depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA
select SSB
select FW_LOADER
select HW_RANDOM
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 37783cdd301a..d3db298c05fc 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -630,7 +630,6 @@ struct b43_pio {
/* Context information for a noise calculation (Link Quality). */
struct b43_noise_calculation {
- u8 channel_at_start;
bool calculation_running;
u8 nr_samples;
s8 samples[8][4];
@@ -737,6 +736,7 @@ struct b43_wl {
struct ieee80211_tx_control beacon_txctl;
bool beacon0_uploaded;
bool beacon1_uploaded;
+ bool beacon_templates_virgin; /* Never wrote the templates? */
struct work_struct beacon_update_trigger;
/* The current QOS parameters for the 4 queues.
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 6dcbb3c87e72..e23f2f172bd7 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -795,24 +795,49 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
{
struct b43_dmaring *ring;
int err;
- int nr_slots;
dma_addr_t dma_test;
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
if (!ring)
goto out;
- ring->type = type;
- nr_slots = B43_RXRING_SLOTS;
+ ring->nr_slots = B43_RXRING_SLOTS;
if (for_tx)
- nr_slots = B43_TXRING_SLOTS;
+ ring->nr_slots = B43_TXRING_SLOTS;
- ring->meta = kcalloc(nr_slots, sizeof(struct b43_dmadesc_meta),
+ ring->meta = kcalloc(ring->nr_slots, sizeof(struct b43_dmadesc_meta),
GFP_KERNEL);
if (!ring->meta)
goto err_kfree_ring;
+
+ ring->type = type;
+ ring->dev = dev;
+ ring->mmio_base = b43_dmacontroller_base(type, controller_index);
+ ring->index = controller_index;
+ if (type == B43_DMA_64BIT)
+ ring->ops = &dma64_ops;
+ else
+ ring->ops = &dma32_ops;
if (for_tx) {
- ring->txhdr_cache = kcalloc(nr_slots,
+ ring->tx = 1;
+ ring->current_slot = -1;
+ } else {
+ if (ring->index == 0) {
+ ring->rx_buffersize = B43_DMA0_RX_BUFFERSIZE;
+ ring->frameoffset = B43_DMA0_RX_FRAMEOFFSET;
+ } else if (ring->index == 3) {
+ ring->rx_buffersize = B43_DMA3_RX_BUFFERSIZE;
+ ring->frameoffset = B43_DMA3_RX_FRAMEOFFSET;
+ } else
+ B43_WARN_ON(1);
+ }
+ spin_lock_init(&ring->lock);
+#ifdef CONFIG_B43_DEBUG
+ ring->last_injected_overflow = jiffies;
+#endif
+
+ if (for_tx) {
+ ring->txhdr_cache = kcalloc(ring->nr_slots,
b43_txhdr_size(dev),
GFP_KERNEL);
if (!ring->txhdr_cache)
@@ -828,7 +853,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
b43_txhdr_size(dev), 1)) {
/* ugh realloc */
kfree(ring->txhdr_cache);
- ring->txhdr_cache = kcalloc(nr_slots,
+ ring->txhdr_cache = kcalloc(ring->nr_slots,
b43_txhdr_size(dev),
GFP_KERNEL | GFP_DMA);
if (!ring->txhdr_cache)
@@ -853,32 +878,6 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
DMA_TO_DEVICE);
}
- ring->dev = dev;
- ring->nr_slots = nr_slots;
- ring->mmio_base = b43_dmacontroller_base(type, controller_index);
- ring->index = controller_index;
- if (type == B43_DMA_64BIT)
- ring->ops = &dma64_ops;
- else
- ring->ops = &dma32_ops;
- if (for_tx) {
- ring->tx = 1;
- ring->current_slot = -1;
- } else {
- if (ring->index == 0) {
- ring->rx_buffersize = B43_DMA0_RX_BUFFERSIZE;
- ring->frameoffset = B43_DMA0_RX_FRAMEOFFSET;
- } else if (ring->index == 3) {
- ring->rx_buffersize = B43_DMA3_RX_BUFFERSIZE;
- ring->frameoffset = B43_DMA3_RX_FRAMEOFFSET;
- } else
- B43_WARN_ON(1);
- }
- spin_lock_init(&ring->lock);
-#ifdef CONFIG_B43_DEBUG
- ring->last_injected_overflow = jiffies;
-#endif
-
err = alloc_ringmemory(ring);
if (err)
goto err_kfree_txhdr_cache;
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c
index 36a9c42df835..76f4c7bad8b8 100644
--- a/drivers/net/wireless/b43/leds.c
+++ b/drivers/net/wireless/b43/leds.c
@@ -72,6 +72,9 @@ static void b43_led_brightness_set(struct led_classdev *led_dev,
struct b43_wldev *dev = led->dev;
bool radio_enabled;
+ if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED))
+ return;
+
/* Checking the radio-enabled status here is slightly racy,
* but we want to avoid the locking overhead and we don't care
* whether the LED has the wrong state for a second. */
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 8fdba9415c04..a70827793086 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1145,7 +1145,6 @@ static void b43_generate_noise_sample(struct b43_wldev *dev)
b43_jssi_write(dev, 0x7F7F7F7F);
b43_write32(dev, B43_MMIO_MACCMD,
b43_read32(dev, B43_MMIO_MACCMD) | B43_MACCMD_BGNOISE);
- B43_WARN_ON(dev->noisecalc.channel_at_start != dev->phy.channel);
}
static void b43_calculate_link_quality(struct b43_wldev *dev)
@@ -1154,7 +1153,6 @@ static void b43_calculate_link_quality(struct b43_wldev *dev)
if (dev->noisecalc.calculation_running)
return;
- dev->noisecalc.channel_at_start = dev->phy.channel;
dev->noisecalc.calculation_running = 1;
dev->noisecalc.nr_samples = 0;
@@ -1171,9 +1169,16 @@ static void handle_irq_noise(struct b43_wldev *dev)
/* Bottom half of Link Quality calculation. */
+ /* Possible race condition: It might be possible that the user
+ * changed to a different channel in the meantime since we
+ * started the calculation. We ignore that fact, since it's
+ * not really that much of a problem. The background noise is
+ * an estimation only anyway. Slightly wrong results will get damped
+ * by the averaging of the 8 sample rounds. Additionally the
+ * value is shortlived. So it will be replaced by the next noise
+ * calculation round soon. */
+
B43_WARN_ON(!dev->noisecalc.calculation_running);
- if (dev->noisecalc.channel_at_start != phy->channel)
- goto drop_calculation;
*((__le32 *)noise) = cpu_to_le32(b43_jssi_read(dev));
if (noise[0] == 0x7F || noise[1] == 0x7F ||
noise[2] == 0x7F || noise[3] == 0x7F)
@@ -1214,11 +1219,10 @@ static void handle_irq_noise(struct b43_wldev *dev)
average -= 48;
dev->stats.link_noise = average;
- drop_calculation:
dev->noisecalc.calculation_running = 0;
return;
}
- generate_new:
+generate_new:
b43_generate_noise_sample(dev);
}
@@ -1544,6 +1548,30 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev,
kfree(probe_resp_data);
}
+static void b43_upload_beacon0(struct b43_wldev *dev)
+{
+ struct b43_wl *wl = dev->wl;
+
+ if (wl->beacon0_uploaded)
+ return;
+ b43_write_beacon_template(dev, 0x68, 0x18);
+ /* FIXME: Probe resp upload doesn't really belong here,
+ * but we don't use that feature anyway. */
+ b43_write_probe_resp_template(dev, 0x268, 0x4A,
+ &__b43_ratetable[3]);
+ wl->beacon0_uploaded = 1;
+}
+
+static void b43_upload_beacon1(struct b43_wldev *dev)
+{
+ struct b43_wl *wl = dev->wl;
+
+ if (wl->beacon1_uploaded)
+ return;
+ b43_write_beacon_template(dev, 0x468, 0x1A);
+ wl->beacon1_uploaded = 1;
+}
+
static void handle_irq_beacon(struct b43_wldev *dev)
{
struct b43_wl *wl = dev->wl;
@@ -1568,24 +1596,27 @@ static void handle_irq_beacon(struct b43_wldev *dev)
return;
}
- if (!beacon0_valid) {
- if (!wl->beacon0_uploaded) {
- b43_write_beacon_template(dev, 0x68, 0x18);
- b43_write_probe_resp_template(dev, 0x268, 0x4A,
- &__b43_ratetable[3]);
- wl->beacon0_uploaded = 1;
- }
+ if (unlikely(wl->beacon_templates_virgin)) {
+ /* We never uploaded a beacon before.
+ * Upload both templates now, but only mark one valid. */
+ wl->beacon_templates_virgin = 0;
+ b43_upload_beacon0(dev);
+ b43_upload_beacon1(dev);
cmd = b43_read32(dev, B43_MMIO_MACCMD);
cmd |= B43_MACCMD_BEACON0_VALID;
b43_write32(dev, B43_MMIO_MACCMD, cmd);
- } else if (!beacon1_valid) {
- if (!wl->beacon1_uploaded) {
- b43_write_beacon_template(dev, 0x468, 0x1A);
- wl->beacon1_uploaded = 1;
+ } else {
+ if (!beacon0_valid) {
+ b43_upload_beacon0(dev);
+ cmd = b43_read32(dev, B43_MMIO_MACCMD);
+ cmd |= B43_MACCMD_BEACON0_VALID;
+ b43_write32(dev, B43_MMIO_MACCMD, cmd);
+ } else if (!beacon1_valid) {
+ b43_upload_beacon1(dev);
+ cmd = b43_read32(dev, B43_MMIO_MACCMD);
+ cmd |= B43_MACCMD_BEACON1_VALID;
+ b43_write32(dev, B43_MMIO_MACCMD, cmd);
}
- cmd = b43_read32(dev, B43_MMIO_MACCMD);
- cmd |= B43_MACCMD_BEACON1_VALID;
- b43_write32(dev, B43_MMIO_MACCMD, cmd);
}
}
@@ -2852,12 +2883,11 @@ static int b43_op_tx(struct ieee80211_hw *hw,
if (unlikely(skb->len < 2 + 2 + 6)) {
/* Too short, this can't be a valid frame. */
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
+ goto drop_packet;
}
B43_WARN_ON(skb_shinfo(skb)->nr_frags);
if (unlikely(!dev))
- return NETDEV_TX_BUSY;
+ goto drop_packet;
/* Transmissions on seperate queues can run concurrently. */
read_lock_irqsave(&wl->tx_lock, flags);
@@ -2873,7 +2903,12 @@ static int b43_op_tx(struct ieee80211_hw *hw,
read_unlock_irqrestore(&wl->tx_lock, flags);
if (unlikely(err))
- return NETDEV_TX_BUSY;
+ goto drop_packet;
+ return NETDEV_TX_OK;
+
+drop_packet:
+ /* We can not transmit this packet. Drop it. */
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -4073,6 +4108,9 @@ static int b43_op_start(struct ieee80211_hw *hw)
wl->filter_flags = 0;
wl->radiotap_enabled = 0;
b43_qos_clear(wl);
+ wl->beacon0_uploaded = 0;
+ wl->beacon1_uploaded = 0;
+ wl->beacon_templates_virgin = 1;
/* First register RFkill.
* LEDs that are registered later depend on it. */
@@ -4241,7 +4279,9 @@ static void b43_chip_reset(struct work_struct *work)
goto out;
}
}
- out:
+out:
+ if (err)
+ wl->current_dev = NULL; /* Failed to init the dev. */
mutex_unlock(&wl->mutex);
if (err)
b43err(wl, "Controller restart FAILED\n");
@@ -4382,9 +4422,11 @@ static void b43_one_core_detach(struct ssb_device *dev)
struct b43_wldev *wldev;
struct b43_wl *wl;
+ /* Do not cancel ieee80211-workqueue based work here.
+ * See comment in b43_remove(). */
+
wldev = ssb_get_drvdata(dev);
wl = wldev->wl;
- cancel_work_sync(&wldev->restart_work);
b43_debugfs_remove_device(wldev);
b43_wireless_core_detach(wldev);
list_del(&wldev->list);
@@ -4569,6 +4611,10 @@ static void b43_remove(struct ssb_device *dev)
struct b43_wl *wl = ssb_get_devtypedata(dev);
struct b43_wldev *wldev = ssb_get_drvdata(dev);
+ /* We must cancel any work here before unregistering from ieee80211,
+ * as the ieee80211 unreg will destroy the workqueue. */
+ cancel_work_sync(&wldev->restart_work);
+
B43_WARN_ON(!wl);
if (wl->current_dev == wldev)
ieee80211_unregister_hw(wl->hw);
diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig
index 13c65faf0247..aef2298d37ac 100644
--- a/drivers/net/wireless/b43legacy/Kconfig
+++ b/drivers/net/wireless/b43legacy/Kconfig
@@ -1,6 +1,6 @@
config B43LEGACY
tristate "Broadcom 43xx-legacy wireless support (mac80211 stack)"
- depends on SSB_POSSIBLE && MAC80211 && WLAN_80211
+ depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA
select SSB
select FW_LOADER
select HW_RANDOM
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index c990f87b107a..93ddc1cbcc8b 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -876,6 +876,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
if (!ring)
goto out;
ring->type = type;
+ ring->dev = dev;
nr_slots = B43legacy_RXRING_SLOTS;
if (for_tx)
@@ -922,7 +923,6 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
DMA_TO_DEVICE);
}
- ring->dev = dev;
ring->nr_slots = nr_slots;
ring->mmio_base = b43legacy_dmacontroller_base(type, controller_index);
ring->index = controller_index;
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 14a5eea2573e..3e612d0a13e8 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -2378,8 +2378,10 @@ static int b43legacy_op_tx(struct ieee80211_hw *hw,
} else
err = b43legacy_dma_tx(dev, skb, ctl);
out:
- if (unlikely(err))
- return NETDEV_TX_BUSY;
+ if (unlikely(err)) {
+ /* Drop the packet. */
+ dev_kfree_skb_any(skb);
+ }
return NETDEV_TX_OK;
}
@@ -3039,7 +3041,6 @@ static void b43legacy_set_pretbtt(struct b43legacy_wldev *dev)
/* Locking: wl->mutex */
static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev)
{
- struct b43legacy_wl *wl = dev->wl;
struct b43legacy_phy *phy = &dev->phy;
u32 macctl;
@@ -3054,12 +3055,6 @@ static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev)
macctl |= B43legacy_MACCTL_PSM_JMP0;
b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
- mutex_unlock(&wl->mutex);
- /* Must unlock as it would otherwise deadlock. No races here.
- * Cancel possibly pending workqueues. */
- cancel_work_sync(&dev->restart_work);
- mutex_lock(&wl->mutex);
-
b43legacy_leds_exit(dev);
b43legacy_rng_exit(dev->wl);
b43legacy_pio_free(dev);
@@ -3486,6 +3481,8 @@ static void b43legacy_chip_reset(struct work_struct *work)
}
}
out:
+ if (err)
+ wl->current_dev = NULL; /* Failed to init the dev. */
mutex_unlock(&wl->mutex);
if (err)
b43legacyerr(wl, "Controller restart FAILED\n");
@@ -3618,9 +3615,11 @@ static void b43legacy_one_core_detach(struct ssb_device *dev)
struct b43legacy_wldev *wldev;
struct b43legacy_wl *wl;
+ /* Do not cancel ieee80211-workqueue based work here.
+ * See comment in b43legacy_remove(). */
+
wldev = ssb_get_drvdata(dev);
wl = wldev->wl;
- cancel_work_sync(&wldev->restart_work);
b43legacy_debugfs_remove_device(wldev);
b43legacy_wireless_core_detach(wldev);
list_del(&wldev->list);
@@ -3789,6 +3788,10 @@ static void b43legacy_remove(struct ssb_device *dev)
struct b43legacy_wl *wl = ssb_get_devtypedata(dev);
struct b43legacy_wldev *wldev = ssb_get_drvdata(dev);
+ /* We must cancel any work here before unregistering from ieee80211,
+ * as the ieee80211 unreg will destroy the workqueue. */
+ cancel_work_sync(&wldev->restart_work);
+
B43legacy_WARN_ON(!wl);
if (wl->current_dev == wldev)
ieee80211_unregister_hw(wl->hw);
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c
index 4fd73809602e..020f450e9dba 100644
--- a/drivers/net/wireless/hostap/hostap_80211_rx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_rx.c
@@ -64,7 +64,7 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
int hdrlen, phdrlen, head_need, tail_need;
u16 fc;
int prism_header, ret;
- struct ieee80211_hdr_4addr *hdr;
+ struct ieee80211_hdr_4addr *fhdr;
iface = netdev_priv(dev);
local = iface->local;
@@ -83,8 +83,8 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
phdrlen = 0;
}
- hdr = (struct ieee80211_hdr_4addr *) skb->data;
- fc = le16_to_cpu(hdr->frame_ctl);
+ fhdr = (struct ieee80211_hdr_4addr *) skb->data;
+ fc = le16_to_cpu(fhdr->frame_ctl);
if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) {
printk(KERN_DEBUG "%s: dropped management frame with header "
@@ -551,7 +551,7 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
hdr->addr1[2] != 0xff || hdr->addr1[3] != 0xff ||
hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) {
/* RA (or BSSID) is not ours - drop */
- PDEBUG(DEBUG_EXTRA, "%s: received WDS frame with "
+ PDEBUG(DEBUG_EXTRA2, "%s: received WDS frame with "
"not own or broadcast %s=%s\n",
local->dev->name,
fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID",
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 0acd9589c48c..ab981afd481d 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -1930,7 +1930,7 @@ static void handle_pspoll(local_info_t *local,
PDEBUG(DEBUG_PS, " PSPOLL and AID[15:14] not set\n");
return;
}
- aid &= ~BIT(15) & ~BIT(14);
+ aid &= ~(BIT(15) | BIT(14));
if (aid == 0 || aid > MAX_AID_TABLE_SIZE) {
PDEBUG(DEBUG_PS, " invalid aid=%d\n", aid);
return;
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 437a9bcc9bd3..3b4e55cf33cd 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -533,10 +533,10 @@ static void prism2_detach(struct pcmcia_device *link)
do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
#define CFG_CHECK2(fn, retf) \
-do { int ret = (retf); \
-if (ret != 0) { \
- PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", ret); \
- cs_error(link, fn, ret); \
+do { int _ret = (retf); \
+if (_ret != 0) { \
+ PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", _ret); \
+ cs_error(link, fn, _ret); \
goto next_entry; \
} \
} while (0)
@@ -777,8 +777,10 @@ static int hostap_cs_suspend(struct pcmcia_device *link)
int dev_open = 0;
struct hostap_interface *iface = NULL;
- if (dev)
- iface = netdev_priv(dev);
+ if (!dev)
+ return -ENODEV;
+
+ iface = netdev_priv(dev);
PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info);
if (iface && iface->local)
@@ -798,8 +800,10 @@ static int hostap_cs_resume(struct pcmcia_device *link)
int dev_open = 0;
struct hostap_interface *iface = NULL;
- if (dev)
- iface = netdev_priv(dev);
+ if (!dev)
+ return -ENODEV;
+
+ iface = netdev_priv(dev);
PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info);
@@ -833,6 +837,7 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001),
PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300),
/* PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), conflict with pcnet_cs */
+ PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002),
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010),
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index 7be68db6f300..936f52e3d95c 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -2835,7 +2835,7 @@ static void hostap_passive_scan(unsigned long data)
{
local_info_t *local = (local_info_t *) data;
struct net_device *dev = local->dev;
- u16 channel;
+ u16 chan;
if (local->passive_scan_interval <= 0)
return;
@@ -2872,11 +2872,11 @@ static void hostap_passive_scan(unsigned long data)
printk(KERN_DEBUG "%s: passive scan channel %d\n",
dev->name, local->passive_scan_channel);
- channel = local->passive_scan_channel;
+ chan = local->passive_scan_channel;
local->passive_scan_state = PASSIVE_SCAN_WAIT;
local->passive_scan_timer.expires = jiffies + HZ / 10;
} else {
- channel = local->channel;
+ chan = local->channel;
local->passive_scan_state = PASSIVE_SCAN_LISTEN;
local->passive_scan_timer.expires = jiffies +
local->passive_scan_interval * HZ;
@@ -2884,9 +2884,9 @@ static void hostap_passive_scan(unsigned long data)
if (hfa384x_cmd_callback(dev, HFA384X_CMDCODE_TEST |
(HFA384X_TEST_CHANGE_CHANNEL << 8),
- channel, NULL, 0))
+ chan, NULL, 0))
printk(KERN_ERR "%s: passive scan channel set %d "
- "failed\n", dev->name, channel);
+ "failed\n", dev->name, chan);
add_timer(&local->passive_scan_timer);
}
@@ -3276,11 +3276,6 @@ while (0)
}
printk(KERN_INFO "%s: Registered netdevice %s\n", dev_info, dev->name);
-#ifndef PRISM2_NO_PROCFS_DEBUG
- create_proc_read_entry("registers", 0, local->proc,
- prism2_registers_proc_read, local);
-#endif /* PRISM2_NO_PROCFS_DEBUG */
-
hostap_init_data(local);
return dev;
@@ -3307,6 +3302,10 @@ static int hostap_hw_ready(struct net_device *dev)
netif_carrier_off(local->ddev);
}
hostap_init_proc(local);
+#ifndef PRISM2_NO_PROCFS_DEBUG
+ create_proc_read_entry("registers", 0, local->proc,
+ prism2_registers_proc_read, local);
+#endif /* PRISM2_NO_PROCFS_DEBUG */
hostap_init_ap_proc(local);
return 0;
}
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 20d387f6658c..a38e85f334df 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -594,7 +594,8 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx)
}
-int hostap_80211_header_parse(const struct sk_buff *skb, unsigned char *haddr)
+static int hostap_80211_header_parse(const struct sk_buff *skb,
+ unsigned char *haddr)
{
struct hostap_interface *iface = netdev_priv(skb->dev);
local_info_t *local = iface->local;
@@ -682,7 +683,13 @@ static int prism2_close(struct net_device *dev)
netif_device_detach(dev);
}
- flush_scheduled_work();
+ cancel_work_sync(&local->reset_queue);
+ cancel_work_sync(&local->set_multicast_list_queue);
+ cancel_work_sync(&local->set_tim_queue);
+#ifndef PRISM2_NO_STATION_MODES
+ cancel_work_sync(&local->info_queue);
+#endif
+ cancel_work_sync(&local->comms_qual_update);
module_put(local->hw_module);
@@ -851,7 +858,6 @@ const struct header_ops hostap_80211_ops = {
.rebuild = eth_rebuild_header,
.cache = eth_header_cache,
.cache_update = eth_header_cache_update,
-
.parse = hostap_80211_header_parse,
};
EXPORT_SYMBOL(hostap_80211_ops);
@@ -1144,7 +1150,6 @@ EXPORT_SYMBOL(hostap_set_roaming);
EXPORT_SYMBOL(hostap_set_auth_algs);
EXPORT_SYMBOL(hostap_dump_rx_header);
EXPORT_SYMBOL(hostap_dump_tx_header);
-EXPORT_SYMBOL(hostap_80211_header_parse);
EXPORT_SYMBOL(hostap_80211_get_hdrlen);
EXPORT_SYMBOL(hostap_get_stats);
EXPORT_SYMBOL(hostap_setup_dev);
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index fa87c5c2ae0b..6e704608947c 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -1753,6 +1753,8 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
if (priv->workqueue) {
cancel_delayed_work(&priv->request_scan);
+ cancel_delayed_work(&priv->request_direct_scan);
+ cancel_delayed_work(&priv->request_passive_scan);
cancel_delayed_work(&priv->scan_event);
}
queue_work(priv->workqueue, &priv->down);
@@ -2005,6 +2007,8 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
wake_up_interruptible(&priv->wait_command_queue);
priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
cancel_delayed_work(&priv->request_scan);
+ cancel_delayed_work(&priv->request_direct_scan);
+ cancel_delayed_work(&priv->request_passive_scan);
cancel_delayed_work(&priv->scan_event);
schedule_work(&priv->link_down);
queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ);
@@ -4712,6 +4716,12 @@ static void ipw_rx_notification(struct ipw_priv *priv,
priv->status &= ~STATUS_SCAN_FORCED;
#endif /* CONFIG_IPW2200_MONITOR */
+ /* Do queued direct scans first */
+ if (priv->status & STATUS_DIRECT_SCAN_PENDING) {
+ queue_delayed_work(priv->workqueue,
+ &priv->request_direct_scan, 0);
+ }
+
if (!(priv->status & (STATUS_ASSOCIATED |
STATUS_ASSOCIATING |
STATUS_ROAMING |
@@ -6267,7 +6277,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv,
}
}
-static int ipw_request_scan_helper(struct ipw_priv *priv, int type)
+static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct)
{
struct ipw_scan_request_ext scan;
int err = 0, scan_type;
@@ -6278,22 +6288,31 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type)
mutex_lock(&priv->mutex);
+ if (direct && (priv->direct_scan_ssid_len == 0)) {
+ IPW_DEBUG_HC("Direct scan requested but no SSID to scan for\n");
+ priv->status &= ~STATUS_DIRECT_SCAN_PENDING;
+ goto done;
+ }
+
if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG_HC("Concurrent scan requested. Ignoring.\n");
- priv->status |= STATUS_SCAN_PENDING;
+ IPW_DEBUG_HC("Concurrent scan requested. Queuing.\n");
+ priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING :
+ STATUS_SCAN_PENDING;
goto done;
}
if (!(priv->status & STATUS_SCAN_FORCED) &&
priv->status & STATUS_SCAN_ABORTING) {
IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n");
- priv->status |= STATUS_SCAN_PENDING;
+ priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING :
+ STATUS_SCAN_PENDING;
goto done;
}
if (priv->status & STATUS_RF_KILL_MASK) {
- IPW_DEBUG_HC("Aborting scan due to RF Kill activation\n");
- priv->status |= STATUS_SCAN_PENDING;
+ IPW_DEBUG_HC("Queuing scan due to RF Kill activation\n");
+ priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING :
+ STATUS_SCAN_PENDING;
goto done;
}
@@ -6321,6 +6340,7 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type)
cpu_to_le16(20);
scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120);
+ scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20);
#ifdef CONFIG_IPW2200_MONITOR
if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
@@ -6360,13 +6380,23 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type)
cpu_to_le16(2000);
} else {
#endif /* CONFIG_IPW2200_MONITOR */
- /* If we are roaming, then make this a directed scan for the
- * current network. Otherwise, ensure that every other scan
- * is a fast channel hop scan */
- if ((priv->status & STATUS_ROAMING)
- || (!(priv->status & STATUS_ASSOCIATED)
- && (priv->config & CFG_STATIC_ESSID)
- && (le32_to_cpu(scan.full_scan_index) % 2))) {
+ /* Honor direct scans first, otherwise if we are roaming make
+ * this a direct scan for the current network. Finally,
+ * ensure that every other scan is a fast channel hop scan */
+ if (direct) {
+ err = ipw_send_ssid(priv, priv->direct_scan_ssid,
+ priv->direct_scan_ssid_len);
+ if (err) {
+ IPW_DEBUG_HC("Attempt to send SSID command "
+ "failed\n");
+ goto done;
+ }
+
+ scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
+ } else if ((priv->status & STATUS_ROAMING)
+ || (!(priv->status & STATUS_ASSOCIATED)
+ && (priv->config & CFG_STATIC_ESSID)
+ && (le32_to_cpu(scan.full_scan_index) % 2))) {
err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
if (err) {
IPW_DEBUG_HC("Attempt to send SSID command "
@@ -6391,7 +6421,12 @@ send_request:
}
priv->status |= STATUS_SCANNING;
- priv->status &= ~STATUS_SCAN_PENDING;
+ if (direct) {
+ priv->status &= ~STATUS_DIRECT_SCAN_PENDING;
+ priv->direct_scan_ssid_len = 0;
+ } else
+ priv->status &= ~STATUS_SCAN_PENDING;
+
queue_delayed_work(priv->workqueue, &priv->scan_check,
IPW_SCAN_CHECK_WATCHDOG);
done:
@@ -6402,15 +6437,22 @@ done:
static void ipw_request_passive_scan(struct work_struct *work)
{
struct ipw_priv *priv =
- container_of(work, struct ipw_priv, request_passive_scan);
- ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE);
+ container_of(work, struct ipw_priv, request_passive_scan.work);
+ ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE, 0);
}
static void ipw_request_scan(struct work_struct *work)
{
struct ipw_priv *priv =
container_of(work, struct ipw_priv, request_scan.work);
- ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE);
+ ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 0);
+}
+
+static void ipw_request_direct_scan(struct work_struct *work)
+{
+ struct ipw_priv *priv =
+ container_of(work, struct ipw_priv, request_direct_scan.work);
+ ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 1);
}
static void ipw_bg_abort_scan(struct work_struct *work)
@@ -7558,8 +7600,31 @@ static int ipw_associate(void *data)
priv->ieee->iw_mode == IW_MODE_ADHOC &&
priv->config & CFG_ADHOC_CREATE &&
priv->config & CFG_STATIC_ESSID &&
- priv->config & CFG_STATIC_CHANNEL &&
- !list_empty(&priv->ieee->network_free_list)) {
+ priv->config & CFG_STATIC_CHANNEL) {
+ /* Use oldest network if the free list is empty */
+ if (list_empty(&priv->ieee->network_free_list)) {
+ struct ieee80211_network *oldest = NULL;
+ struct ieee80211_network *target;
+ DECLARE_MAC_BUF(mac);
+
+ list_for_each_entry(target, &priv->ieee->network_list, list) {
+ if ((oldest == NULL) ||
+ (target->last_scanned < oldest->last_scanned))
+ oldest = target;
+ }
+
+ /* If there are no more slots, expire the oldest */
+ list_del(&oldest->list);
+ target = oldest;
+ IPW_DEBUG_ASSOC("Expired '%s' (%s) from "
+ "network list.\n",
+ escape_essid(target->ssid,
+ target->ssid_len),
+ print_mac(mac, target->bssid));
+ list_add_tail(&target->list,
+ &priv->ieee->network_free_list);
+ }
+
element = priv->ieee->network_free_list.next;
network = list_entry(element, struct ieee80211_network, list);
ipw_adhoc_create(priv, network);
@@ -9454,99 +9519,38 @@ static int ipw_wx_get_retry(struct net_device *dev,
return 0;
}
-static int ipw_request_direct_scan(struct ipw_priv *priv, char *essid,
- int essid_len)
-{
- struct ipw_scan_request_ext scan;
- int err = 0, scan_type;
-
- if (!(priv->status & STATUS_INIT) ||
- (priv->status & STATUS_EXIT_PENDING))
- return 0;
-
- mutex_lock(&priv->mutex);
-
- if (priv->status & STATUS_RF_KILL_MASK) {
- IPW_DEBUG_HC("Aborting scan due to RF kill activation\n");
- priv->status |= STATUS_SCAN_PENDING;
- goto done;
- }
-
- IPW_DEBUG_HC("starting request direct scan!\n");
-
- if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) {
- /* We should not sleep here; otherwise we will block most
- * of the system (for instance, we hold rtnl_lock when we
- * get here).
- */
- err = -EAGAIN;
- goto done;
- }
- memset(&scan, 0, sizeof(scan));
-
- if (priv->config & CFG_SPEED_SCAN)
- scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
- cpu_to_le16(30);
- else
- scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
- cpu_to_le16(20);
-
- scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] =
- cpu_to_le16(20);
- scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120);
- scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20);
-
- scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee));
-
- err = ipw_send_ssid(priv, essid, essid_len);
- if (err) {
- IPW_DEBUG_HC("Attempt to send SSID command failed\n");
- goto done;
- }
- scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
-
- ipw_add_scan_channels(priv, &scan, scan_type);
-
- err = ipw_send_scan_request_ext(priv, &scan);
- if (err) {
- IPW_DEBUG_HC("Sending scan command failed: %08X\n", err);
- goto done;
- }
-
- priv->status |= STATUS_SCANNING;
-
- done:
- mutex_unlock(&priv->mutex);
- return err;
-}
-
static int ipw_wx_set_scan(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
struct iw_scan_req *req = (struct iw_scan_req *)extra;
+ struct delayed_work *work = NULL;
mutex_lock(&priv->mutex);
+
priv->user_requested_scan = 1;
- mutex_unlock(&priv->mutex);
if (wrqu->data.length == sizeof(struct iw_scan_req)) {
if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
- ipw_request_direct_scan(priv, req->essid,
- req->essid_len);
- return 0;
- }
- if (req->scan_type == IW_SCAN_TYPE_PASSIVE) {
- queue_work(priv->workqueue,
- &priv->request_passive_scan);
- return 0;
+ int len = min((int)req->essid_len,
+ (int)sizeof(priv->direct_scan_ssid));
+ memcpy(priv->direct_scan_ssid, req->essid, len);
+ priv->direct_scan_ssid_len = len;
+ work = &priv->request_direct_scan;
+ } else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) {
+ work = &priv->request_passive_scan;
}
+ } else {
+ /* Normal active broadcast scan */
+ work = &priv->request_scan;
}
+ mutex_unlock(&priv->mutex);
+
IPW_DEBUG_WX("Start scan\n");
- queue_delayed_work(priv->workqueue, &priv->request_scan, 0);
+ queue_delayed_work(priv->workqueue, work, 0);
return 0;
}
@@ -10708,6 +10712,8 @@ static void ipw_link_up(struct ipw_priv *priv)
}
cancel_delayed_work(&priv->request_scan);
+ cancel_delayed_work(&priv->request_direct_scan);
+ cancel_delayed_work(&priv->request_passive_scan);
cancel_delayed_work(&priv->scan_event);
ipw_reset_stats(priv);
/* Ensure the rate is updated immediately */
@@ -10738,6 +10744,8 @@ static void ipw_link_down(struct ipw_priv *priv)
/* Cancel any queued work ... */
cancel_delayed_work(&priv->request_scan);
+ cancel_delayed_work(&priv->request_direct_scan);
+ cancel_delayed_work(&priv->request_passive_scan);
cancel_delayed_work(&priv->adhoc_check);
cancel_delayed_work(&priv->gather_stats);
@@ -10777,8 +10785,9 @@ static int __devinit ipw_setup_deferred_work(struct ipw_priv *priv)
INIT_WORK(&priv->up, ipw_bg_up);
INIT_WORK(&priv->down, ipw_bg_down);
INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan);
+ INIT_DELAYED_WORK(&priv->request_direct_scan, ipw_request_direct_scan);
+ INIT_DELAYED_WORK(&priv->request_passive_scan, ipw_request_passive_scan);
INIT_DELAYED_WORK(&priv->scan_event, ipw_scan_event);
- INIT_WORK(&priv->request_passive_scan, ipw_request_passive_scan);
INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats);
INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan);
INIT_WORK(&priv->roam, ipw_bg_roam);
@@ -11584,6 +11593,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv)
priv->prom_net_dev->hard_start_xmit = ipw_prom_hard_start_xmit;
priv->prom_priv->ieee->iw_mode = IW_MODE_MONITOR;
+ SET_NETDEV_DEV(priv->prom_net_dev, &priv->pci_dev->dev);
rc = register_netdev(priv->prom_net_dev);
if (rc) {
@@ -11811,6 +11821,8 @@ static void __devexit ipw_pci_remove(struct pci_dev *pdev)
cancel_delayed_work(&priv->adhoc_check);
cancel_delayed_work(&priv->gather_stats);
cancel_delayed_work(&priv->request_scan);
+ cancel_delayed_work(&priv->request_direct_scan);
+ cancel_delayed_work(&priv->request_passive_scan);
cancel_delayed_work(&priv->scan_event);
cancel_delayed_work(&priv->rf_kill);
cancel_delayed_work(&priv->scan_check);
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index cd3295b66dd6..d4ab28b73b32 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -1037,6 +1037,7 @@ struct ipw_cmd { /* XXX */
#define STATUS_DISASSOC_PENDING (1<<12)
#define STATUS_STATE_PENDING (1<<13)
+#define STATUS_DIRECT_SCAN_PENDING (1<<19)
#define STATUS_SCAN_PENDING (1<<20)
#define STATUS_SCANNING (1<<21)
#define STATUS_SCAN_ABORTING (1<<22)
@@ -1292,6 +1293,8 @@ struct ipw_priv {
struct iw_public_data wireless_data;
int user_requested_scan;
+ u8 direct_scan_ssid[IW_ESSID_MAX_SIZE];
+ u8 direct_scan_ssid_len;
struct workqueue_struct *workqueue;
@@ -1301,8 +1304,9 @@ struct ipw_priv {
struct work_struct system_config;
struct work_struct rx_replenish;
struct delayed_work request_scan;
+ struct delayed_work request_direct_scan;
+ struct delayed_work request_passive_scan;
struct delayed_work scan_event;
- struct work_struct request_passive_scan;
struct work_struct adapter_restart;
struct delayed_work rf_kill;
struct work_struct up;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
index d200d08fb086..8b1528e52d43 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
@@ -229,14 +229,15 @@ static int iwl3945_led_register_led(struct iwl3945_priv *priv,
led->led_dev.brightness_set = iwl3945_led_brightness_set;
led->led_dev.default_trigger = trigger;
+ led->priv = priv;
+ led->type = type;
+
ret = led_classdev_register(device, &led->led_dev);
if (ret) {
IWL_ERROR("Error: failed to register led handler.\n");
return ret;
}
- led->priv = priv;
- led->type = type;
led->registered = 1;
if (set_led && led->led_on)
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 62a3d8f8563e..55ac850744b3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -449,7 +449,7 @@ static void iwl3945_dbg_report_frame(struct iwl3945_priv *priv,
if (print_summary) {
char *title;
- u32 rate;
+ int rate;
if (hundred)
title = "100Frames";
@@ -487,7 +487,7 @@ static void iwl3945_dbg_report_frame(struct iwl3945_priv *priv,
* but you can hack it to show more, if you'd like to. */
if (dataframe)
IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, "
- "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
+ "len=%u, rssi=%d, chnl=%d, rate=%d, \n",
title, fc, header->addr1[5],
length, rssi, channel, rate);
else {
@@ -588,8 +588,12 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
if (rate == -1)
iwl3945_rt->rt_rate = 0;
- else
+ else {
+ if (stats->band == IEEE80211_BAND_5GHZ)
+ rate += IWL_FIRST_OFDM_RATE;
+
iwl3945_rt->rt_rate = iwl3945_rates[rate].ieee;
+ }
/* antenna number */
antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK;
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
index c9847b1a67f7..3a7f0cb710ec 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
@@ -1162,7 +1162,6 @@ static s32 rs_get_best_rate(struct iwl_priv *priv,
/* Higher rate not available, use the original */
} else {
- new_rate = rate;
break;
}
}
@@ -2009,7 +2008,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
* 2) Not just finishing up a search
* 3) Allowing a new search
*/
- if (!update_lq && !done_search && !lq_sta->stay_in_tbl) {
+ if (!update_lq && !done_search && !lq_sta->stay_in_tbl && window->counter) {
/* Save current throughput to compare with "search" throughput*/
lq_sta->last_tpt = current_tpt;
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index bf19eb8aafd0..de330ae0ca95 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -3528,8 +3528,12 @@ static void iwl4965_add_radiotap(struct iwl_priv *priv,
if (rate == -1)
iwl4965_rt->rt_rate = 0;
- else
+ else {
+ if (stats->band == IEEE80211_BAND_5GHZ)
+ rate += IWL_FIRST_OFDM_RATE;
+
iwl4965_rt->rt_rate = iwl4965_rates[rate].ieee;
+ }
/*
* "antenna number"
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 13925b627e3b..6027e1119c3f 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -2227,7 +2227,10 @@ static int iwl3945_scan_initiate(struct iwl3945_priv *priv)
}
IWL_DEBUG_INFO("Starting scan...\n");
- priv->scan_bands = 2;
+ if (priv->cfg->sku & IWL_SKU_G)
+ priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
+ if (priv->cfg->sku & IWL_SKU_A)
+ priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
set_bit(STATUS_SCANNING, &priv->status);
priv->scan_start = jiffies;
priv->scan_pass_start = priv->scan_start;
@@ -3352,13 +3355,18 @@ static void iwl3945_rx_scan_complete_notif(struct iwl3945_priv *priv,
cancel_delayed_work(&priv->scan_check);
IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
- (priv->scan_bands == 2) ? "2.4" : "5.2",
+ (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ?
+ "2.4" : "5.2",
jiffies_to_msecs(elapsed_jiffies
(priv->scan_pass_start, jiffies)));
- /* Remove this scanned band from the list
- * of pending bands to scan */
- priv->scan_bands--;
+ /* Remove this scanned band from the list of pending
+ * bands to scan, band G precedes A in order of scanning
+ * as seen in iwl3945_bg_request_scan */
+ if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ))
+ priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ);
+ else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ))
+ priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ);
/* If a request to abort was given, or the scan did not succeed
* then we reset the scan state machine and terminate,
@@ -4972,7 +4980,7 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv,
ch_info = iwl3945_get_channel_info(priv, band, scan_ch->channel);
if (!is_channel_valid(ch_info)) {
- IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
+ IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n",
scan_ch->channel);
continue;
}
@@ -6315,21 +6323,16 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
/* flags + rate selection */
- switch (priv->scan_bands) {
- case 2:
+ if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) {
scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
scan->tx_cmd.rate = IWL_RATE_1M_PLCP;
scan->good_CRC_th = 0;
band = IEEE80211_BAND_2GHZ;
- break;
-
- case 1:
+ } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) {
scan->tx_cmd.rate = IWL_RATE_6M_PLCP;
scan->good_CRC_th = IWL_GOOD_CRC_TH;
band = IEEE80211_BAND_5GHZ;
- break;
-
- default:
+ } else {
IWL_WARNING("Invalid scan band count\n");
goto done;
}
@@ -6684,7 +6687,8 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
IWL_DEBUG_MAC80211("leave - monitor\n");
- return -1;
+ dev_kfree_skb_any(skb);
+ return 0;
}
IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
@@ -6770,7 +6774,7 @@ static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
ch_info = iwl3945_get_channel_info(priv, conf->channel->band,
conf->channel->hw_value);
if (!is_channel_valid(ch_info)) {
- IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n",
+ IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this band.\n",
conf->channel->hw_value, conf->channel->band);
IWL_DEBUG_MAC80211("leave - invalid channel\n");
spin_unlock_irqrestore(&priv->lock, flags);
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 883b42f7e998..0bd55bb19739 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -1774,7 +1774,10 @@ static int iwl4965_scan_initiate(struct iwl_priv *priv)
}
IWL_DEBUG_INFO("Starting scan...\n");
- priv->scan_bands = 2;
+ if (priv->cfg->sku & IWL_SKU_G)
+ priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
+ if (priv->cfg->sku & IWL_SKU_A)
+ priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
set_bit(STATUS_SCANNING, &priv->status);
priv->scan_start = jiffies;
priv->scan_pass_start = priv->scan_start;
@@ -3023,8 +3026,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
if (index != -1) {
- int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
#ifdef CONFIG_IWL4965_HT
+ int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
+
if (tid != MAX_TID_COUNT)
priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
if (iwl4965_queue_space(&txq->q) > txq->q.low_mark &&
@@ -3276,13 +3280,18 @@ static void iwl4965_rx_scan_complete_notif(struct iwl_priv *priv,
cancel_delayed_work(&priv->scan_check);
IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
- (priv->scan_bands == 2) ? "2.4" : "5.2",
+ (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ?
+ "2.4" : "5.2",
jiffies_to_msecs(elapsed_jiffies
(priv->scan_pass_start, jiffies)));
- /* Remove this scanned band from the list
- * of pending bands to scan */
- priv->scan_bands--;
+ /* Remove this scanned band from the list of pending
+ * bands to scan, band G precedes A in order of scanning
+ * as seen in iwl_bg_request_scan */
+ if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ))
+ priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ);
+ else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ))
+ priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ);
/* If a request to abort was given, or the scan did not succeed
* then we reset the scan state machine and terminate,
@@ -3292,7 +3301,7 @@ static void iwl4965_rx_scan_complete_notif(struct iwl_priv *priv,
clear_bit(STATUS_SCAN_ABORTING, &priv->status);
} else {
/* If there are more bands on this scan pass reschedule */
- if (priv->scan_bands > 0)
+ if (priv->scan_bands)
goto reschedule;
}
@@ -4635,10 +4644,9 @@ static int iwl4965_get_channels_for_scan(struct iwl_priv *priv,
scan_ch->channel = ieee80211_frequency_to_channel(channels[i].center_freq);
- ch_info = iwl_get_channel_info(priv, band,
- scan_ch->channel);
+ ch_info = iwl_get_channel_info(priv, band, scan_ch->channel);
if (!is_channel_valid(ch_info)) {
- IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
+ IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n",
scan_ch->channel);
continue;
}
@@ -5830,8 +5838,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data)
scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
- switch (priv->scan_bands) {
- case 2:
+ if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) {
scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
scan->tx_cmd.rate_n_flags =
iwl4965_hw_set_rate_n_flags(IWL_RATE_1M_PLCP,
@@ -5839,17 +5846,13 @@ static void iwl4965_bg_request_scan(struct work_struct *data)
scan->good_CRC_th = 0;
band = IEEE80211_BAND_2GHZ;
- break;
-
- case 1:
+ } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) {
scan->tx_cmd.rate_n_flags =
iwl4965_hw_set_rate_n_flags(IWL_RATE_6M_PLCP,
RATE_MCS_ANT_B_MSK);
scan->good_CRC_th = IWL_GOOD_CRC_TH;
band = IEEE80211_BAND_5GHZ;
- break;
-
- default:
+ } else {
IWL_WARNING("Invalid scan band count\n");
goto done;
}
@@ -6234,7 +6237,8 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
IWL_DEBUG_MAC80211("leave - monitor\n");
- return -1;
+ dev_kfree_skb_any(skb);
+ return 0;
}
IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 6328b9593877..8124fd9b1353 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -1842,6 +1842,9 @@ static void lbs_send_confirmsleep(struct lbs_private *priv)
spin_lock_irqsave(&priv->driver_lock, flags);
+ /* We don't get a response on the sleep-confirmation */
+ priv->dnld_sent = DNLD_RES_RECEIVED;
+
/* If nothing to do, go back to sleep (?) */
if (!__kfifo_len(priv->event_fifo) && !priv->resp_len[priv->resp_idx])
priv->psstate = PS_STATE_SLEEP;
@@ -1904,12 +1907,12 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv)
lbs_deb_enter(LBS_DEB_HOST);
+ spin_lock_irqsave(&priv->driver_lock, flags);
if (priv->dnld_sent) {
allowed = 0;
lbs_deb_host("dnld_sent was set\n");
}
- spin_lock_irqsave(&priv->driver_lock, flags);
/* In-progress command? */
if (priv->cur_cmd) {
allowed = 0;
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index ad2fabca9116..0aa0ce3b2c42 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -312,8 +312,8 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
if (tlv_type != TLV_TYPE_BCNMISS)
tlv->freq = freq;
- /* The command header, the event mask, and the one TLV */
- events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 2 + sizeof(*tlv));
+ /* The command header, the action, the event mask, and one TLV */
+ events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 4 + sizeof(*tlv));
ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index dcfdb404678b..688d60de55cb 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -73,8 +73,8 @@ out:
return ret;
}
-static void lbs_ethtool_get_stats(struct net_device * dev,
- struct ethtool_stats * stats, u64 * data)
+static void lbs_ethtool_get_stats(struct net_device *dev,
+ struct ethtool_stats *stats, uint64_t *data)
{
struct lbs_private *priv = dev->priv;
struct cmd_ds_mesh_access mesh_access;
@@ -83,12 +83,12 @@ static void lbs_ethtool_get_stats(struct net_device * dev,
lbs_deb_enter(LBS_DEB_ETHTOOL);
/* Get Mesh Statistics */
- ret = lbs_prepare_and_send_command(priv,
- CMD_MESH_ACCESS, CMD_ACT_MESH_GET_STATS,
- CMD_OPTION_WAITFORRSP, 0, &mesh_access);
+ ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
- if (ret)
+ if (ret) {
+ memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
return;
+ }
priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
@@ -111,19 +111,18 @@ static void lbs_ethtool_get_stats(struct net_device * dev,
lbs_deb_enter(LBS_DEB_ETHTOOL);
}
-static int lbs_ethtool_get_sset_count(struct net_device * dev, int sset)
+static int lbs_ethtool_get_sset_count(struct net_device *dev, int sset)
{
- switch (sset) {
- case ETH_SS_STATS:
+ struct lbs_private *priv = dev->priv;
+
+ if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
return MESH_STATS_NUM;
- default:
- return -EOPNOTSUPP;
- }
+
+ return -EOPNOTSUPP;
}
static void lbs_ethtool_get_strings(struct net_device *dev,
- u32 stringset,
- u8 * s)
+ uint32_t stringset, uint8_t *s)
{
int i;
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 8032df72aaab..36288b29abf7 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -925,6 +925,7 @@ static struct usb_driver if_usb_driver = {
.id_table = if_usb_table,
.suspend = if_usb_suspend,
.resume = if_usb_resume,
+ .reset_resume = if_usb_resume,
};
static int __init if_usb_init_module(void)
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 406f54d40956..acfc4bfcc262 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -732,8 +732,8 @@ static int lbs_thread(void *data)
lbs_deb_thread("4: currenttxskb %p, dnld_sent %d\n",
priv->currenttxskb, priv->dnld_sent);
- spin_lock_irq(&priv->driver_lock);
/* Process any pending command response */
+ spin_lock_irq(&priv->driver_lock);
resp_idx = priv->resp_idx;
if (priv->resp_len[resp_idx]) {
spin_unlock_irq(&priv->driver_lock);
@@ -756,6 +756,7 @@ static int lbs_thread(void *data)
priv->nr_retries = 0;
} else {
priv->cur_cmd = NULL;
+ priv->dnld_sent = DNLD_RES_RECEIVED;
lbs_pr_info("requeueing command %x due to timeout (#%d)\n",
le16_to_cpu(cmdnode->cmdbuf->command), priv->nr_retries);
@@ -1564,6 +1565,7 @@ static int lbs_add_rtap(struct lbs_private *priv)
rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit;
rtap_dev->set_multicast_list = lbs_set_multicast_list;
rtap_dev->priv = priv;
+ SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent);
ret = register_netdev(rtap_dev);
if (ret) {
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index d448c9702a0f..387d4878af2f 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -567,11 +567,11 @@ static int lbs_process_bss(struct bss_descriptor *bss,
pos += 8;
/* beacon interval is 2 bytes long */
- bss->beaconperiod = le16_to_cpup((void *) pos);
+ bss->beaconperiod = get_unaligned_le16(pos);
pos += 2;
/* capability information is 2 bytes long */
- bss->capability = le16_to_cpup((void *) pos);
+ bss->capability = get_unaligned_le16(pos);
lbs_deb_scan("process_bss: capabilities 0x%04x\n", bss->capability);
pos += 2;
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index 8b7f5768a103..1c216e015f64 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -461,6 +461,7 @@ static struct pcmcia_device_id orinoco_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */
PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */
PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), /* SpeedStream SS1021 Wireless Adapter */
+ PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x3021), /* SpeedStream Wireless Adapter */
PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), /* PLANEX RoadLannerWave GW-NS11H */
PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */
PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), /* Adaptec Ultra Wireless ANW-8030 */
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 98ddbb3b3273..1610a7308c1d 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -49,6 +49,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
{USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */
/* Version 2 devices (3887) */
+ {USB_DEVICE(0x0471, 0x1230)}, /* Philips CPWUA054/00 */
{USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
{USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
{USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c
index 762e85bef55d..e43bae97ed8f 100644
--- a/drivers/net/wireless/prism54/islpci_eth.c
+++ b/drivers/net/wireless/prism54/islpci_eth.c
@@ -290,7 +290,7 @@ islpci_monitor_rx(islpci_private *priv, struct sk_buff **skb)
avs->version = cpu_to_be32(P80211CAPTURE_VERSION);
avs->length = cpu_to_be32(sizeof (struct avs_80211_1_header));
- avs->mactime = cpu_to_be64(le64_to_cpu(clock));
+ avs->mactime = cpu_to_be64(clock);
avs->hosttime = cpu_to_be64(jiffies);
avs->phytype = cpu_to_be32(6); /*OFDM: 6 for (g), 8 for (a) */
avs->channel = cpu_to_be32(channel_of_freq(freq));
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index d0b1fb15c709..18c9931e3267 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -116,6 +116,7 @@ MODULE_PARM_DESC(workaround_interval,
#define OID_802_11_ENCRYPTION_STATUS ccpu2(0x0d01011b)
#define OID_802_11_ADD_KEY ccpu2(0x0d01011d)
#define OID_802_11_REMOVE_KEY ccpu2(0x0d01011e)
+#define OID_802_11_ASSOCIATION_INFORMATION ccpu2(0x0d01011f)
#define OID_802_11_PMKID ccpu2(0x0d010123)
#define OID_802_11_NETWORK_TYPES_SUPPORTED ccpu2(0x0d010203)
#define OID_802_11_NETWORK_TYPE_IN_USE ccpu2(0x0d010204)
@@ -271,6 +272,26 @@ struct ndis_config_param {
__le32 value_length;
} __attribute__((packed));
+struct ndis_80211_assoc_info {
+ __le32 length;
+ __le16 req_ies;
+ struct req_ie {
+ __le16 capa;
+ __le16 listen_interval;
+ u8 cur_ap_address[6];
+ } req_ie;
+ __le32 req_ie_length;
+ __le32 offset_req_ies;
+ __le16 resp_ies;
+ struct resp_ie {
+ __le16 capa;
+ __le16 status_code;
+ __le16 assoc_id;
+ } resp_ie;
+ __le32 resp_ie_length;
+ __le32 offset_resp_ies;
+} __attribute__((packed));
+
/* these have to match what is in wpa_supplicant */
enum wpa_alg { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP };
enum wpa_cipher { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
@@ -674,6 +695,12 @@ static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN])
return ret;
}
+static int get_association_info(struct usbnet *usbdev,
+ struct ndis_80211_assoc_info *info, int len)
+{
+ return rndis_query_oid(usbdev, OID_802_11_ASSOCIATION_INFORMATION,
+ info, &len);
+}
static int is_associated(struct usbnet *usbdev)
{
@@ -2182,11 +2209,40 @@ static void rndis_wext_worker(struct work_struct *work)
struct usbnet *usbdev = priv->usbdev;
union iwreq_data evt;
unsigned char bssid[ETH_ALEN];
- int ret;
+ struct ndis_80211_assoc_info *info;
+ int assoc_size = sizeof(*info) + IW_CUSTOM_MAX + 32;
+ int ret, offset;
if (test_and_clear_bit(WORK_CONNECTION_EVENT, &priv->work_pending)) {
- ret = get_bssid(usbdev, bssid);
+ info = kzalloc(assoc_size, GFP_KERNEL);
+ if (!info)
+ goto get_bssid;
+
+ /* Get association info IEs from device and send them back to
+ * userspace. */
+ ret = get_association_info(usbdev, info, assoc_size);
+ if (!ret) {
+ evt.data.length = le32_to_cpu(info->req_ie_length);
+ if (evt.data.length > 0) {
+ offset = le32_to_cpu(info->offset_req_ies);
+ wireless_send_event(usbdev->net,
+ IWEVASSOCREQIE, &evt,
+ (char *)info + offset);
+ }
+
+ evt.data.length = le32_to_cpu(info->resp_ie_length);
+ if (evt.data.length > 0) {
+ offset = le32_to_cpu(info->offset_resp_ies);
+ wireless_send_event(usbdev->net,
+ IWEVASSOCRESPIE, &evt,
+ (char *)info + offset);
+ }
+ }
+
+ kfree(info);
+get_bssid:
+ ret = get_bssid(usbdev, bssid);
if (!ret) {
evt.data.flags = 0;
evt.data.length = 0;
@@ -2414,6 +2470,11 @@ static int bcm4320_early_init(struct usbnet *dev)
else if (priv->param_power_save > 2)
priv->param_power_save = 2;
+ if (priv->param_power_output < 0)
+ priv->param_power_output = 0;
+ else if (priv->param_power_output > 3)
+ priv->param_power_output = 3;
+
if (priv->param_roamtrigger < -80)
priv->param_roamtrigger = -80;
else if (priv->param_roamtrigger > -60)
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index ab1029e79884..2d611876bbe0 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -32,12 +32,13 @@ config RT2X00_LIB_FIRMWARE
config RT2X00_LIB_RFKILL
boolean
depends on RT2X00_LIB
+ depends on INPUT
select RFKILL
select INPUT_POLLDEV
config RT2X00_LIB_LEDS
boolean
- depends on RT2X00_LIB
+ depends on RT2X00_LIB && NEW_LEDS
config RT2400PCI
tristate "Ralink rt2400 pci/pcmcia support"
@@ -51,7 +52,7 @@ config RT2400PCI
config RT2400PCI_RFKILL
bool "RT2400 rfkill support"
- depends on RT2400PCI
+ depends on RT2400PCI && INPUT
select RT2X00_LIB_RFKILL
---help---
This adds support for integrated rt2400 devices that feature a
@@ -60,7 +61,7 @@ config RT2400PCI_RFKILL
config RT2400PCI_LEDS
bool "RT2400 leds support"
- depends on RT2400PCI
+ depends on RT2400PCI && NEW_LEDS
select LEDS_CLASS
select RT2X00_LIB_LEDS
---help---
@@ -78,7 +79,7 @@ config RT2500PCI
config RT2500PCI_RFKILL
bool "RT2500 rfkill support"
- depends on RT2500PCI
+ depends on RT2500PCI && INPUT
select RT2X00_LIB_RFKILL
---help---
This adds support for integrated rt2500 devices that feature a
@@ -87,7 +88,7 @@ config RT2500PCI_RFKILL
config RT2500PCI_LEDS
bool "RT2500 leds support"
- depends on RT2500PCI
+ depends on RT2500PCI && NEW_LEDS
select LEDS_CLASS
select RT2X00_LIB_LEDS
---help---
@@ -107,7 +108,7 @@ config RT61PCI
config RT61PCI_RFKILL
bool "RT61 rfkill support"
- depends on RT61PCI
+ depends on RT61PCI && INPUT
select RT2X00_LIB_RFKILL
---help---
This adds support for integrated rt61 devices that feature a
@@ -116,7 +117,7 @@ config RT61PCI_RFKILL
config RT61PCI_LEDS
bool "RT61 leds support"
- depends on RT61PCI
+ depends on RT61PCI && NEW_LEDS
select LEDS_CLASS
select RT2X00_LIB_LEDS
---help---
@@ -133,7 +134,7 @@ config RT2500USB
config RT2500USB_LEDS
bool "RT2500 leds support"
- depends on RT2500USB
+ depends on RT2500USB && NEW_LEDS
select LEDS_CLASS
select RT2X00_LIB_LEDS
---help---
@@ -152,7 +153,7 @@ config RT73USB
config RT73USB_LEDS
bool "RT73 leds support"
- depends on RT73USB
+ depends on RT73USB && NEW_LEDS
select LEDS_CLASS
select RT2X00_LIB_LEDS
---help---
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 560b9c73c0b9..b36ed1c6c746 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -731,6 +731,17 @@ static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev)
(rt2x00dev->rx->data_size / 128));
rt2x00pci_register_write(rt2x00dev, CSR9, reg);
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(&reg, CSR14_TSF_SYNC, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+ rt2x00_set_field32(&reg, CSR14_TCFP, 0);
+ rt2x00_set_field32(&reg, CSR14_TATIMW, 0);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, CSR14_CFP_COUNT_PRELOAD, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCM_PRELOAD, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
rt2x00pci_register_write(rt2x00dev, CNT3, 0x3f080000);
rt2x00pci_register_read(rt2x00dev, ARCSR0, &reg);
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index a5ed54b69262..f7731fb82555 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -824,6 +824,17 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, CSR11_CW_SELECT, 0);
rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(&reg, CSR14_TSF_SYNC, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+ rt2x00_set_field32(&reg, CSR14_TCFP, 0);
+ rt2x00_set_field32(&reg, CSR14_TATIMW, 0);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, CSR14_CFP_COUNT_PRELOAD, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCM_PRELOAD, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
rt2x00pci_register_write(rt2x00dev, CNT3, 0);
rt2x00pci_register_read(rt2x00dev, TXCSR8, &reg);
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index fdbd0ef2be4b..d90512f97b39 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -138,11 +138,8 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
* Wait until the BBP becomes ready.
*/
reg = rt2500usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
- ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
- return;
- }
+ if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+ goto exit_fail;
/*
* Write the data into the BBP.
@@ -155,6 +152,13 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+ return;
+
+exit_fail:
+ mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+ ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
}
static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -168,10 +172,8 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
* Wait until the BBP becomes ready.
*/
reg = rt2500usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
- ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
- return;
- }
+ if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+ goto exit_fail;
/*
* Write the request into the BBP.
@@ -186,17 +188,21 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
* Wait until the BBP becomes ready.
*/
reg = rt2500usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
- ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
- *value = 0xff;
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
- return;
- }
+ if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+ goto exit_fail;
rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
*value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+ return;
+
+exit_fail:
+ mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+ ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
+ *value = 0xff;
}
static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
@@ -795,6 +801,13 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&reg, TXRX_CSR8_BBP_ID1_VALID, 0);
rt2500usb_register_write(rt2x00dev, TXRX_CSR8, reg);
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TSF_SYNC, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+
rt2500usb_register_write(rt2x00dev, TXRX_CSR21, 0xe78f);
rt2500usb_register_write(rt2x00dev, MAC_CSR9, 0xff1d);
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 57bdc153952f..b4bf1e09cf9a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -328,6 +328,11 @@ static inline int rt2x00_get_link_ant_rssi(struct link *link)
return DEFAULT_RSSI;
}
+static inline void rt2x00_reset_link_ant_rssi(struct link *link)
+{
+ link->ant.rssi_ant = 0;
+}
+
static inline int rt2x00_get_link_ant_rssi_history(struct link *link,
enum antenna ant)
{
@@ -816,6 +821,7 @@ struct rt2x00_dev {
/*
* Scheduled work.
*/
+ struct workqueue_struct *workqueue;
struct work_struct intf_work;
struct work_struct filter_work;
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index a9930a03f450..48608e8cc8b4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -129,6 +129,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
*/
rt2x00dev->ops->lib->config(rt2x00dev, &libconf, CONFIG_UPDATE_ANTENNA);
rt2x00lib_reset_link_tuner(rt2x00dev);
+ rt2x00_reset_link_ant_rssi(&rt2x00dev->link);
rt2x00dev->link.ant.active.rx = libconf.ant.rx;
rt2x00dev->link.ant.active.tx = libconf.ant.tx;
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index b22c02737185..c997d4f28ab3 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -75,7 +75,7 @@ static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev)
rt2x00lib_reset_link_tuner(rt2x00dev);
- queue_delayed_work(rt2x00dev->hw->workqueue,
+ queue_delayed_work(rt2x00dev->workqueue,
&rt2x00dev->link.work, LINK_TUNE_INTERVAL);
}
@@ -137,14 +137,6 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
return;
/*
- * Stop all scheduled work.
- */
- if (work_pending(&rt2x00dev->intf_work))
- cancel_work_sync(&rt2x00dev->intf_work);
- if (work_pending(&rt2x00dev->filter_work))
- cancel_work_sync(&rt2x00dev->filter_work);
-
- /*
* Stop the TX queues.
*/
ieee80211_stop_queues(rt2x00dev->hw);
@@ -398,8 +390,8 @@ static void rt2x00lib_link_tuner(struct work_struct *work)
* Increase tuner counter, and reschedule the next link tuner run.
*/
rt2x00dev->link.count++;
- queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work,
- LINK_TUNE_INTERVAL);
+ queue_delayed_work(rt2x00dev->workqueue,
+ &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
}
static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
@@ -433,6 +425,15 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
spin_unlock(&intf->lock);
+ /*
+ * It is possible the radio was disabled while the work had been
+ * scheduled. If that happens we should return here immediately,
+ * note that in the spinlock protected area above the delayed_flags
+ * have been cleared correctly.
+ */
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
if (delayed_flags & DELAYED_UPDATE_BEACON) {
skb = ieee80211_beacon_get(rt2x00dev->hw, vif, &control);
if (skb && rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw,
@@ -441,7 +442,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
}
if (delayed_flags & DELAYED_CONFIG_ERP)
- rt2x00lib_config_erp(rt2x00dev, intf, &intf->conf);
+ rt2x00lib_config_erp(rt2x00dev, intf, &conf);
if (delayed_flags & DELAYED_LED_ASSOC)
rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated);
@@ -483,11 +484,11 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
return;
- ieee80211_iterate_active_interfaces(rt2x00dev->hw,
- rt2x00lib_beacondone_iter,
- rt2x00dev);
+ ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
+ rt2x00lib_beacondone_iter,
+ rt2x00dev);
- queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work);
+ queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work);
}
EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
@@ -507,7 +508,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
* Update TX statistics.
*/
rt2x00dev->link.qual.tx_success += success;
- rt2x00dev->link.qual.tx_failed += txdesc->retry + fail;
+ rt2x00dev->link.qual.tx_failed += fail;
/*
* Initialize TX status
@@ -1130,6 +1131,10 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
/*
* Initialize configuration work.
*/
+ rt2x00dev->workqueue = create_singlethread_workqueue("rt2x00lib");
+ if (!rt2x00dev->workqueue)
+ goto exit;
+
INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled);
INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner);
@@ -1190,6 +1195,13 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
rt2x00leds_unregister(rt2x00dev);
/*
+ * Stop all queued work. Note that most tasks will already be halted
+ * during rt2x00lib_disable_radio() and rt2x00lib_uninitialize().
+ */
+ flush_workqueue(rt2x00dev->workqueue);
+ destroy_workqueue(rt2x00dev->workqueue);
+
+ /*
* Free ieee80211_hw memory.
*/
rt2x00lib_remove_hw(rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index c206b5092070..9cb023edd2e9 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -93,6 +93,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
*/
if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) {
ieee80211_stop_queues(hw);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -427,7 +428,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
else
- queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
+ queue_work(rt2x00dev->workqueue, &rt2x00dev->filter_work);
}
EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
@@ -508,7 +509,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
memcpy(&intf->conf, bss_conf, sizeof(*bss_conf));
if (delayed) {
intf->delayed_flags |= delayed;
- queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work);
+ queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work);
}
spin_unlock(&intf->lock);
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 971af2546b59..60893de3bf8f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -412,8 +412,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
if (pci_set_mwi(pci_dev))
ERROR_PROBE("MWI not available.\n");
- if (pci_set_dma_mask(pci_dev, DMA_64BIT_MASK) &&
- pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) {
+ if (pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) {
ERROR_PROBE("PCI DMA not supported.\n");
retval = -EIO;
goto exit_disable_device;
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 5a331674dcb2..e5ceae805b57 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -362,6 +362,12 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
}
}
+ /*
+ * Kill guardian urb (if required by driver).
+ */
+ if (!test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))
+ return;
+
for (i = 0; i < rt2x00dev->bcn->limit; i++) {
priv_bcn = rt2x00dev->bcn->entries[i].priv_data;
usb_kill_urb(priv_bcn->urb);
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 14bc7b281659..c3afb5cbe807 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1201,6 +1201,15 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR8, reg);
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TIMESTAMP_COMPENSATE, 0);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+
rt2x00pci_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
rt2x00pci_register_write(rt2x00dev, MAC_CSR6, 0x00000fff);
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index da19a3a91f4d..46e9e081fbf1 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -134,11 +134,8 @@ static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev,
* Wait until the BBP becomes ready.
*/
reg = rt73usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
- ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
- return;
- }
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+ goto exit_fail;
/*
* Write the data into the BBP.
@@ -151,6 +148,13 @@ static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev,
rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+ return;
+
+exit_fail:
+ mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+ ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
}
static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -164,11 +168,8 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
* Wait until the BBP becomes ready.
*/
reg = rt73usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
- ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
- mutex_unlock(&rt2x00dev->usb_cache_mutex);
- return;
- }
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+ goto exit_fail;
/*
* Write the request into the BBP.
@@ -184,14 +185,19 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
* Wait until the BBP becomes ready.
*/
reg = rt73usb_bbp_check(rt2x00dev);
- if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
- ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
- *value = 0xff;
- return;
- }
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+ goto exit_fail;
*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+ return;
+
+exit_fail:
+ mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+ ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+ *value = 0xff;
}
static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev,
@@ -1000,6 +1006,15 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
rt73usb_register_write(rt2x00dev, TXRX_CSR8, reg);
+ rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TIMESTAMP_COMPENSATE, 0);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+
rt73usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
rt73usb_register_read(rt2x00dev, MAC_CSR6, &reg);
@@ -2131,6 +2146,7 @@ static struct usb_device_id rt73usb_device_table[] = {
/* D-Link */
{ USB_DEVICE(0x07d1, 0x3c03), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c04), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x07d1, 0x3c06), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x07d1, 0x3c07), USB_DEVICE_DATA(&rt73usb_ops) },
/* Gemtek */
{ USB_DEVICE(0x15a9, 0x0004), USB_DEVICE_DATA(&rt73usb_ops) },
diff --git a/drivers/net/wireless/rtl8180_grf5101.c b/drivers/net/wireless/rtl8180_grf5101.c
index 5d47935dbac3..947ee55f18b2 100644
--- a/drivers/net/wireless/rtl8180_grf5101.c
+++ b/drivers/net/wireless/rtl8180_grf5101.c
@@ -88,7 +88,7 @@ static void grf5101_rf_set_channel(struct ieee80211_hw *dev,
write_grf5101(dev, 0x0B, chan);
write_grf5101(dev, 0x07, 0x1000);
- grf5101_write_phy_antenna(dev, chan);
+ grf5101_write_phy_antenna(dev, channel);
}
static void grf5101_rf_stop(struct ieee80211_hw *dev)
diff --git a/drivers/net/wireless/rtl8180_max2820.c b/drivers/net/wireless/rtl8180_max2820.c
index a34dfd382b6d..6c825fd7f3b6 100644
--- a/drivers/net/wireless/rtl8180_max2820.c
+++ b/drivers/net/wireless/rtl8180_max2820.c
@@ -78,7 +78,8 @@ static void max2820_rf_set_channel(struct ieee80211_hw *dev,
struct ieee80211_conf *conf)
{
struct rtl8180_priv *priv = dev->priv;
- int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
+ int channel = conf ?
+ ieee80211_frequency_to_channel(conf->channel->center_freq) : 1;
unsigned int chan_idx = channel - 1;
u32 txpw = priv->channels[chan_idx].hw_value & 0xFF;
u32 chan = max2820_chan[chan_idx];
@@ -87,7 +88,7 @@ static void max2820_rf_set_channel(struct ieee80211_hw *dev,
* sa2400, for MAXIM we do this directly from BB */
rtl8180_write_phy(dev, 3, txpw);
- max2820_write_phy_antenna(dev, chan);
+ max2820_write_phy_antenna(dev, channel);
write_max2820(dev, 3, chan);
}
diff --git a/drivers/net/wireless/rtl8180_sa2400.c b/drivers/net/wireless/rtl8180_sa2400.c
index 0311b4ea124c..cea4e0ccb92d 100644
--- a/drivers/net/wireless/rtl8180_sa2400.c
+++ b/drivers/net/wireless/rtl8180_sa2400.c
@@ -86,7 +86,7 @@ static void sa2400_rf_set_channel(struct ieee80211_hw *dev,
write_sa2400(dev, 7, txpw);
- sa2400_write_phy_antenna(dev, chan);
+ sa2400_write_phy_antenna(dev, channel);
write_sa2400(dev, 0, chan);
write_sa2400(dev, 1, 0xbb50);
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c
index d5787b37e1fb..9223ada5f00e 100644
--- a/drivers/net/wireless/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl8187_dev.c
@@ -92,6 +92,7 @@ static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr,
u8 data[4];
struct usb_ctrlrequest dr;
} *buf;
+ int rc;
buf = kmalloc(sizeof(*buf), GFP_ATOMIC);
if (!buf)
@@ -116,7 +117,11 @@ static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr,
usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0),
(unsigned char *)dr, buf, len,
rtl8187_iowrite_async_cb, buf);
- usb_submit_urb(urb, GFP_ATOMIC);
+ rc = usb_submit_urb(urb, GFP_ATOMIC);
+ if (rc < 0) {
+ kfree(buf);
+ usb_free_urb(urb);
+ }
}
static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv,
@@ -169,6 +174,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
struct urb *urb;
__le16 rts_dur = 0;
u32 flags;
+ int rc;
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
@@ -208,7 +214,11 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
info->dev = dev;
usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, 2),
hdr, skb->len, rtl8187_tx_cb, skb);
- usb_submit_urb(urb, GFP_ATOMIC);
+ rc = usb_submit_urb(urb, GFP_ATOMIC);
+ if (rc < 0) {
+ usb_free_urb(urb);
+ kfree_skb(skb);
+ }
return 0;
}
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 69c45ca99051..694e95d35fd4 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -719,7 +719,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
fc = le16_to_cpu(*((__le16 *) buffer));
is_qos = ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
- ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_QOS_DATA);
+ (fc & IEEE80211_STYPE_QOS_DATA);
is_4addr = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS);
need_padding = is_qos ^ is_4addr;
@@ -765,6 +765,7 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw,
{
struct zd_mac *mac = zd_hw_mac(hw);
mac->type = IEEE80211_IF_TYPE_INVALID;
+ zd_set_beacon_interval(&mac->chip, 0);
zd_write_mac_addr(&mac->chip, NULL);
}
@@ -805,7 +806,7 @@ void zd_process_intr(struct work_struct *work)
u16 int_status;
struct zd_mac *mac = container_of(work, struct zd_mac, process_intr);
- int_status = le16_to_cpu(*(u16 *)(mac->intr_buffer+4));
+ int_status = le16_to_cpu(*(__le16 *)(mac->intr_buffer+4));
if (int_status & INT_CFG_NEXT_BCN) {
if (net_ratelimit())
dev_dbg_f(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n");
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 12e24f04dddf..6cdad9764604 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -64,6 +64,7 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
@@ -342,7 +343,7 @@ static inline void handle_regs_int(struct urb *urb)
ZD_ASSERT(in_interrupt());
spin_lock(&intr->lock);
- int_num = le16_to_cpu(*(u16 *)(urb->transfer_buffer+2));
+ int_num = le16_to_cpu(*(__le16 *)(urb->transfer_buffer+2));
if (int_num == CR_INTERRUPT) {
struct zd_mac *mac = zd_hw_mac(zd_usb_to_hw(urb->context));
memcpy(&mac->intr_buffer, urb->transfer_buffer,
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 8bddff150c70..d26f69b0184f 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -946,8 +946,7 @@ err:
work_done++;
}
- while ((skb = __skb_dequeue(&errq)))
- kfree_skb(skb);
+ __skb_queue_purge(&errq);
work_done -= handle_incoming_queue(dev, &rxq);
@@ -1079,8 +1078,7 @@ static void xennet_release_rx_bufs(struct netfront_info *np)
}
}
- while ((skb = __skb_dequeue(&free_list)) != NULL)
- dev_kfree_skb(skb);
+ __skb_queue_purge(&free_list);
spin_unlock_bh(&np->rx_lock);
}
diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c
index 715a44471617..b2ccdcbeb896 100644
--- a/drivers/of/of_i2c.c
+++ b/drivers/of/of_i2c.c
@@ -21,7 +21,6 @@ struct i2c_driver_device {
};
static struct i2c_driver_device i2c_devices[] = {
- { "dallas,ds1374", "rtc-ds1374" },
};
static int of_find_i2c_driver(struct device_node *node,
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index ec8f7002b09d..39bb96b413ef 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -178,8 +178,7 @@ static int pci_vpd_pci22_read(struct pci_dev *dev, int pos, int size,
int ret;
int begin, end, i;
- if (pos < 0 || pos > PCI_VPD_PCI22_SIZE ||
- size > PCI_VPD_PCI22_SIZE - pos)
+ if (pos < 0 || pos > vpd->base.len || size > vpd->base.len - pos)
return -EINVAL;
if (size == 0)
return 0;
@@ -223,8 +222,8 @@ static int pci_vpd_pci22_write(struct pci_dev *dev, int pos, int size,
u32 val;
int ret;
- if (pos < 0 || pos > PCI_VPD_PCI22_SIZE || pos & 3 ||
- size > PCI_VPD_PCI22_SIZE - pos || size < 4)
+ if (pos < 0 || pos > vpd->base.len || pos & 3 ||
+ size > vpd->base.len - pos || size < 4)
return -EINVAL;
val = (u8) *buf++;
@@ -255,11 +254,6 @@ out:
return 4;
}
-static int pci_vpd_pci22_get_size(struct pci_dev *dev)
-{
- return PCI_VPD_PCI22_SIZE;
-}
-
static void pci_vpd_pci22_release(struct pci_dev *dev)
{
kfree(container_of(dev->vpd, struct pci_vpd_pci22, base));
@@ -268,7 +262,6 @@ static void pci_vpd_pci22_release(struct pci_dev *dev)
static struct pci_vpd_ops pci_vpd_pci22_ops = {
.read = pci_vpd_pci22_read,
.write = pci_vpd_pci22_write,
- .get_size = pci_vpd_pci22_get_size,
.release = pci_vpd_pci22_release,
};
@@ -284,6 +277,7 @@ int pci_vpd_pci22_init(struct pci_dev *dev)
if (!vpd)
return -ENOMEM;
+ vpd->base.len = PCI_VPD_PCI22_SIZE;
vpd->base.ops = &pci_vpd_pci22_ops;
spin_lock_init(&vpd->lock);
vpd->cap = cap;
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 648596d469f6..91156f85a926 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -700,9 +700,10 @@ cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
cleanup_p2p_bridge, NULL, NULL);
- if (!(bridge = acpiphp_handle_to_bridge(handle)))
- return AE_OK;
- cleanup_bridge(bridge);
+ bridge = acpiphp_handle_to_bridge(handle);
+ if (bridge)
+ cleanup_bridge(bridge);
+
return AE_OK;
}
@@ -715,9 +716,19 @@ static void remove_bridge(acpi_handle handle)
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
(u32)1, cleanup_p2p_bridge, NULL, NULL);
+ /*
+ * On root bridges with hotplug slots directly underneath (ie,
+ * no p2p bridge inbetween), we call cleanup_bridge().
+ *
+ * The else clause cleans up root bridges that either had no
+ * hotplug slots at all, or had a p2p bridge underneath.
+ */
bridge = acpiphp_handle_to_bridge(handle);
if (bridge)
cleanup_bridge(bridge);
+ else
+ acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ handle_hotplug_event_bridge);
}
static struct pci_dev * get_apic_pci_info(acpi_handle handle)
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index 925ba16355ce..a11021e8ce37 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -619,6 +619,7 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
int pci_hp_register (struct hotplug_slot *slot)
{
int result;
+ struct hotplug_slot *tmp;
if (slot == NULL)
return -ENODEV;
@@ -630,7 +631,11 @@ int pci_hp_register (struct hotplug_slot *slot)
return -EINVAL;
}
- /* this can fail if we have already registered a slot with the same name */
+ /* Check if we have already registered a slot with the same name. */
+ tmp = get_slot_from_name(slot->name);
+ if (tmp)
+ return -EEXIST;
+
slot->kobj.kset = pci_hotplug_slots_kset;
result = kobject_init_and_add(&slot->kobj, &hotplug_slot_ktype, NULL,
"%s", slot->name);
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 8264a7680435..79c9ddaad3fb 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -97,6 +97,7 @@ struct controller {
u8 cap_base;
struct timer_list poll_timer;
volatile int cmd_busy;
+ unsigned int no_cmd_complete:1;
};
#define INT_BUTTON_IGNORE 0
@@ -135,6 +136,7 @@ struct controller {
#define PWR_LED_PRSN 0x00000010
#define HP_SUPR_RM_SUP 0x00000020
#define EMI_PRSN 0x00020000
+#define NO_CMD_CMPL_SUP 0x00040000
#define ATTN_BUTTN(ctrl) ((ctrl)->slot_cap & ATTN_BUTTN_PRSN)
#define POWER_CTRL(ctrl) ((ctrl)->slot_cap & PWR_CTRL_PRSN)
@@ -143,13 +145,14 @@ struct controller {
#define PWR_LED(ctrl) ((ctrl)->slot_cap & PWR_LED_PRSN)
#define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & HP_SUPR_RM_SUP)
#define EMI(ctrl) ((ctrl)->slot_cap & EMI_PRSN)
+#define NO_CMD_CMPL(ctrl) ((ctrl)->slot_cap & NO_CMD_CMPL_SUP)
extern int pciehp_sysfs_enable_slot(struct slot *slot);
extern int pciehp_sysfs_disable_slot(struct slot *slot);
-extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl);
-extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
-extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
-extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_attention_button(struct slot *p_slot);
+ extern u8 pciehp_handle_switch_change(struct slot *p_slot);
+extern u8 pciehp_handle_presence_change(struct slot *p_slot);
+extern u8 pciehp_handle_power_fault(struct slot *p_slot);
extern int pciehp_configure_device(struct slot *p_slot);
extern int pciehp_unconfigure_device(struct slot *p_slot);
extern void pciehp_queue_pushbutton_work(struct work_struct *work);
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 43d8ddb2d679..48a2ed378914 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -254,7 +254,11 @@ static int init_slots(struct controller *ctrl)
slot->hp_slot, slot->number, ctrl->slot_device_offset);
retval = pci_hp_register(hotplug_slot);
if (retval) {
- err ("pci_hp_register failed with error %d\n", retval);
+ err("pci_hp_register failed with error %d\n", retval);
+ if (retval == -EEXIST)
+ err("Failed to register slot because of name "
+ "collision. Try \'pciehp_slot_with_bus\' "
+ "module option.\n");
goto error_info;
}
/* create additional sysfs entries */
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 0a7aa628e955..96a5d55a4983 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -55,16 +55,13 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
return 0;
}
-u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
+u8 pciehp_handle_attention_button(struct slot *p_slot)
{
- struct slot *p_slot;
u32 event_type;
/* Attention Button Change */
dbg("pciehp: Attention button interrupt received.\n");
- p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
-
/*
* Button pressed - See if need to TAKE ACTION!!!
*/
@@ -76,18 +73,15 @@ u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
return 0;
}
-u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
+u8 pciehp_handle_switch_change(struct slot *p_slot)
{
- struct slot *p_slot;
u8 getstatus;
u32 event_type;
/* Switch Change */
dbg("pciehp: Switch interrupt received.\n");
- p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
-
if (getstatus) {
/*
* Switch opened
@@ -107,17 +101,14 @@ u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
return 1;
}
-u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
+u8 pciehp_handle_presence_change(struct slot *p_slot)
{
- struct slot *p_slot;
u32 event_type;
u8 presence_save;
/* Presence Change */
dbg("pciehp: Presence/Notify input change.\n");
- p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
-
/* Switch is open, assume a presence change
* Save the presence state
*/
@@ -141,16 +132,13 @@ u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
return 1;
}
-u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
+u8 pciehp_handle_power_fault(struct slot *p_slot)
{
- struct slot *p_slot;
u32 event_type;
/* power fault */
dbg("pciehp: Power fault interrupt received.\n");
- p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
-
if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
/*
* power fault Cleared
@@ -163,7 +151,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
*/
info("Power fault on Slot(%s)\n", p_slot->name);
event_type = INT_POWER_FAULT;
- info("power fault bit %x set\n", hp_slot);
+ info("power fault bit %x set\n", 0);
}
queue_interrupt_event(p_slot, event_type);
@@ -186,6 +174,13 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
}
}
+ /*
+ * After turning power off, we must wait for at least 1 second
+ * before taking any action that relies on power having been
+ * removed from the slot/adapter.
+ */
+ msleep(1000);
+
if (PWR_LED(ctrl))
pslot->hpc_ops->green_led_off(pslot);
@@ -289,6 +284,13 @@ static int remove_board(struct slot *p_slot)
}
}
+ /*
+ * After turning power off, we must wait for at least 1 second
+ * before taking any action that relies on power having been
+ * removed from the slot/adapter.
+ */
+ msleep(1000);
+
if (PWR_LED(ctrl))
/* turn off Green LED */
p_slot->hpc_ops->green_led_off(p_slot);
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 891f81a0400c..79f104963166 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -247,14 +247,38 @@ static inline void pciehp_free_irq(struct controller *ctrl)
free_irq(ctrl->pci_dev->irq, ctrl);
}
-static inline int pcie_wait_cmd(struct controller *ctrl)
+static inline int pcie_poll_cmd(struct controller *ctrl)
+{
+ u16 slot_status;
+ int timeout = 1000;
+
+ if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status))
+ if (slot_status & CMD_COMPLETED)
+ goto completed;
+ for (timeout = 1000; timeout > 0; timeout -= 100) {
+ msleep(100);
+ if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status))
+ if (slot_status & CMD_COMPLETED)
+ goto completed;
+ }
+ return 0; /* timeout */
+
+completed:
+ pciehp_writew(ctrl, SLOTSTATUS, CMD_COMPLETED);
+ return timeout;
+}
+
+static inline int pcie_wait_cmd(struct controller *ctrl, int poll)
{
int retval = 0;
unsigned int msecs = pciehp_poll_mode ? 2500 : 1000;
unsigned long timeout = msecs_to_jiffies(msecs);
int rc;
- rc = wait_event_interruptible_timeout(ctrl->queue,
+ if (poll)
+ rc = pcie_poll_cmd(ctrl);
+ else
+ rc = wait_event_interruptible_timeout(ctrl->queue,
!ctrl->cmd_busy, timeout);
if (!rc)
dbg("Command not completed in 1000 msec\n");
@@ -286,12 +310,28 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
goto out;
}
- if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) {
- /* After 1 sec and CMD_COMPLETED still not set, just
- proceed forward to issue the next command according
- to spec. Just print out the error message */
- dbg("%s: CMD_COMPLETED not clear after 1 sec.\n",
- __func__);
+ if (slot_status & CMD_COMPLETED) {
+ if (!ctrl->no_cmd_complete) {
+ /*
+ * After 1 sec and CMD_COMPLETED still not set, just
+ * proceed forward to issue the next command according
+ * to spec. Just print out the error message.
+ */
+ dbg("%s: CMD_COMPLETED not clear after 1 sec.\n",
+ __func__);
+ } else if (!NO_CMD_CMPL(ctrl)) {
+ /*
+ * This controller semms to notify of command completed
+ * event even though it supports none of power
+ * controller, attention led, power led and EMI.
+ */
+ dbg("%s: Unexpected CMD_COMPLETED. Need to wait for "
+ "command completed event.\n", __func__);
+ ctrl->no_cmd_complete = 0;
+ } else {
+ dbg("%s: Unexpected CMD_COMPLETED. Maybe the "
+ "controller is broken.\n", __func__);
+ }
}
retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
@@ -315,8 +355,18 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
/*
* Wait for command completion.
*/
- if (!retval)
- retval = pcie_wait_cmd(ctrl);
+ if (!retval && !ctrl->no_cmd_complete) {
+ int poll = 0;
+ /*
+ * if hotplug interrupt is not enabled or command
+ * completed interrupt is not enabled, we need to poll
+ * command completed event.
+ */
+ if (!(slot_ctrl & HP_INTR_ENABLE) ||
+ !(slot_ctrl & CMD_CMPL_INTR_ENABLE))
+ poll = 1;
+ retval = pcie_wait_cmd(ctrl, poll);
+ }
out:
mutex_unlock(&ctrl->ctrl_lock);
return retval;
@@ -704,13 +754,6 @@ static int hpc_power_off_slot(struct slot * slot)
}
dbg("%s: SLOTCTRL %x write cmd %x\n",
__func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
-
- /*
- * After turning power off, we must wait for at least 1 second
- * before taking any action that relies on power having been
- * removed from the slot/adapter.
- */
- msleep(1000);
out:
if (changed)
pcie_unmask_bad_dllp(ctrl);
@@ -722,6 +765,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
{
struct controller *ctrl = (struct controller *)dev_id;
u16 detected, intr_loc;
+ struct slot *p_slot;
/*
* In order to guarantee that all interrupt events are
@@ -756,21 +800,38 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
wake_up_interruptible(&ctrl->queue);
}
+ if (!(intr_loc & ~CMD_COMPLETED))
+ return IRQ_HANDLED;
+
+ /*
+ * Return without handling events if this handler routine is
+ * called before controller initialization is done. This may
+ * happen if hotplug event or another interrupt that shares
+ * the IRQ with pciehp arrives before slot initialization is
+ * done after interrupt handler is registered.
+ *
+ * FIXME - Need more structural fixes. We need to be ready to
+ * handle the event before installing interrupt handler.
+ */
+ p_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
+ if (!p_slot || !p_slot->hpc_ops)
+ return IRQ_HANDLED;
+
/* Check MRL Sensor Changed */
if (intr_loc & MRL_SENS_CHANGED)
- pciehp_handle_switch_change(0, ctrl);
+ pciehp_handle_switch_change(p_slot);
/* Check Attention Button Pressed */
if (intr_loc & ATTN_BUTTN_PRESSED)
- pciehp_handle_attention_button(0, ctrl);
+ pciehp_handle_attention_button(p_slot);
/* Check Presence Detect Changed */
if (intr_loc & PRSN_DETECT_CHANGED)
- pciehp_handle_presence_change(0, ctrl);
+ pciehp_handle_presence_change(p_slot);
/* Check Power Fault Detected */
if (intr_loc & PWR_FAULT_DETECTED)
- pciehp_handle_power_fault(0, ctrl);
+ pciehp_handle_power_fault(p_slot);
return IRQ_HANDLED;
}
@@ -1028,6 +1089,12 @@ static int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
static int pcie_init_hardware_part1(struct controller *ctrl,
struct pcie_device *dev)
{
+ /* Clear all remaining event bits in Slot Status register */
+ if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) {
+ err("%s: Cannot write to SLOTSTATUS register\n", __func__);
+ return -1;
+ }
+
/* Mask Hot-plug Interrupt Enable */
if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) {
err("%s: Cannot mask hotplug interrupt enable\n", __func__);
@@ -1040,16 +1107,6 @@ int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev)
{
u16 cmd, mask;
- /*
- * We need to clear all events before enabling hotplug interrupt
- * notification mechanism in order for hotplug controler to
- * generate interrupts.
- */
- if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) {
- err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
- return -1;
- }
-
cmd = PRSN_DETECT_ENABLE;
if (ATTN_BUTTN(ctrl))
cmd |= ATTN_BUTTN_ENABLE;
@@ -1116,6 +1173,7 @@ static inline void dbg_ctrl(struct controller *ctrl)
dbg(" Power Indicator : %3s\n", PWR_LED(ctrl) ? "yes" : "no");
dbg(" Hot-Plug Surprise : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no");
dbg(" EMI Present : %3s\n", EMI(ctrl) ? "yes" : "no");
+ dbg(" Comamnd Completed : %3s\n", NO_CMD_CMPL(ctrl)? "no" : "yes");
pciehp_readw(ctrl, SLOTSTATUS, &reg16);
dbg("Slot Status : 0x%04x\n", reg16);
pciehp_readw(ctrl, SLOTSTATUS, &reg16);
@@ -1147,6 +1205,15 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev)
mutex_init(&ctrl->ctrl_lock);
init_waitqueue_head(&ctrl->queue);
dbg_ctrl(ctrl);
+ /*
+ * Controller doesn't notify of command completion if the "No
+ * Command Completed Support" bit is set in Slot Capability
+ * register or the controller supports none of power
+ * controller, attention led, power led and EMI.
+ */
+ if (NO_CMD_CMPL(ctrl) ||
+ !(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl)))
+ ctrl->no_cmd_complete = 1;
info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n",
pdev->vendor, pdev->device,
diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c
index e32148a8fa12..779c5db71be4 100644
--- a/drivers/pci/hotplug/rpadlpar_sysfs.c
+++ b/drivers/pci/hotplug/rpadlpar_sysfs.c
@@ -18,8 +18,12 @@
#include "rpadlpar.h"
#define DLPAR_KOBJ_NAME "control"
-#define ADD_SLOT_ATTR_NAME "add_slot"
-#define REMOVE_SLOT_ATTR_NAME "remove_slot"
+
+/* Those two have no quotes because they are passed to __ATTR() which
+ * stringifies the argument (yuck !)
+ */
+#define ADD_SLOT_ATTR_NAME add_slot
+#define REMOVE_SLOT_ATTR_NAME remove_slot
#define MAX_DRC_NAME_LEN 64
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index 1648076600fc..97848654652a 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -162,6 +162,10 @@ static int init_slots(struct controller *ctrl)
retval = pci_hp_register(slot->hotplug_slot);
if (retval) {
err("pci_hp_register failed with error %d\n", retval);
+ if (retval == -EEXIST)
+ err("Failed to register slot because of name "
+ "collision. Try \'shpchp_slot_with_bus\' "
+ "module option.\n");
goto error_info;
}
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 72cf61ed8f96..e1637bd82b8e 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -181,7 +181,7 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
any need to change it. */
struct mempolicy *oldpol;
cpumask_t oldmask = current->cpus_allowed;
- int node = pcibus_to_node(dev->bus);
+ int node = dev_to_node(&dev->dev);
if (node >= 0) {
node_to_cpumask_ptr(nodecpumask, node);
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 271d41cc05ab..9c718583a237 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -489,13 +489,13 @@ pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr,
* @kobj: kobject for mapping
* @attr: struct bin_attribute for the file being mapped
* @vma: struct vm_area_struct passed into the mmap
+ * @write_combine: 1 for write_combine mapping
*
* Use the regular PCI mapping routines to map a PCI resource into userspace.
- * FIXME: write combining? maybe automatic for prefetchable regions?
*/
static int
pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
- struct vm_area_struct *vma)
+ struct vm_area_struct *vma, int write_combine)
{
struct pci_dev *pdev = to_pci_dev(container_of(kobj,
struct device, kobj));
@@ -518,7 +518,21 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
vma->vm_pgoff += start >> PAGE_SHIFT;
mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
- return pci_mmap_page_range(pdev, vma, mmap_type, 0);
+ return pci_mmap_page_range(pdev, vma, mmap_type, write_combine);
+}
+
+static int
+pci_mmap_resource_uc(struct kobject *kobj, struct bin_attribute *attr,
+ struct vm_area_struct *vma)
+{
+ return pci_mmap_resource(kobj, attr, vma, 0);
+}
+
+static int
+pci_mmap_resource_wc(struct kobject *kobj, struct bin_attribute *attr,
+ struct vm_area_struct *vma)
+{
+ return pci_mmap_resource(kobj, attr, vma, 1);
}
/**
@@ -541,9 +555,46 @@ pci_remove_resource_files(struct pci_dev *pdev)
sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
kfree(res_attr);
}
+
+ res_attr = pdev->res_attr_wc[i];
+ if (res_attr) {
+ sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
+ kfree(res_attr);
+ }
}
}
+static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine)
+{
+ /* allocate attribute structure, piggyback attribute name */
+ int name_len = write_combine ? 13 : 10;
+ struct bin_attribute *res_attr;
+ int retval;
+
+ res_attr = kzalloc(sizeof(*res_attr) + name_len, GFP_ATOMIC);
+ if (res_attr) {
+ char *res_attr_name = (char *)(res_attr + 1);
+
+ if (write_combine) {
+ pdev->res_attr_wc[num] = res_attr;
+ sprintf(res_attr_name, "resource%d_wc", num);
+ res_attr->mmap = pci_mmap_resource_wc;
+ } else {
+ pdev->res_attr[num] = res_attr;
+ sprintf(res_attr_name, "resource%d", num);
+ res_attr->mmap = pci_mmap_resource_uc;
+ }
+ res_attr->attr.name = res_attr_name;
+ res_attr->attr.mode = S_IRUSR | S_IWUSR;
+ res_attr->size = pci_resource_len(pdev, num);
+ res_attr->private = &pdev->resource[num];
+ retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
+ } else
+ retval = -ENOMEM;
+
+ return retval;
+}
+
/**
* pci_create_resource_files - create resource files in sysfs for @dev
* @dev: dev in question
@@ -557,31 +608,19 @@ static int pci_create_resource_files(struct pci_dev *pdev)
/* Expose the PCI resources from this device as files */
for (i = 0; i < PCI_ROM_RESOURCE; i++) {
- struct bin_attribute *res_attr;
/* skip empty resources */
if (!pci_resource_len(pdev, i))
continue;
- /* allocate attribute structure, piggyback attribute name */
- res_attr = kzalloc(sizeof(*res_attr) + 10, GFP_ATOMIC);
- if (res_attr) {
- char *res_attr_name = (char *)(res_attr + 1);
-
- pdev->res_attr[i] = res_attr;
- sprintf(res_attr_name, "resource%d", i);
- res_attr->attr.name = res_attr_name;
- res_attr->attr.mode = S_IRUSR | S_IWUSR;
- res_attr->size = pci_resource_len(pdev, i);
- res_attr->mmap = pci_mmap_resource;
- res_attr->private = &pdev->resource[i];
- retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
- if (retval) {
- pci_remove_resource_files(pdev);
- return retval;
- }
- } else {
- return -ENOMEM;
+ retval = pci_create_attr(pdev, i, 0);
+ /* for prefetchable resources, create a WC mappable file */
+ if (!retval && pdev->resource[i].flags & IORESOURCE_PREFETCH)
+ retval = pci_create_attr(pdev, i, 1);
+
+ if (retval) {
+ pci_remove_resource_files(pdev);
+ return retval;
}
}
return 0;
@@ -697,9 +736,9 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
attr = kzalloc(sizeof(*attr), GFP_ATOMIC);
if (attr) {
pdev->vpd->attr = attr;
- attr->size = pdev->vpd->ops->get_size(pdev);
+ attr->size = pdev->vpd->len;
attr->attr.name = "vpd";
- attr->attr.mode = S_IRUGO | S_IWUSR;
+ attr->attr.mode = S_IRUSR | S_IWUSR;
attr->read = pci_read_vpd;
attr->write = pci_write_vpd;
retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 0a497c1b4227..00408c97e5fc 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -21,11 +21,11 @@ extern int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val);
struct pci_vpd_ops {
int (*read)(struct pci_dev *dev, int pos, int size, char *buf);
int (*write)(struct pci_dev *dev, int pos, int size, const char *buf);
- int (*get_size)(struct pci_dev *dev);
void (*release)(struct pci_dev *dev);
};
struct pci_vpd {
+ unsigned int len;
struct pci_vpd_ops *ops;
struct bin_attribute *attr; /* descriptor for sysfs VPD entry */
};
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 61fedb2448b6..f82495583e63 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -506,6 +506,23 @@ static void free_link_state(struct pci_dev *pdev)
pdev->link_state = NULL;
}
+static int pcie_aspm_sanity_check(struct pci_dev *pdev)
+{
+ struct pci_dev *child_dev;
+ int child_pos;
+
+ /*
+ * Some functions in a slot might not all be PCIE functions, very
+ * strange. Disable ASPM for the whole slot
+ */
+ list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
+ child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP);
+ if (!child_pos)
+ return -EINVAL;
+ }
+ return 0;
+}
+
/*
* pcie_aspm_init_link_state: Initiate PCI express link state.
* It is called after the pcie and its children devices are scaned.
@@ -526,6 +543,9 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
if (list_empty(&pdev->subordinate->devices))
goto out;
+ if (pcie_aspm_sanity_check(pdev))
+ goto out;
+
mutex_lock(&aspm_lock);
link_state = kzalloc(sizeof(*link_state), GFP_KERNEL);
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index dabb563f51d9..338a3f94b4d4 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -1670,6 +1670,48 @@ static void __devinit quirk_via_cx700_pci_parking_caching(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching);
+/*
+ * For Broadcom 5706, 5708, 5709 rev. A nics, any read beyond the
+ * VPD end tag will hang the device. This problem was initially
+ * observed when a vpd entry was created in sysfs
+ * ('/sys/bus/pci/devices/<id>/vpd'). A read to this sysfs entry
+ * will dump 32k of data. Reading a full 32k will cause an access
+ * beyond the VPD end tag causing the device to hang. Once the device
+ * is hung, the bnx2 driver will not be able to reset the device.
+ * We believe that it is legal to read beyond the end tag and
+ * therefore the solution is to limit the read/write length.
+ */
+static void __devinit quirk_brcm_570x_limit_vpd(struct pci_dev *dev)
+{
+ /* Only disable the VPD capability for 5706, 5708, and 5709 rev. A */
+ if ((dev->device == PCI_DEVICE_ID_NX2_5706) ||
+ (dev->device == PCI_DEVICE_ID_NX2_5708) ||
+ ((dev->device == PCI_DEVICE_ID_NX2_5709) &&
+ (dev->revision & 0xf0) == 0x0)) {
+ if (dev->vpd)
+ dev->vpd->len = 0x80;
+ }
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+ PCI_DEVICE_ID_NX2_5706,
+ quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+ PCI_DEVICE_ID_NX2_5706S,
+ quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+ PCI_DEVICE_ID_NX2_5708,
+ quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+ PCI_DEVICE_ID_NX2_5708S,
+ quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+ PCI_DEVICE_ID_NX2_5709,
+ quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+ PCI_DEVICE_ID_NX2_5709S,
+ quirk_brcm_570x_limit_vpd);
+
#ifdef CONFIG_PCI_MSI
/* Some chipsets do not support MSI. We cannot easily rely on setting
* PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
@@ -1685,6 +1727,7 @@ static void __init quirk_disable_all_msi(struct pci_dev *dev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS480, quirk_disable_all_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3336, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disable_all_msi);
/* Disable MSI on chipsets that are known to not support it */
diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c
index 0a6cea1316b4..52d0aa8c2e7a 100644
--- a/drivers/pcmcia/electra_cf.c
+++ b/drivers/pcmcia/electra_cf.c
@@ -352,6 +352,7 @@ static struct of_device_id electra_cf_match[] = {
},
{},
};
+MODULE_DEVICE_TABLE(of, electra_cf_match);
static struct of_platform_driver electra_cf_driver = {
.name = (char *)driver_name,
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 0201c8adfda7..46c791adb894 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -50,15 +50,17 @@ static int irq_flags(int triggering, int polarity, int shareable)
flags = IORESOURCE_IRQ_HIGHEDGE;
}
- if (shareable)
+ if (shareable == ACPI_SHARED)
flags |= IORESOURCE_IRQ_SHAREABLE;
return flags;
}
-static void decode_irq_flags(int flag, int *triggering, int *polarity)
+static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering,
+ int *polarity, int *shareable)
{
- switch (flag) {
+ switch (flags & (IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_HIGHLEVEL |
+ IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE)) {
case IORESOURCE_IRQ_LOWLEVEL:
*triggering = ACPI_LEVEL_SENSITIVE;
*polarity = ACPI_ACTIVE_LOW;
@@ -75,7 +77,18 @@ static void decode_irq_flags(int flag, int *triggering, int *polarity)
*triggering = ACPI_EDGE_SENSITIVE;
*polarity = ACPI_ACTIVE_HIGH;
break;
+ default:
+ dev_err(&dev->dev, "can't encode invalid IRQ mode %#x\n",
+ flags);
+ *triggering = ACPI_EDGE_SENSITIVE;
+ *polarity = ACPI_ACTIVE_HIGH;
+ break;
}
+
+ if (flags & IORESOURCE_IRQ_SHAREABLE)
+ *shareable = ACPI_SHARED;
+ else
+ *shareable = ACPI_EXCLUSIVE;
}
static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev,
@@ -742,6 +755,9 @@ static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data)
if (pnpacpi_supported_resource(res)) {
(*resource)->type = res->type;
(*resource)->length = sizeof(struct acpi_resource);
+ if (res->type == ACPI_RESOURCE_TYPE_IRQ)
+ (*resource)->data.irq.descriptor_length =
+ res->data.irq.descriptor_length;
(*resource)++;
}
@@ -788,22 +804,21 @@ static void pnpacpi_encode_irq(struct pnp_dev *dev,
struct resource *p)
{
struct acpi_resource_irq *irq = &resource->data.irq;
- int triggering, polarity;
+ int triggering, polarity, shareable;
- decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity);
+ decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
irq->triggering = triggering;
irq->polarity = polarity;
- if (triggering == ACPI_EDGE_SENSITIVE)
- irq->sharable = ACPI_EXCLUSIVE;
- else
- irq->sharable = ACPI_SHARED;
+ irq->sharable = shareable;
irq->interrupt_count = 1;
irq->interrupts[0] = p->start;
- dev_dbg(&dev->dev, " encode irq %d %s %s %s\n", (int) p->start,
+ dev_dbg(&dev->dev, " encode irq %d %s %s %s (%d-byte descriptor)\n",
+ (int) p->start,
triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
polarity == ACPI_ACTIVE_LOW ? "low" : "high",
- irq->sharable == ACPI_SHARED ? "shared" : "exclusive");
+ irq->sharable == ACPI_SHARED ? "shared" : "exclusive",
+ irq->descriptor_length);
}
static void pnpacpi_encode_ext_irq(struct pnp_dev *dev,
@@ -811,16 +826,13 @@ static void pnpacpi_encode_ext_irq(struct pnp_dev *dev,
struct resource *p)
{
struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq;
- int triggering, polarity;
+ int triggering, polarity, shareable;
- decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity);
+ decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
extended_irq->producer_consumer = ACPI_CONSUMER;
extended_irq->triggering = triggering;
extended_irq->polarity = polarity;
- if (triggering == ACPI_EDGE_SENSITIVE)
- extended_irq->sharable = ACPI_EXCLUSIVE;
- else
- extended_irq->sharable = ACPI_SHARED;
+ extended_irq->sharable = shareable;
extended_irq->interrupt_count = 1;
extended_irq->interrupts[0] = p->start;
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index e2b7de4cb05e..1ff3bb585ab2 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -286,7 +286,7 @@ static void quirk_system_pci_resources(struct pnp_dev *dev)
pci_name(pdev), i,
(unsigned long long) pci_start,
(unsigned long long) pci_end);
- res->flags = 0;
+ res->flags |= IORESOURCE_DISABLED;
}
}
}
diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c
index 9c2496dbeee4..cf4e07b01d48 100644
--- a/drivers/pnp/system.c
+++ b/drivers/pnp/system.c
@@ -81,7 +81,7 @@ static void reserve_resources_of_dev(struct pnp_dev *dev)
}
for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) {
- if (res->flags & IORESOURCE_UNSET)
+ if (res->flags & (IORESOURCE_UNSET | IORESOURCE_DISABLED))
continue;
reserve_range(dev, res->start, res->end, 0);
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 138dd76ee347..af1633eb3b70 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -91,15 +91,13 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
{
int rc = 0;
- psy->dev = device_create(power_supply_class, parent, 0,
- "%s", psy->name);
+ psy->dev = device_create_drvdata(power_supply_class, parent, 0,
+ psy, "%s", psy->name);
if (IS_ERR(psy->dev)) {
rc = PTR_ERR(psy->dev);
goto dev_create_failed;
}
- dev_set_drvdata(psy->dev, psy);
-
INIT_WORK(&psy->changed_work, power_supply_changed_work);
rc = power_supply_create_attrs(psy);
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index c444d6b10c58..49215da5249b 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -201,7 +201,7 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
dev_dbg(dev, "uevent\n");
- if (!psy) {
+ if (!psy || !psy->dev) {
dev_dbg(dev, "No power supply yet\n");
return ret;
}
diff --git a/drivers/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c
index 3ce9f3defc12..956d3e79f6aa 100644
--- a/drivers/rapidio/rio-driver.c
+++ b/drivers/rapidio/rio-driver.c
@@ -101,8 +101,8 @@ static int rio_device_probe(struct device *dev)
if (error >= 0) {
rdev->driver = rdrv;
error = 0;
+ } else
rio_dev_put(rdev);
- }
}
return error;
}
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 6cc2c0330230..4949dc4859be 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -256,6 +256,17 @@ config RTC_DRV_S35390A
This driver can also be built as a module. If so the module
will be called rtc-s35390a.
+config RTC_DRV_FM3130
+ tristate "Ramtron FM3130"
+ help
+ If you say Y here you will get support for the
+ Ramtron FM3130 RTC chips.
+ Ramtron FM3130 is a chip with two separate devices inside,
+ RTC clock and FRAM. This driver provides only RTC functionality.
+
+ This driver can also be built as a module. If so the module
+ will be called rtc-fm3130.
+
endif # I2C
comment "SPI RTC drivers"
@@ -534,4 +545,12 @@ config RTC_DRV_RS5C313
help
If you say yes here you get support for the Ricoh RS5C313 RTC chips.
+config RTC_DRV_PPC
+ tristate "PowerPC machine dependent RTC support"
+ depends on PPC_MERGE
+ help
+ The PowerPC kernel has machine-specific functions for accessing
+ the RTC. This exposes that functionality through the generic RTC
+ class.
+
endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 872f1218ff9f..b6e14d51670b 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
+obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
@@ -41,6 +42,7 @@ obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
+obj-$(CONFIG_RTC_DRV_PPC) += rtc-ppc.o
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 7e3ad4f3b343..58b7336640ff 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -126,12 +126,25 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
int err;
struct rtc_time before, now;
int first_time = 1;
+ unsigned long t_now, t_alm;
+ enum { none, day, month, year } missing = none;
+ unsigned days;
- /* The lower level RTC driver may not be capable of filling
- * in all fields of the rtc_time struct (eg. rtc-cmos),
- * and so might instead return -1 in some fields.
- * We deal with that here by grabbing a current RTC timestamp
- * and using values from that for any missing (-1) values.
+ /* The lower level RTC driver may return -1 in some fields,
+ * creating invalid alarm->time values, for reasons like:
+ *
+ * - The hardware may not be capable of filling them in;
+ * many alarms match only on time-of-day fields, not
+ * day/month/year calendar data.
+ *
+ * - Some hardware uses illegal values as "wildcard" match
+ * values, which non-Linux firmware (like a BIOS) may try
+ * to set up as e.g. "alarm 15 minutes after each hour".
+ * Linux uses only oneshot alarms.
+ *
+ * When we see that here, we deal with it by using values from
+ * a current RTC timestamp for any missing (-1) values. The
+ * RTC driver prevents "periodic alarm" modes.
*
* But this can be racey, because some fields of the RTC timestamp
* may have wrapped in the interval since we read the RTC alarm,
@@ -174,6 +187,10 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
if (!alarm->enabled)
return 0;
+ /* full-function RTCs won't have such missing fields */
+ if (rtc_valid_tm(&alarm->time) == 0)
+ return 0;
+
/* get the "after" timestamp, to detect wrapped fields */
err = rtc_read_time(rtc, &now);
if (err < 0)
@@ -183,22 +200,85 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
} while ( before.tm_min != now.tm_min
|| before.tm_hour != now.tm_hour
|| before.tm_mon != now.tm_mon
- || before.tm_year != now.tm_year
- || before.tm_isdst != now.tm_isdst);
+ || before.tm_year != now.tm_year);
- /* Fill in any missing alarm fields using the timestamp */
+ /* Fill in the missing alarm fields using the timestamp; we
+ * know there's at least one since alarm->time is invalid.
+ */
if (alarm->time.tm_sec == -1)
alarm->time.tm_sec = now.tm_sec;
if (alarm->time.tm_min == -1)
alarm->time.tm_min = now.tm_min;
if (alarm->time.tm_hour == -1)
alarm->time.tm_hour = now.tm_hour;
- if (alarm->time.tm_mday == -1)
+
+ /* For simplicity, only support date rollover for now */
+ if (alarm->time.tm_mday == -1) {
alarm->time.tm_mday = now.tm_mday;
- if (alarm->time.tm_mon == -1)
+ missing = day;
+ }
+ if (alarm->time.tm_mon == -1) {
alarm->time.tm_mon = now.tm_mon;
- if (alarm->time.tm_year == -1)
+ if (missing == none)
+ missing = month;
+ }
+ if (alarm->time.tm_year == -1) {
alarm->time.tm_year = now.tm_year;
+ if (missing == none)
+ missing = year;
+ }
+
+ /* with luck, no rollover is needed */
+ rtc_tm_to_time(&now, &t_now);
+ rtc_tm_to_time(&alarm->time, &t_alm);
+ if (t_now < t_alm)
+ goto done;
+
+ switch (missing) {
+
+ /* 24 hour rollover ... if it's now 10am Monday, an alarm that
+ * that will trigger at 5am will do so at 5am Tuesday, which
+ * could also be in the next month or year. This is a common
+ * case, especially for PCs.
+ */
+ case day:
+ dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day");
+ t_alm += 24 * 60 * 60;
+ rtc_time_to_tm(t_alm, &alarm->time);
+ break;
+
+ /* Month rollover ... if it's the 31th, an alarm on the 3rd will
+ * be next month. An alarm matching on the 30th, 29th, or 28th
+ * may end up in the month after that! Many newer PCs support
+ * this type of alarm.
+ */
+ case month:
+ dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month");
+ do {
+ if (alarm->time.tm_mon < 11)
+ alarm->time.tm_mon++;
+ else {
+ alarm->time.tm_mon = 0;
+ alarm->time.tm_year++;
+ }
+ days = rtc_month_days(alarm->time.tm_mon,
+ alarm->time.tm_year);
+ } while (days < alarm->time.tm_mday);
+ break;
+
+ /* Year rollover ... easy except for leap years! */
+ case year:
+ dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year");
+ do {
+ alarm->time.tm_year++;
+ } while (!rtc_valid_tm(&alarm->time));
+ break;
+
+ default:
+ dev_warn(&rtc->dev, "alarm rollover not handled\n");
+ }
+
+done:
return 0;
}
EXPORT_SYMBOL_GPL(rtc_read_alarm);
diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c
index 42244f14b41c..2ef8cdfda4a7 100644
--- a/drivers/rtc/rtc-at32ap700x.c
+++ b/drivers/rtc/rtc-at32ap700x.c
@@ -94,8 +94,11 @@ static int at32_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
+ spin_lock_irq(&rtc->lock);
rtc_time_to_tm(rtc->alarm_time, &alrm->time);
- alrm->pending = rtc_readl(rtc, IMR) & RTC_BIT(IMR_TOPI) ? 1 : 0;
+ alrm->enabled = rtc_readl(rtc, IMR) & RTC_BIT(IMR_TOPI) ? 1 : 0;
+ alrm->pending = rtc_readl(rtc, ISR) & RTC_BIT(ISR_TOPI) ? 1 : 0;
+ spin_unlock_irq(&rtc->lock);
return 0;
}
@@ -119,7 +122,7 @@ static int at32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
spin_lock_irq(&rtc->lock);
rtc->alarm_time = alarm_unix_time;
rtc_writel(rtc, TOP, rtc->alarm_time);
- if (alrm->pending)
+ if (alrm->enabled)
rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
| RTC_BIT(CTRL_TOPEN));
else
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index d060a06ce05b..d7bb9bac71df 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -905,19 +905,7 @@ static struct pnp_driver cmos_pnp_driver = {
.resume = cmos_pnp_resume,
};
-static int __init cmos_init(void)
-{
- return pnp_register_driver(&cmos_pnp_driver);
-}
-module_init(cmos_init);
-
-static void __exit cmos_exit(void)
-{
- pnp_unregister_driver(&cmos_pnp_driver);
-}
-module_exit(cmos_exit);
-
-#else /* no PNP */
+#endif /* CONFIG_PNP */
/*----------------------------------------------------------------*/
@@ -958,20 +946,33 @@ static struct platform_driver cmos_platform_driver = {
static int __init cmos_init(void)
{
+#ifdef CONFIG_PNP
+ if (pnp_platform_devices)
+ return pnp_register_driver(&cmos_pnp_driver);
+ else
+ return platform_driver_probe(&cmos_platform_driver,
+ cmos_platform_probe);
+#else
return platform_driver_probe(&cmos_platform_driver,
cmos_platform_probe);
+#endif /* CONFIG_PNP */
}
module_init(cmos_init);
static void __exit cmos_exit(void)
{
+#ifdef CONFIG_PNP
+ if (pnp_platform_devices)
+ pnp_unregister_driver(&cmos_pnp_driver);
+ else
+ platform_driver_unregister(&cmos_platform_driver);
+#else
platform_driver_unregister(&cmos_platform_driver);
+#endif /* CONFIG_PNP */
}
module_exit(cmos_exit);
-#endif /* !PNP */
-
MODULE_AUTHOR("David Brownell");
MODULE_DESCRIPTION("Driver for PC-style 'CMOS' RTCs");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index fa2d2f8b3f4d..640acd20fdde 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -42,7 +42,7 @@
#define DS1374_REG_TCR 0x09 /* Trickle Charge */
static const struct i2c_device_id ds1374_id[] = {
- { "rtc-ds1374", 0 },
+ { "ds1374", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds1374_id);
diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c
new file mode 100644
index 000000000000..abfdfcbaa059
--- /dev/null
+++ b/drivers/rtc/rtc-fm3130.c
@@ -0,0 +1,501 @@
+/*
+ * rtc-fm3130.c - RTC driver for Ramtron FM3130 I2C chip.
+ *
+ * Copyright (C) 2008 Sergey Lapin
+ * Based on ds1307 driver by James Chapman and David Brownell
+ *
+ * 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/module.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+#define FM3130_RTC_CONTROL (0x0)
+#define FM3130_CAL_CONTROL (0x1)
+#define FM3130_RTC_SECONDS (0x2)
+#define FM3130_RTC_MINUTES (0x3)
+#define FM3130_RTC_HOURS (0x4)
+#define FM3130_RTC_DAY (0x5)
+#define FM3130_RTC_DATE (0x6)
+#define FM3130_RTC_MONTHS (0x7)
+#define FM3130_RTC_YEARS (0x8)
+
+#define FM3130_ALARM_SECONDS (0x9)
+#define FM3130_ALARM_MINUTES (0xa)
+#define FM3130_ALARM_HOURS (0xb)
+#define FM3130_ALARM_DATE (0xc)
+#define FM3130_ALARM_MONTHS (0xd)
+#define FM3130_ALARM_WP_CONTROL (0xe)
+
+#define FM3130_CAL_CONTROL_BIT_nOSCEN (1 << 7) /* Osciallator enabled */
+#define FM3130_RTC_CONTROL_BIT_LB (1 << 7) /* Low battery */
+#define FM3130_RTC_CONTROL_BIT_AF (1 << 6) /* Alarm flag */
+#define FM3130_RTC_CONTROL_BIT_CF (1 << 5) /* Century overflow */
+#define FM3130_RTC_CONTROL_BIT_POR (1 << 4) /* Power on reset */
+#define FM3130_RTC_CONTROL_BIT_AEN (1 << 3) /* Alarm enable */
+#define FM3130_RTC_CONTROL_BIT_CAL (1 << 2) /* Calibration mode */
+#define FM3130_RTC_CONTROL_BIT_WRITE (1 << 1) /* W=1 -> write mode W=0 normal */
+#define FM3130_RTC_CONTROL_BIT_READ (1 << 0) /* R=1 -> read mode R=0 normal */
+
+#define FM3130_CLOCK_REGS 7
+#define FM3130_ALARM_REGS 5
+
+struct fm3130 {
+ u8 reg_addr_time;
+ u8 reg_addr_alarm;
+ u8 regs[15];
+ struct i2c_msg msg[4];
+ struct i2c_client *client;
+ struct rtc_device *rtc;
+ int data_valid;
+ int alarm;
+};
+static const struct i2c_device_id fm3130_id[] = {
+ { "fm3130", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, fm3130_id);
+
+#define FM3130_MODE_NORMAL 0
+#define FM3130_MODE_WRITE 1
+#define FM3130_MODE_READ 2
+
+static void fm3130_rtc_mode(struct device *dev, int mode)
+{
+ struct fm3130 *fm3130 = dev_get_drvdata(dev);
+
+ fm3130->regs[FM3130_RTC_CONTROL] =
+ i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL);
+ switch (mode) {
+ case FM3130_MODE_NORMAL:
+ fm3130->regs[FM3130_RTC_CONTROL] &=
+ ~(FM3130_RTC_CONTROL_BIT_WRITE |
+ FM3130_RTC_CONTROL_BIT_READ);
+ break;
+ case FM3130_MODE_WRITE:
+ fm3130->regs[FM3130_RTC_CONTROL] |= FM3130_RTC_CONTROL_BIT_WRITE;
+ break;
+ case FM3130_MODE_READ:
+ fm3130->regs[FM3130_RTC_CONTROL] |= FM3130_RTC_CONTROL_BIT_READ;
+ break;
+ default:
+ dev_dbg(dev, "invalid mode %d\n", mode);
+ break;
+ }
+ /* Checking for alarm */
+ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) {
+ fm3130->alarm = 1;
+ fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF;
+ }
+ i2c_smbus_write_byte_data(fm3130->client,
+ FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL]);
+}
+
+static int fm3130_get_time(struct device *dev, struct rtc_time *t)
+{
+ struct fm3130 *fm3130 = dev_get_drvdata(dev);
+ int tmp;
+
+ if (!fm3130->data_valid) {
+ /* We have invalid data in RTC, probably due
+ to battery faults or other problems. Return EIO
+ for now, it will allow us to set data later insted
+ of error during probing which disables device */
+ return -EIO;
+ }
+ fm3130_rtc_mode(dev, FM3130_MODE_READ);
+
+ /* read the RTC date and time registers all at once */
+ tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent),
+ fm3130->msg, 2);
+ if (tmp != 2) {
+ dev_err(dev, "%s error %d\n", "read", tmp);
+ return -EIO;
+ }
+
+ fm3130_rtc_mode(dev, FM3130_MODE_NORMAL);
+
+ dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x"
+ "%02x %02x %02x %02x %02x %02x %02x\n",
+ "read",
+ fm3130->regs[0], fm3130->regs[1],
+ fm3130->regs[2], fm3130->regs[3],
+ fm3130->regs[4], fm3130->regs[5],
+ fm3130->regs[6], fm3130->regs[7],
+ fm3130->regs[8], fm3130->regs[9],
+ fm3130->regs[0xa], fm3130->regs[0xb],
+ fm3130->regs[0xc], fm3130->regs[0xd],
+ fm3130->regs[0xe]);
+
+ t->tm_sec = BCD2BIN(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f);
+ t->tm_min = BCD2BIN(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
+ tmp = fm3130->regs[FM3130_RTC_HOURS] & 0x3f;
+ t->tm_hour = BCD2BIN(tmp);
+ t->tm_wday = BCD2BIN(fm3130->regs[FM3130_RTC_DAY] & 0x07) - 1;
+ t->tm_mday = BCD2BIN(fm3130->regs[FM3130_RTC_DATE] & 0x3f);
+ tmp = fm3130->regs[FM3130_RTC_MONTHS] & 0x1f;
+ t->tm_mon = BCD2BIN(tmp) - 1;
+
+ /* assume 20YY not 19YY, and ignore CF bit */
+ t->tm_year = BCD2BIN(fm3130->regs[FM3130_RTC_YEARS]) + 100;
+
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
+ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+ "read", t->tm_sec, t->tm_min,
+ t->tm_hour, t->tm_mday,
+ t->tm_mon, t->tm_year, t->tm_wday);
+
+ /* initial clock setting can be undefined */
+ return rtc_valid_tm(t);
+}
+
+
+static int fm3130_set_time(struct device *dev, struct rtc_time *t)
+{
+ struct fm3130 *fm3130 = dev_get_drvdata(dev);
+ int tmp, i;
+ u8 *buf = fm3130->regs;
+
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
+ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+ "write", t->tm_sec, t->tm_min,
+ t->tm_hour, t->tm_mday,
+ t->tm_mon, t->tm_year, t->tm_wday);
+
+ /* first register addr */
+ buf[FM3130_RTC_SECONDS] = BIN2BCD(t->tm_sec);
+ buf[FM3130_RTC_MINUTES] = BIN2BCD(t->tm_min);
+ buf[FM3130_RTC_HOURS] = BIN2BCD(t->tm_hour);
+ buf[FM3130_RTC_DAY] = BIN2BCD(t->tm_wday + 1);
+ buf[FM3130_RTC_DATE] = BIN2BCD(t->tm_mday);
+ buf[FM3130_RTC_MONTHS] = BIN2BCD(t->tm_mon + 1);
+
+ /* assume 20YY not 19YY */
+ tmp = t->tm_year - 100;
+ buf[FM3130_RTC_YEARS] = BIN2BCD(tmp);
+
+ dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x"
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ "write", buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6], buf[7],
+ buf[8], buf[9], buf[0xa], buf[0xb],
+ buf[0xc], buf[0xd], buf[0xe]);
+
+ fm3130_rtc_mode(dev, FM3130_MODE_WRITE);
+
+ /* Writing time registers, we don't support multibyte transfers */
+ for (i = 0; i < FM3130_CLOCK_REGS; i++) {
+ i2c_smbus_write_byte_data(fm3130->client,
+ FM3130_RTC_SECONDS + i,
+ fm3130->regs[FM3130_RTC_SECONDS + i]);
+ }
+
+ fm3130_rtc_mode(dev, FM3130_MODE_NORMAL);
+
+ /* We assume here that data are valid once written */
+ if (!fm3130->data_valid)
+ fm3130->data_valid = 1;
+ return 0;
+}
+
+static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct fm3130 *fm3130 = dev_get_drvdata(dev);
+ int tmp;
+ struct rtc_time *tm = &alrm->time;
+ /* read the RTC alarm registers all at once */
+ tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent),
+ &fm3130->msg[2], 2);
+ if (tmp != 2) {
+ dev_err(dev, "%s error %d\n", "read", tmp);
+ return -EIO;
+ }
+ dev_dbg(dev, "alarm read %02x %02x %02x %02x %02x\n",
+ fm3130->regs[FM3130_ALARM_SECONDS],
+ fm3130->regs[FM3130_ALARM_MINUTES],
+ fm3130->regs[FM3130_ALARM_HOURS],
+ fm3130->regs[FM3130_ALARM_DATE],
+ fm3130->regs[FM3130_ALARM_MONTHS]);
+
+
+ tm->tm_sec = BCD2BIN(fm3130->regs[FM3130_ALARM_SECONDS] & 0x7F);
+ tm->tm_min = BCD2BIN(fm3130->regs[FM3130_ALARM_MINUTES] & 0x7F);
+ tm->tm_hour = BCD2BIN(fm3130->regs[FM3130_ALARM_HOURS] & 0x3F);
+ tm->tm_mday = BCD2BIN(fm3130->regs[FM3130_ALARM_DATE] & 0x3F);
+ tm->tm_mon = BCD2BIN(fm3130->regs[FM3130_ALARM_MONTHS] & 0x1F);
+ if (tm->tm_mon > 0)
+ tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
+ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+ "read alarm", tm->tm_sec, tm->tm_min,
+ tm->tm_hour, tm->tm_mday,
+ tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+ return 0;
+}
+
+static int fm3130_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct fm3130 *fm3130 = dev_get_drvdata(dev);
+ struct rtc_time *tm = &alrm->time;
+ int i;
+
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
+ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+ "write alarm", tm->tm_sec, tm->tm_min,
+ tm->tm_hour, tm->tm_mday,
+ tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+ if (tm->tm_sec != -1)
+ fm3130->regs[FM3130_ALARM_SECONDS] =
+ BIN2BCD(tm->tm_sec) | 0x80;
+
+ if (tm->tm_min != -1)
+ fm3130->regs[FM3130_ALARM_MINUTES] =
+ BIN2BCD(tm->tm_min) | 0x80;
+
+ if (tm->tm_hour != -1)
+ fm3130->regs[FM3130_ALARM_HOURS] =
+ BIN2BCD(tm->tm_hour) | 0x80;
+
+ if (tm->tm_mday != -1)
+ fm3130->regs[FM3130_ALARM_DATE] =
+ BIN2BCD(tm->tm_mday) | 0x80;
+
+ if (tm->tm_mon != -1)
+ fm3130->regs[FM3130_ALARM_MONTHS] =
+ BIN2BCD(tm->tm_mon + 1) | 0x80;
+
+ dev_dbg(dev, "alarm write %02x %02x %02x %02x %02x\n",
+ fm3130->regs[FM3130_ALARM_SECONDS],
+ fm3130->regs[FM3130_ALARM_MINUTES],
+ fm3130->regs[FM3130_ALARM_HOURS],
+ fm3130->regs[FM3130_ALARM_DATE],
+ fm3130->regs[FM3130_ALARM_MONTHS]);
+ /* Writing time registers, we don't support multibyte transfers */
+ for (i = 0; i < FM3130_ALARM_REGS; i++) {
+ i2c_smbus_write_byte_data(fm3130->client,
+ FM3130_ALARM_SECONDS + i,
+ fm3130->regs[FM3130_ALARM_SECONDS + i]);
+ }
+ fm3130->regs[FM3130_RTC_CONTROL] =
+ i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL);
+ /* Checking for alarm */
+ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) {
+ fm3130->alarm = 1;
+ fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF;
+ }
+ if (alrm->enabled) {
+ i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL,
+ (fm3130->regs[FM3130_RTC_CONTROL] &
+ ~(FM3130_RTC_CONTROL_BIT_CAL)) |
+ FM3130_RTC_CONTROL_BIT_AEN);
+ } else {
+ i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL,
+ fm3130->regs[FM3130_RTC_CONTROL] &
+ ~(FM3130_RTC_CONTROL_BIT_AEN));
+ }
+ return 0;
+}
+
+static const struct rtc_class_ops fm3130_rtc_ops = {
+ .read_time = fm3130_get_time,
+ .set_time = fm3130_set_time,
+ .read_alarm = fm3130_read_alarm,
+ .set_alarm = fm3130_set_alarm,
+};
+
+static struct i2c_driver fm3130_driver;
+
+static int __devinit fm3130_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct fm3130 *fm3130;
+ int err = -ENODEV;
+ int tmp;
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+
+ if (!i2c_check_functionality(adapter,
+ I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+ return -EIO;
+
+ fm3130 = kzalloc(sizeof(struct fm3130), GFP_KERNEL);
+
+ if (!fm3130)
+ return -ENOMEM;
+
+ fm3130->client = client;
+ i2c_set_clientdata(client, fm3130);
+ fm3130->reg_addr_time = FM3130_RTC_SECONDS;
+ fm3130->reg_addr_alarm = FM3130_ALARM_SECONDS;
+
+ /* Messages to read time */
+ fm3130->msg[0].addr = client->addr;
+ fm3130->msg[0].flags = 0;
+ fm3130->msg[0].len = 1;
+ fm3130->msg[0].buf = &fm3130->reg_addr_time;
+
+ fm3130->msg[1].addr = client->addr;
+ fm3130->msg[1].flags = I2C_M_RD;
+ fm3130->msg[1].len = FM3130_CLOCK_REGS;
+ fm3130->msg[1].buf = &fm3130->regs[FM3130_RTC_SECONDS];
+
+ /* Messages to read alarm */
+ fm3130->msg[2].addr = client->addr;
+ fm3130->msg[2].flags = 0;
+ fm3130->msg[2].len = 1;
+ fm3130->msg[2].buf = &fm3130->reg_addr_alarm;
+
+ fm3130->msg[3].addr = client->addr;
+ fm3130->msg[3].flags = I2C_M_RD;
+ fm3130->msg[3].len = FM3130_ALARM_REGS;
+ fm3130->msg[3].buf = &fm3130->regs[FM3130_ALARM_SECONDS];
+
+ fm3130->data_valid = 0;
+
+ tmp = i2c_transfer(adapter, fm3130->msg, 4);
+ if (tmp != 4) {
+ pr_debug("read error %d\n", tmp);
+ err = -EIO;
+ goto exit_free;
+ }
+
+ fm3130->regs[FM3130_RTC_CONTROL] =
+ i2c_smbus_read_byte_data(client, FM3130_RTC_CONTROL);
+ fm3130->regs[FM3130_CAL_CONTROL] =
+ i2c_smbus_read_byte_data(client, FM3130_CAL_CONTROL);
+
+ /* Checking for alarm */
+ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) {
+ fm3130->alarm = 1;
+ fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF;
+ }
+
+ /* Disabling calibration mode */
+ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL)
+ i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
+ fm3130->regs[FM3130_RTC_CONTROL] &
+ ~(FM3130_RTC_CONTROL_BIT_CAL));
+ dev_warn(&client->dev, "Disabling calibration mode!\n");
+
+ /* Disabling read and write modes */
+ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_WRITE ||
+ fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_READ)
+ i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
+ fm3130->regs[FM3130_RTC_CONTROL] &
+ ~(FM3130_RTC_CONTROL_BIT_READ |
+ FM3130_RTC_CONTROL_BIT_WRITE));
+ dev_warn(&client->dev, "Disabling READ or WRITE mode!\n");
+
+ /* oscillator off? turn it on, so clock can tick. */
+ if (fm3130->regs[FM3130_CAL_CONTROL] & FM3130_CAL_CONTROL_BIT_nOSCEN)
+ i2c_smbus_write_byte_data(client, FM3130_CAL_CONTROL,
+ fm3130->regs[FM3130_CAL_CONTROL] &
+ ~(FM3130_CAL_CONTROL_BIT_nOSCEN));
+
+ /* oscillator fault? clear flag, and warn */
+ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_LB)
+ dev_warn(&client->dev, "Low battery!\n");
+
+ /* oscillator fault? clear flag, and warn */
+ if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_POR) {
+ i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
+ fm3130->regs[FM3130_RTC_CONTROL] &
+ ~FM3130_RTC_CONTROL_BIT_POR);
+ dev_warn(&client->dev, "SET TIME!\n");
+ }
+ /* ACS is controlled by alarm */
+ i2c_smbus_write_byte_data(client, FM3130_ALARM_WP_CONTROL, 0x80);
+
+ /* TODO */
+ /* TODO need to sanity check alarm */
+ tmp = fm3130->regs[FM3130_RTC_SECONDS];
+ tmp = BCD2BIN(tmp & 0x7f);
+ if (tmp > 60)
+ goto exit_bad;
+ tmp = BCD2BIN(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
+ if (tmp > 60)
+ goto exit_bad;
+
+ tmp = BCD2BIN(fm3130->regs[FM3130_RTC_DATE] & 0x3f);
+ if (tmp == 0 || tmp > 31)
+ goto exit_bad;
+
+ tmp = BCD2BIN(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f);
+ if (tmp == 0 || tmp > 12)
+ goto exit_bad;
+
+ tmp = fm3130->regs[FM3130_RTC_HOURS];
+
+ fm3130->data_valid = 1;
+
+exit_bad:
+ if (!fm3130->data_valid)
+ dev_dbg(&client->dev,
+ "%s: %02x %02x %02x %02x %02x %02x %02x %02x"
+ "%02x %02x %02x %02x %02x %02x %02x\n",
+ "bogus registers",
+ fm3130->regs[0], fm3130->regs[1],
+ fm3130->regs[2], fm3130->regs[3],
+ fm3130->regs[4], fm3130->regs[5],
+ fm3130->regs[6], fm3130->regs[7],
+ fm3130->regs[8], fm3130->regs[9],
+ fm3130->regs[0xa], fm3130->regs[0xb],
+ fm3130->regs[0xc], fm3130->regs[0xd],
+ fm3130->regs[0xe]);
+
+ /* We won't bail out here because we just got invalid data.
+ Time setting from u-boot doesn't work anyway */
+ fm3130->rtc = rtc_device_register(client->name, &client->dev,
+ &fm3130_rtc_ops, THIS_MODULE);
+ if (IS_ERR(fm3130->rtc)) {
+ err = PTR_ERR(fm3130->rtc);
+ dev_err(&client->dev,
+ "unable to register the class device\n");
+ goto exit_free;
+ }
+ return 0;
+exit_free:
+ kfree(fm3130);
+ return err;
+}
+
+static int __devexit fm3130_remove(struct i2c_client *client)
+{
+ struct fm3130 *fm3130 = i2c_get_clientdata(client);
+
+ rtc_device_unregister(fm3130->rtc);
+ kfree(fm3130);
+ return 0;
+}
+
+static struct i2c_driver fm3130_driver = {
+ .driver = {
+ .name = "rtc-fm3130",
+ .owner = THIS_MODULE,
+ },
+ .probe = fm3130_probe,
+ .remove = __devexit_p(fm3130_remove),
+ .id_table = fm3130_id,
+};
+
+static int __init fm3130_init(void)
+{
+ return i2c_add_driver(&fm3130_driver);
+}
+module_init(fm3130_init);
+
+static void __exit fm3130_exit(void)
+{
+ i2c_del_driver(&fm3130_driver);
+}
+module_exit(fm3130_exit);
+
+MODULE_DESCRIPTION("RTC driver for FM3130");
+MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 0fc4c3630780..748a502a6355 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -302,6 +302,7 @@ static int pcf8563_remove(struct i2c_client *client)
static const struct i2c_device_id pcf8563_id[] = {
{ "pcf8563", 0 },
+ { "rtc8564", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf8563_id);
diff --git a/drivers/rtc/rtc-ppc.c b/drivers/rtc/rtc-ppc.c
new file mode 100644
index 000000000000..c8e97e25ef7e
--- /dev/null
+++ b/drivers/rtc/rtc-ppc.c
@@ -0,0 +1,69 @@
+/*
+ * RTC driver for ppc_md RTC functions
+ *
+ * © 2007 Red Hat, Inc.
+ *
+ * Author: David Woodhouse <dwmw2@infradead.org>
+ *
+ * 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/module.h>
+#include <linux/err.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <asm/machdep.h>
+
+static int ppc_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ ppc_md.get_rtc_time(tm);
+ return 0;
+}
+
+static int ppc_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ return ppc_md.set_rtc_time(tm);
+}
+
+static const struct rtc_class_ops ppc_rtc_ops = {
+ .set_time = ppc_rtc_set_time,
+ .read_time = ppc_rtc_read_time,
+};
+
+static struct rtc_device *rtc;
+static struct platform_device *ppc_rtc_pdev;
+
+static int __init ppc_rtc_init(void)
+{
+ if (!ppc_md.get_rtc_time || !ppc_md.set_rtc_time)
+ return -ENODEV;
+
+ ppc_rtc_pdev = platform_device_register_simple("ppc-rtc", 0, NULL, 0);
+ if (IS_ERR(ppc_rtc_pdev))
+ return PTR_ERR(ppc_rtc_pdev);
+
+ rtc = rtc_device_register("ppc_md", &ppc_rtc_pdev->dev,
+ &ppc_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ platform_device_unregister(ppc_rtc_pdev);
+ return PTR_ERR(rtc);
+ }
+
+ return 0;
+}
+
+static void __exit ppc_rtc_exit(void)
+{
+ rtc_device_unregister(rtc);
+ platform_device_unregister(ppc_rtc_pdev);
+}
+
+module_init(ppc_rtc_init);
+module_exit(ppc_rtc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_DESCRIPTION("Generic RTC class driver for PowerPC");
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 82f62d25f921..67421b0d3a7b 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -331,14 +331,14 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
RCNR = 0;
}
+ device_init_wakeup(&pdev->dev, 1);
+
rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops,
THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
- device_init_wakeup(&pdev->dev, 1);
-
platform_set_drvdata(pdev, rtc);
return 0;
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index eaf55945f21b..7dcfba1bbfe1 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -71,6 +71,7 @@
#define X1205_SR_RTCF 0x01 /* Clock failure */
#define X1205_SR_WEL 0x02 /* Write Enable Latch */
#define X1205_SR_RWEL 0x04 /* Register Write Enable */
+#define X1205_SR_AL0 0x20 /* Alarm 0 match */
#define X1205_DTR_DTR0 0x01
#define X1205_DTR_DTR1 0x02
@@ -78,6 +79,8 @@
#define X1205_HR_MIL 0x80 /* Set in ccr.hour for 24 hr mode */
+#define X1205_INT_AL0E 0x20 /* Alarm 0 enable */
+
static struct i2c_driver x1205_driver;
/*
@@ -89,8 +92,8 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
unsigned char reg_base)
{
unsigned char dt_addr[2] = { 0, reg_base };
-
unsigned char buf[8];
+ int i;
struct i2c_msg msgs[] = {
{ client->addr, 0, 2, dt_addr }, /* setup read ptr */
@@ -98,7 +101,7 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
};
/* read date registers */
- if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+ if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
@@ -110,6 +113,11 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5], buf[6], buf[7]);
+ /* Mask out the enable bits if these are alarm registers */
+ if (reg_base < X1205_CCR_BASE)
+ for (i = 0; i <= 4; i++)
+ buf[i] &= 0x7F;
+
tm->tm_sec = BCD2BIN(buf[CCR_SEC]);
tm->tm_min = BCD2BIN(buf[CCR_MIN]);
tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */
@@ -138,7 +146,7 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr)
};
/* read status register */
- if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+ if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
@@ -147,10 +155,11 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr)
}
static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
- int datetoo, u8 reg_base)
+ int datetoo, u8 reg_base, unsigned char alm_enable)
{
- int i, xfer;
+ int i, xfer, nbytes;
unsigned char buf[8];
+ unsigned char rdata[10] = { 0, reg_base };
static const unsigned char wel[3] = { 0, X1205_REG_SR,
X1205_SR_WEL };
@@ -189,6 +198,11 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
buf[CCR_Y2K] = BIN2BCD(tm->tm_year / 100);
}
+ /* If writing alarm registers, set compare bits on registers 0-4 */
+ if (reg_base < X1205_CCR_BASE)
+ for (i = 0; i <= 4; i++)
+ buf[i] |= 0x80;
+
/* this sequence is required to unlock the chip */
if ((xfer = i2c_master_send(client, wel, 3)) != 3) {
dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer);
@@ -200,19 +214,57 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
return -EIO;
}
+
/* write register's data */
- for (i = 0; i < (datetoo ? 8 : 3); i++) {
- unsigned char rdata[3] = { 0, reg_base + i, buf[i] };
+ if (datetoo)
+ nbytes = 8;
+ else
+ nbytes = 3;
+ for (i = 0; i < nbytes; i++)
+ rdata[2+i] = buf[i];
+
+ xfer = i2c_master_send(client, rdata, nbytes+2);
+ if (xfer != nbytes+2) {
+ dev_err(&client->dev,
+ "%s: result=%d addr=%02x, data=%02x\n",
+ __func__,
+ xfer, rdata[1], rdata[2]);
+ return -EIO;
+ }
+
+ /* If we wrote to the nonvolatile region, wait 10msec for write cycle*/
+ if (reg_base < X1205_CCR_BASE) {
+ unsigned char al0e[3] = { 0, X1205_REG_INT, 0 };
+
+ msleep(10);
- xfer = i2c_master_send(client, rdata, 3);
+ /* ...and set or clear the AL0E bit in the INT register */
+
+ /* Need to set RWEL again as the write has cleared it */
+ xfer = i2c_master_send(client, rwel, 3);
if (xfer != 3) {
dev_err(&client->dev,
- "%s: xfer=%d addr=%02x, data=%02x\n",
+ "%s: aloe rwel - %d\n",
__func__,
- xfer, rdata[1], rdata[2]);
+ xfer);
+ return -EIO;
+ }
+
+ if (alm_enable)
+ al0e[2] = X1205_INT_AL0E;
+
+ xfer = i2c_master_send(client, al0e, 3);
+ if (xfer != 3) {
+ dev_err(&client->dev,
+ "%s: al0e - %d\n",
+ __func__,
+ xfer);
return -EIO;
}
- };
+
+ /* and wait 10msec again for this write to complete */
+ msleep(10);
+ }
/* disable further writes */
if ((xfer = i2c_master_send(client, diswe, 3)) != 3) {
@@ -230,9 +282,9 @@ static int x1205_fix_osc(struct i2c_client *client)
tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
- if ((err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE)) < 0)
- dev_err(&client->dev,
- "unable to restart the oscillator\n");
+ err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE, 0);
+ if (err < 0)
+ dev_err(&client->dev, "unable to restart the oscillator\n");
return err;
}
@@ -248,7 +300,7 @@ static int x1205_get_dtrim(struct i2c_client *client, int *trim)
};
/* read dtr register */
- if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+ if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
@@ -280,7 +332,7 @@ static int x1205_get_atrim(struct i2c_client *client, int *trim)
};
/* read atr register */
- if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+ if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
dev_err(&client->dev, "%s: read error\n", __func__);
return -EIO;
}
@@ -403,14 +455,33 @@ static int x1205_validate_client(struct i2c_client *client)
static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
- return x1205_get_datetime(to_i2c_client(dev),
- &alrm->time, X1205_ALM0_BASE);
+ int err;
+ unsigned char intreg, status;
+ static unsigned char int_addr[2] = { 0, X1205_REG_INT };
+ struct i2c_client *client = to_i2c_client(dev);
+ struct i2c_msg msgs[] = {
+ { client->addr, 0, 2, int_addr }, /* setup read ptr */
+ { client->addr, I2C_M_RD, 1, &intreg }, /* read INT register */
+ };
+
+ /* read interrupt register and status register */
+ if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
+ dev_err(&client->dev, "%s: read error\n", __func__);
+ return -EIO;
+ }
+ err = x1205_get_status(client, &status);
+ if (err == 0) {
+ alrm->pending = (status & X1205_SR_AL0) ? 1 : 0;
+ alrm->enabled = (intreg & X1205_INT_AL0E) ? 1 : 0;
+ err = x1205_get_datetime(client, &alrm->time, X1205_ALM0_BASE);
+ }
+ return err;
}
static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
return x1205_set_datetime(to_i2c_client(dev),
- &alrm->time, 1, X1205_ALM0_BASE);
+ &alrm->time, 1, X1205_ALM0_BASE, alrm->enabled);
}
static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm)
@@ -422,7 +493,7 @@ static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int x1205_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
return x1205_set_datetime(to_i2c_client(dev),
- tm, 1, X1205_CCR_BASE);
+ tm, 1, X1205_CCR_BASE, 0);
}
static int x1205_rtc_proc(struct device *dev, struct seq_file *seq)
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 8ba3f135da22..1a4025683362 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -63,6 +63,7 @@ static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
*/
static wait_queue_head_t dasd_init_waitq;
static wait_queue_head_t dasd_flush_wq;
+static wait_queue_head_t generic_waitq;
/*
* Allocate memory for a new device structure.
@@ -1151,11 +1152,15 @@ static void __dasd_device_process_final_queue(struct dasd_device *device,
struct list_head *l, *n;
struct dasd_ccw_req *cqr;
struct dasd_block *block;
+ void (*callback)(struct dasd_ccw_req *, void *data);
+ void *callback_data;
list_for_each_safe(l, n, final_queue) {
cqr = list_entry(l, struct dasd_ccw_req, devlist);
list_del_init(&cqr->devlist);
block = cqr->block;
+ callback = cqr->callback;
+ callback_data = cqr->callback_data;
if (block)
spin_lock_bh(&block->queue_lock);
switch (cqr->status) {
@@ -1176,7 +1181,7 @@ static void __dasd_device_process_final_queue(struct dasd_device *device,
BUG();
}
if (cqr->callback != NULL)
- (cqr->callback)(cqr, cqr->callback_data);
+ (callback)(cqr, callback_data);
if (block)
spin_unlock_bh(&block->queue_lock);
}
@@ -1406,17 +1411,15 @@ static inline int _wait_for_wakeup(struct dasd_ccw_req *cqr)
*/
int dasd_sleep_on(struct dasd_ccw_req *cqr)
{
- wait_queue_head_t wait_q;
struct dasd_device *device;
int rc;
device = cqr->startdev;
- init_waitqueue_head (&wait_q);
cqr->callback = dasd_wakeup_cb;
- cqr->callback_data = (void *) &wait_q;
+ cqr->callback_data = (void *) &generic_waitq;
dasd_add_request_tail(cqr);
- wait_event(wait_q, _wait_for_wakeup(cqr));
+ wait_event(generic_waitq, _wait_for_wakeup(cqr));
/* Request status is either done or failed. */
rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
@@ -1429,20 +1432,18 @@ int dasd_sleep_on(struct dasd_ccw_req *cqr)
*/
int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr)
{
- wait_queue_head_t wait_q;
struct dasd_device *device;
int rc;
device = cqr->startdev;
- init_waitqueue_head (&wait_q);
cqr->callback = dasd_wakeup_cb;
- cqr->callback_data = (void *) &wait_q;
+ cqr->callback_data = (void *) &generic_waitq;
dasd_add_request_tail(cqr);
- rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr));
+ rc = wait_event_interruptible(generic_waitq, _wait_for_wakeup(cqr));
if (rc == -ERESTARTSYS) {
dasd_cancel_req(cqr);
/* wait (non-interruptible) for final status */
- wait_event(wait_q, _wait_for_wakeup(cqr));
+ wait_event(generic_waitq, _wait_for_wakeup(cqr));
}
rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
return rc;
@@ -1466,7 +1467,6 @@ static inline int _dasd_term_running_cqr(struct dasd_device *device)
int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
{
- wait_queue_head_t wait_q;
struct dasd_device *device;
int rc;
@@ -1478,9 +1478,8 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
return rc;
}
- init_waitqueue_head (&wait_q);
cqr->callback = dasd_wakeup_cb;
- cqr->callback_data = (void *) &wait_q;
+ cqr->callback_data = (void *) &generic_waitq;
cqr->status = DASD_CQR_QUEUED;
list_add(&cqr->devlist, &device->ccw_queue);
@@ -1489,7 +1488,7 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
spin_unlock_irq(get_ccwdev_lock(device->cdev));
- wait_event(wait_q, _wait_for_wakeup(cqr));
+ wait_event(generic_waitq, _wait_for_wakeup(cqr));
/* Request status is either done or failed. */
rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
@@ -2430,6 +2429,7 @@ static int __init dasd_init(void)
init_waitqueue_head(&dasd_init_waitq);
init_waitqueue_head(&dasd_flush_wq);
+ init_waitqueue_head(&generic_waitq);
/* register 'common' DASD debug area, used for all DBF_XXX calls */
dasd_debug_area = debug_register("dasd", 1, 1, 8 * sizeof(long));
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 0d98f1ff2edd..848ef7e8523f 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -549,7 +549,6 @@ raw3270_start_init(struct raw3270 *rp, struct raw3270_view *view,
struct raw3270_request *rq)
{
unsigned long flags;
- wait_queue_head_t wq;
int rc;
#ifdef CONFIG_TN3270_CONSOLE
@@ -566,20 +565,20 @@ raw3270_start_init(struct raw3270 *rp, struct raw3270_view *view,
return rq->rc;
}
#endif
- init_waitqueue_head(&wq);
rq->callback = raw3270_wake_init;
- rq->callback_data = &wq;
+ rq->callback_data = &raw3270_wait_queue;
spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
rc = __raw3270_start(rp, view, rq);
spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
if (rc)
return rc;
/* Now wait for the completion. */
- rc = wait_event_interruptible(wq, raw3270_request_final(rq));
+ rc = wait_event_interruptible(raw3270_wait_queue,
+ raw3270_request_final(rq));
if (rc == -ERESTARTSYS) { /* Interrupted by a signal. */
raw3270_halt_io(view->dev, rq);
/* No wait for the halt to complete. */
- wait_event(wq, raw3270_request_final(rq));
+ wait_event(raw3270_wait_queue, raw3270_request_final(rq));
return -ERESTARTSYS;
}
return rq->rc;
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
index 9e784d5f7f57..ad05a87bc480 100644
--- a/drivers/s390/char/sclp_config.c
+++ b/drivers/s390/char/sclp_config.c
@@ -40,7 +40,7 @@ static void sclp_cpu_capability_notify(struct work_struct *work)
put_online_cpus();
}
-static void sclp_cpu_change_notify(struct work_struct *work)
+static void __ref sclp_cpu_change_notify(struct work_struct *work)
{
smp_rescan_cpus();
}
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index 35707c04e613..3e577f655b18 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -71,9 +71,6 @@ static struct list_head sclp_vt220_outqueue;
/* Number of requests in outqueue */
static int sclp_vt220_outqueue_count;
-/* Wait queue used to delay write requests while we've run out of buffers */
-static wait_queue_head_t sclp_vt220_waitq;
-
/* Timer used for delaying write requests to merge subsequent messages into
* a single buffer */
static struct timer_list sclp_vt220_timer;
@@ -133,7 +130,6 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request)
} while (request && __sclp_vt220_emit(request));
if (request == NULL && sclp_vt220_flush_later)
sclp_vt220_emit_current();
- wake_up(&sclp_vt220_waitq);
/* Check if the tty needs a wake up call */
if (sclp_vt220_tty != NULL) {
tty_wakeup(sclp_vt220_tty);
@@ -383,7 +379,7 @@ sclp_vt220_timeout(unsigned long data)
*/
static int
__sclp_vt220_write(const unsigned char *buf, int count, int do_schedule,
- int convertlf, int may_schedule)
+ int convertlf, int may_fail)
{
unsigned long flags;
void *page;
@@ -395,15 +391,14 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule,
overall_written = 0;
spin_lock_irqsave(&sclp_vt220_lock, flags);
do {
- /* Create a sclp output buffer if none exists yet */
+ /* Create an sclp output buffer if none exists yet */
if (sclp_vt220_current_request == NULL) {
while (list_empty(&sclp_vt220_empty)) {
spin_unlock_irqrestore(&sclp_vt220_lock, flags);
- if (in_interrupt() || !may_schedule)
- sclp_sync_wait();
+ if (may_fail)
+ goto out;
else
- wait_event(sclp_vt220_waitq,
- !list_empty(&sclp_vt220_empty));
+ sclp_sync_wait();
spin_lock_irqsave(&sclp_vt220_lock, flags);
}
page = (void *) sclp_vt220_empty.next;
@@ -437,6 +432,7 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule,
add_timer(&sclp_vt220_timer);
}
spin_unlock_irqrestore(&sclp_vt220_lock, flags);
+out:
return overall_written;
}
@@ -520,19 +516,11 @@ sclp_vt220_close(struct tty_struct *tty, struct file *filp)
* character to the tty device. If the kernel uses this routine,
* it must call the flush_chars() routine (if defined) when it is
* done stuffing characters into the driver.
- *
- * NOTE: include/linux/tty_driver.h specifies that a character should be
- * ignored if there is no room in the queue. This driver implements a different
- * semantic in that it will block when there is no more room left.
- *
- * FIXME: putchar can currently be called from BH and other non blocking
- * handlers so this semantic isn't a good idea.
*/
static int
sclp_vt220_put_char(struct tty_struct *tty, unsigned char ch)
{
- __sclp_vt220_write(&ch, 1, 0, 0, 1);
- return 1;
+ return __sclp_vt220_write(&ch, 1, 0, 0, 1);
}
/*
@@ -653,7 +641,6 @@ static int __init __sclp_vt220_init(void)
spin_lock_init(&sclp_vt220_lock);
INIT_LIST_HEAD(&sclp_vt220_empty);
INIT_LIST_HEAD(&sclp_vt220_outqueue);
- init_waitqueue_head(&sclp_vt220_waitq);
init_timer(&sclp_vt220_timer);
sclp_vt220_current_request = NULL;
sclp_vt220_buffered_chars = 0;
@@ -786,6 +773,7 @@ sclp_vt220_con_init(void)
{
int rc;
+ INIT_LIST_HEAD(&sclp_vt220_register.list);
if (!CONSOLE_IS_SCLP)
return 0;
rc = __sclp_vt220_init();
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index dddf8d62c153..d0d565a05dfe 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -231,6 +231,9 @@ struct tape_device {
/* Request queue. */
struct list_head req_queue;
+ /* Request wait queue. */
+ wait_queue_head_t wait_queue;
+
/* Each tape device has (currently) two minor numbers. */
int first_minor;
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 8246ef3ab095..42ce7915fc5d 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -1598,7 +1598,7 @@ tape_3590_setup_device(struct tape_device *device)
rc = tape_3590_read_dev_chars(device, rdc_data);
if (rc) {
DBF_LH(3, "Read device characteristics failed!\n");
- goto fail_kmalloc;
+ goto fail_rdc_data;
}
rc = tape_std_assign(device);
if (rc)
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index ddc4a114e7f4..95da72bc17e8 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -179,11 +179,11 @@ tapeblock_requeue(struct work_struct *work) {
tapeblock_end_request(req, -EIO);
continue;
}
+ blkdev_dequeue_request(req);
+ nr_queued++;
spin_unlock_irq(&device->blk_data.request_queue_lock);
rc = tapeblock_start_request(device, req);
spin_lock_irq(&device->blk_data.request_queue_lock);
- blkdev_dequeue_request(req);
- nr_queued++;
}
spin_unlock_irq(&device->blk_data.request_queue_lock);
atomic_set(&device->blk_data.requeue_scheduled, 0);
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 76e44eb7c47f..c20e3c548343 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -449,6 +449,7 @@ tape_alloc_device(void)
INIT_LIST_HEAD(&device->req_queue);
INIT_LIST_HEAD(&device->node);
init_waitqueue_head(&device->state_change_wq);
+ init_waitqueue_head(&device->wait_queue);
device->tape_state = TS_INIT;
device->medium_state = MS_UNKNOWN;
*device->modeset_byte = 0;
@@ -954,21 +955,19 @@ __tape_wake_up(struct tape_request *request, void *data)
int
tape_do_io(struct tape_device *device, struct tape_request *request)
{
- wait_queue_head_t wq;
int rc;
- init_waitqueue_head(&wq);
spin_lock_irq(get_ccwdev_lock(device->cdev));
/* Setup callback */
request->callback = __tape_wake_up;
- request->callback_data = &wq;
+ request->callback_data = &device->wait_queue;
/* Add request to request queue and try to start it. */
rc = __tape_start_request(device, request);
spin_unlock_irq(get_ccwdev_lock(device->cdev));
if (rc)
return rc;
/* Request added to the queue. Wait for its completion. */
- wait_event(wq, (request->callback == NULL));
+ wait_event(device->wait_queue, (request->callback == NULL));
/* Get rc from request */
return request->rc;
}
@@ -989,20 +988,19 @@ int
tape_do_io_interruptible(struct tape_device *device,
struct tape_request *request)
{
- wait_queue_head_t wq;
int rc;
- init_waitqueue_head(&wq);
spin_lock_irq(get_ccwdev_lock(device->cdev));
/* Setup callback */
request->callback = __tape_wake_up_interruptible;
- request->callback_data = &wq;
+ request->callback_data = &device->wait_queue;
rc = __tape_start_request(device, request);
spin_unlock_irq(get_ccwdev_lock(device->cdev));
if (rc)
return rc;
/* Request added to the queue. Wait for its completion. */
- rc = wait_event_interruptible(wq, (request->callback == NULL));
+ rc = wait_event_interruptible(device->wait_queue,
+ (request->callback == NULL));
if (rc != -ERESTARTSYS)
/* Request finished normally. */
return request->rc;
@@ -1015,7 +1013,7 @@ tape_do_io_interruptible(struct tape_device *device,
/* Wait for the interrupt that acknowledges the halt. */
do {
rc = wait_event_interruptible(
- wq,
+ device->wait_queue,
(request->callback == NULL)
);
} while (rc == -ERESTARTSYS);
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index d101328a2980..6f852fdb6d70 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -768,10 +768,10 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
device_unregister(dev);
return ret;
}
- priv->class_device = device_create(vmlogrdr_class, dev,
- MKDEV(vmlogrdr_major,
- priv->minor_num),
- "%s", dev->bus_id);
+ priv->class_device = device_create_drvdata(vmlogrdr_class, dev,
+ MKDEV(vmlogrdr_major,
+ priv->minor_num),
+ priv, "%s", dev->bus_id);
if (IS_ERR(priv->class_device)) {
ret = PTR_ERR(priv->class_device);
priv->class_device=NULL;
@@ -779,7 +779,6 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
device_unregister(dev);
return ret;
}
- dev->driver_data = priv;
priv->device = dev;
return 0;
}
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index a4a5f2efea48..0bfcbbe375c4 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -97,8 +97,8 @@ static int pure_hex(char **cp, unsigned int *val, int min_digit,
return 0;
}
-static int parse_busid(char *str, int *cssid, int *ssid, int *devno,
- int msgtrigger)
+static int parse_busid(char *str, unsigned int *cssid, unsigned int *ssid,
+ unsigned int *devno, int msgtrigger)
{
char *str_work;
int val, rc, ret;
@@ -148,7 +148,7 @@ out:
static int blacklist_parse_parameters(char *str, range_action action,
int msgtrigger)
{
- int from_cssid, to_cssid, from_ssid, to_ssid, from, to;
+ unsigned int from_cssid, to_cssid, from_ssid, to_ssid, from, to;
int rc, totalrc;
char *parm;
range_action ra;
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 82c6a2d45128..b32d7eb3d81a 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -576,12 +576,14 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
err = -ENODEV;
goto out;
}
- if (cio_is_console(sch->schid))
+ if (cio_is_console(sch->schid)) {
sch->opm = 0xff;
- else
+ sch->isc = 1;
+ } else {
sch->opm = chp_get_sch_opm(sch);
+ sch->isc = 3;
+ }
sch->lpm = sch->schib.pmcw.pam & sch->opm;
- sch->isc = 3;
CIO_MSG_EVENT(6, "Detected device %04x on subchannel 0.%x.%04X "
"- PIM = %02X, PAM = %02X, POM = %02X\n",
@@ -704,9 +706,9 @@ void wait_cons_dev(void)
if (!console_subchannel_in_use)
return;
- /* disable all but isc 7 (console device) */
+ /* disable all but isc 1 (console device) */
__ctl_store (save_cr6, 6, 6);
- cr6 = 0x01000000;
+ cr6 = 0x40000000;
__ctl_load (cr6, 6, 6);
do {
@@ -788,11 +790,11 @@ cio_probe_console(void)
}
/*
- * enable console I/O-interrupt subclass 7
+ * enable console I/O-interrupt subclass 1
*/
- ctl_set_bit(6, 24);
- console_subchannel.isc = 7;
- console_subchannel.schib.pmcw.isc = 7;
+ ctl_set_bit(6, 30);
+ console_subchannel.isc = 1;
+ console_subchannel.schib.pmcw.isc = 1;
console_subchannel.schib.pmcw.intparm =
(u32)(addr_t)&console_subchannel;
ret = cio_modify(&console_subchannel);
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
index 47a7e6200b26..5ab34340919b 100644
--- a/drivers/s390/kvm/kvm_virtio.c
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -31,11 +31,6 @@
*/
static void *kvm_devices;
-/*
- * Unique numbering for kvm devices.
- */
-static unsigned int dev_index;
-
struct kvm_device {
struct virtio_device vdev;
struct kvm_device_desc *desc;
@@ -78,27 +73,32 @@ static unsigned desc_size(const struct kvm_device_desc *desc)
+ desc->config_len;
}
-/*
- * This tests (and acknowleges) a feature bit.
- */
-static bool kvm_feature(struct virtio_device *vdev, unsigned fbit)
+/* This gets the device's feature bits. */
+static u32 kvm_get_features(struct virtio_device *vdev)
{
+ unsigned int i;
+ u32 features = 0;
struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
- u8 *features;
+ u8 *in_features = kvm_vq_features(desc);
- if (fbit / 8 > desc->feature_len)
- return false;
+ for (i = 0; i < min(desc->feature_len * 8, 32); i++)
+ if (in_features[i / 8] & (1 << (i % 8)))
+ features |= (1 << i);
+ return features;
+}
- features = kvm_vq_features(desc);
- if (!(features[fbit / 8] & (1 << (fbit % 8))))
- return false;
+static void kvm_set_features(struct virtio_device *vdev, u32 features)
+{
+ unsigned int i;
+ struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
+ /* Second half of bitmap is features we accept. */
+ u8 *out_features = kvm_vq_features(desc) + desc->feature_len;
- /*
- * We set the matching bit in the other half of the bitmap to tell the
- * Host we want to use this feature.
- */
- features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8));
- return true;
+ memset(out_features, 0, desc->feature_len);
+ for (i = 0; i < min(desc->feature_len * 8, 32); i++) {
+ if (features & (1 << i))
+ out_features[i / 8] |= (1 << (i % 8));
+ }
}
/*
@@ -221,7 +221,8 @@ static void kvm_del_vq(struct virtqueue *vq)
* The config ops structure as defined by virtio config
*/
static struct virtio_config_ops kvm_vq_configspace_ops = {
- .feature = kvm_feature,
+ .get_features = kvm_get_features,
+ .set_features = kvm_set_features,
.get = kvm_get,
.set = kvm_set,
.get_status = kvm_get_status,
@@ -244,26 +245,25 @@ static struct device kvm_root = {
* adds a new device and register it with virtio
* appropriate drivers are loaded by the device model
*/
-static void add_kvm_device(struct kvm_device_desc *d)
+static void add_kvm_device(struct kvm_device_desc *d, unsigned int offset)
{
struct kvm_device *kdev;
kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
if (!kdev) {
- printk(KERN_EMERG "Cannot allocate kvm dev %u\n",
- dev_index++);
+ printk(KERN_EMERG "Cannot allocate kvm dev %u type %u\n",
+ offset, d->type);
return;
}
kdev->vdev.dev.parent = &kvm_root;
- kdev->vdev.index = dev_index++;
kdev->vdev.id.device = d->type;
kdev->vdev.config = &kvm_vq_configspace_ops;
kdev->desc = d;
if (register_virtio_device(&kdev->vdev) != 0) {
- printk(KERN_ERR "Failed to register kvm device %u\n",
- kdev->vdev.index);
+ printk(KERN_ERR "Failed to register kvm device %u type %u\n",
+ offset, d->type);
kfree(kdev);
}
}
@@ -283,7 +283,7 @@ static void scan_devices(void)
if (d->type == 0)
break;
- add_kvm_device(d);
+ add_kvm_device(d, i);
}
}
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 436bf1f6d4a6..9a71dae223e8 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -290,9 +290,6 @@ int qeth_set_large_send(struct qeth_card *card,
card->dev->features |= NETIF_F_TSO | NETIF_F_SG |
NETIF_F_HW_CSUM;
} else {
- PRINT_WARN("TSO not supported on %s. "
- "large_send set to 'no'.\n",
- card->dev->name);
card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
NETIF_F_HW_CSUM);
card->options.large_send = QETH_LARGE_SEND_NO;
@@ -1407,12 +1404,6 @@ static void qeth_init_func_level(struct qeth_card *card)
}
}
-static inline __u16 qeth_raw_devno_from_bus_id(char *id)
-{
- id += (strlen(id) - 4);
- return (__u16) simple_strtoul(id, &id, 16);
-}
-
static int qeth_idx_activate_get_answer(struct qeth_channel *channel,
void (*idx_reply_cb)(struct qeth_channel *,
struct qeth_cmd_buffer *))
@@ -1439,7 +1430,7 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel,
spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
if (rc) {
- PRINT_ERR("Error2 in activating channel rc=%d\n", rc);
+ QETH_DBF_MESSAGE(2, "Error2 in activating channel rc=%d\n", rc);
QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
atomic_set(&channel->irq_pending, 0);
wake_up(&card->wait_q);
@@ -1468,6 +1459,7 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel,
__u16 temp;
__u8 tmp;
int rc;
+ struct ccw_dev_id temp_devid;
card = CARD_FROM_CDEV(channel->ccwdev);
@@ -1494,8 +1486,8 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel,
&card->token.issuer_rm_w, QETH_MPC_TOKEN_LENGTH);
memcpy(QETH_IDX_ACT_FUNC_LEVEL(iob->data),
&card->info.func_level, sizeof(__u16));
- temp = qeth_raw_devno_from_bus_id(CARD_DDEV_ID(card));
- memcpy(QETH_IDX_ACT_QDIO_DEV_CUA(iob->data), &temp, 2);
+ ccw_device_get_id(CARD_DDEV(card), &temp_devid);
+ memcpy(QETH_IDX_ACT_QDIO_DEV_CUA(iob->data), &temp_devid.devno, 2);
temp = (card->info.cula << 8) + card->info.unit_addr2;
memcpy(QETH_IDX_ACT_QDIO_DEV_REALADDR(iob->data), &temp, 2);
@@ -1508,7 +1500,8 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel,
spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
if (rc) {
- PRINT_ERR("Error1 in activating channel. rc=%d\n", rc);
+ QETH_DBF_MESSAGE(2, "Error1 in activating channel. rc=%d\n",
+ rc);
QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
atomic_set(&channel->irq_pending, 0);
wake_up(&card->wait_q);
@@ -1658,7 +1651,6 @@ int qeth_send_control_data(struct qeth_card *card, int len,
reply = qeth_alloc_reply(card);
if (!reply) {
- PRINT_WARN("Could not alloc qeth_reply!\n");
return -ENOMEM;
}
reply->callback = reply_cb;
@@ -2612,15 +2604,9 @@ void qeth_queue_input_buffer(struct qeth_card *card, int index)
if (newcount < count) {
/* we are in memory shortage so we switch back to
traditional skb allocation and drop packages */
- if (!atomic_read(&card->force_alloc_skb) &&
- net_ratelimit())
- PRINT_WARN("Switch to alloc skb\n");
atomic_set(&card->force_alloc_skb, 3);
count = newcount;
} else {
- if ((atomic_read(&card->force_alloc_skb) == 1) &&
- net_ratelimit())
- PRINT_WARN("Switch to sg\n");
atomic_add_unless(&card->force_alloc_skb, -1, 0);
}
@@ -3034,7 +3020,7 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr,
elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE)
+ skb->len) >> PAGE_SHIFT);
if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
- PRINT_ERR("Invalid size of IP packet "
+ QETH_DBF_MESSAGE(2, "Invalid size of IP packet "
"(Number=%d / Length=%d). Discarded.\n",
(elements_needed+elems), skb->len);
return 0;
@@ -3247,8 +3233,6 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
* free buffers) to handle eddp context */
if (qeth_eddp_check_buffers_for_context(queue, ctx)
< 0) {
- if (net_ratelimit())
- PRINT_WARN("eddp tx_dropped 1\n");
rc = -EBUSY;
goto out;
}
@@ -3260,7 +3244,6 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
tmp = qeth_eddp_fill_buffer(queue, ctx,
queue->next_buf_to_fill);
if (tmp < 0) {
- PRINT_ERR("eddp tx_dropped 2\n");
rc = -EBUSY;
goto out;
}
@@ -3602,8 +3585,6 @@ int qeth_snmp_command(struct qeth_card *card, char __user *udata)
if ((!qeth_adp_supported(card, IPA_SETADP_SET_SNMP_CONTROL)) &&
(!card->options.layer2)) {
- PRINT_WARN("SNMP Query MIBS not supported "
- "on %s!\n", QETH_CARD_IFNAME(card));
return -EOPNOTSUPP;
}
/* skip 4 bytes (data_len struct member) to get req_len */
@@ -3634,7 +3615,7 @@ int qeth_snmp_command(struct qeth_card *card, char __user *udata)
rc = qeth_send_ipa_snmp_cmd(card, iob, QETH_SETADP_BASE_LEN + req_len,
qeth_snmp_command_cb, (void *)&qinfo);
if (rc)
- PRINT_WARN("SNMP command failed on %s: (0x%x)\n",
+ QETH_DBF_MESSAGE(2, "SNMP command failed on %s: (0x%x)\n",
QETH_CARD_IFNAME(card), rc);
else {
if (copy_to_user(udata, qinfo.udata, qinfo.udata_len))
@@ -3807,8 +3788,8 @@ retry:
if (mpno)
mpno = min(mpno - 1, QETH_MAX_PORTNO);
if (card->info.portno > mpno) {
- PRINT_ERR("Device %s does not offer port number %d \n.",
- CARD_BUS_ID(card), card->info.portno);
+ QETH_DBF_MESSAGE(2, "Device %s does not offer port number %d"
+ "\n.", CARD_BUS_ID(card), card->info.portno);
rc = -ENODEV;
goto out;
}
@@ -3985,8 +3966,6 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
return skb;
no_mem:
if (net_ratelimit()) {
- PRINT_WARN("No memory for packet received on %s.\n",
- QETH_CARD_IFNAME(card));
QETH_DBF_TEXT(TRACE, 2, "noskbmem");
QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_BUS_ID(card));
}
@@ -4004,15 +3983,17 @@ static void qeth_unregister_dbf_views(void)
}
}
-void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *text, ...)
+void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *fmt, ...)
{
char dbf_txt_buf[32];
+ va_list args;
if (level > (qeth_dbf[dbf_nix].id)->level)
return;
- snprintf(dbf_txt_buf, sizeof(dbf_txt_buf), text);
+ va_start(args, fmt);
+ vsnprintf(dbf_txt_buf, sizeof(dbf_txt_buf), fmt, args);
+ va_end(args);
debug_text_event(qeth_dbf[dbf_nix].id, level, dbf_txt_buf);
-
}
EXPORT_SYMBOL_GPL(qeth_dbf_longtext);
diff --git a/drivers/s390/net/qeth_core_offl.c b/drivers/s390/net/qeth_core_offl.c
index 822df8362856..452874e89740 100644
--- a/drivers/s390/net/qeth_core_offl.c
+++ b/drivers/s390/net/qeth_core_offl.c
@@ -122,8 +122,8 @@ int qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
if (element == 0)
return -EBUSY;
else {
- PRINT_WARN("could only partially fill eddp "
- "buffer!\n");
+ QETH_DBF_MESSAGE(2, "could only partially fill"
+ "eddp buffer!\n");
goto out;
}
}
@@ -143,8 +143,6 @@ int qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
if (must_refcnt) {
must_refcnt = 0;
if (qeth_eddp_buf_ref_context(buf, ctx)) {
- PRINT_WARN("no memory to create eddp context "
- "reference\n");
goto out_check;
}
}
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c
index 08a50f057284..c26e842ad905 100644
--- a/drivers/s390/net/qeth_core_sys.c
+++ b/drivers/s390/net/qeth_core_sys.c
@@ -129,7 +129,6 @@ static ssize_t qeth_dev_portno_store(struct device *dev,
portno = simple_strtoul(buf, &tmp, 16);
if (portno > QETH_MAX_PORTNO) {
- PRINT_WARN("portno 0x%X is out of range\n", portno);
return -EINVAL;
}
@@ -223,8 +222,6 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev,
* if though we have to permit priority queueing
*/
if (card->qdio.no_out_queues == 1) {
- PRINT_WARN("Priority queueing disabled due "
- "to hardware limitations!\n");
card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT;
return -EPERM;
}
@@ -250,7 +247,6 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev,
card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
} else {
- PRINT_WARN("Unknown queueing type '%s'\n", tmp);
return -EINVAL;
}
return count;
@@ -291,9 +287,6 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev,
((cnt > QETH_IN_BUF_COUNT_MAX) ? QETH_IN_BUF_COUNT_MAX : cnt);
if (old_cnt != cnt) {
rc = qeth_realloc_buffer_pool(card, cnt);
- if (rc)
- PRINT_WARN("Error (%d) while setting "
- "buffer count.\n", rc);
}
return count;
}
@@ -355,7 +348,6 @@ static ssize_t qeth_dev_performance_stats_store(struct device *dev,
card->perf_stats.initial_rx_packets = card->stats.rx_packets;
card->perf_stats.initial_tx_packets = card->stats.tx_packets;
} else {
- PRINT_WARN("performance_stats: write 0 or 1 to this file!\n");
return -EINVAL;
}
return count;
@@ -399,7 +391,6 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
newdis = QETH_DISCIPLINE_LAYER2;
break;
default:
- PRINT_WARN("layer2: write 0 or 1 to this file!\n");
return -EINVAL;
}
@@ -463,7 +454,6 @@ static ssize_t qeth_dev_large_send_store(struct device *dev,
} else if (!strcmp(tmp, "TSO")) {
type = QETH_LARGE_SEND_TSO;
} else {
- PRINT_WARN("large_send: invalid mode %s!\n", tmp);
return -EINVAL;
}
if (card->options.large_send == type)
@@ -503,8 +493,6 @@ static ssize_t qeth_dev_blkt_store(struct qeth_card *card,
if (i <= max_value) {
*value = i;
} else {
- PRINT_WARN("blkt total time: write values between"
- " 0 and %d to this file!\n", max_value);
return -EINVAL;
}
return count;
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 86ec50ddae13..f682f7b14480 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -101,19 +101,16 @@ static struct net_device *qeth_l2_netdev_by_devno(unsigned char *read_dev_no)
{
struct qeth_card *card;
struct net_device *ndev;
- unsigned char *readno;
- __u16 temp_dev_no, card_dev_no;
- char *endp;
+ __u16 temp_dev_no;
unsigned long flags;
+ struct ccw_dev_id read_devid;
ndev = NULL;
memcpy(&temp_dev_no, read_dev_no, 2);
read_lock_irqsave(&qeth_core_card_list.rwlock, flags);
list_for_each_entry(card, &qeth_core_card_list.list, list) {
- readno = CARD_RDEV_ID(card);
- readno += (strlen(readno) - 4);
- card_dev_no = simple_strtoul(readno, &endp, 16);
- if (card_dev_no == temp_dev_no) {
+ ccw_device_get_id(CARD_RDEV(card), &read_devid);
+ if (read_devid.devno == temp_dev_no) {
ndev = card->dev;
break;
}
@@ -134,14 +131,14 @@ static int qeth_l2_send_setgroupmac_cb(struct qeth_card *card,
mac = &cmd->data.setdelmac.mac[0];
/* MAC already registered, needed in couple/uncouple case */
if (cmd->hdr.return_code == 0x2005) {
- PRINT_WARN("Group MAC %02x:%02x:%02x:%02x:%02x:%02x " \
+ QETH_DBF_MESSAGE(2, "Group MAC %02x:%02x:%02x:%02x:%02x:%02x "
"already existing on %s \n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
QETH_CARD_IFNAME(card));
cmd->hdr.return_code = 0;
}
if (cmd->hdr.return_code)
- PRINT_ERR("Could not set group MAC " \
+ QETH_DBF_MESSAGE(2, "Could not set group MAC "
"%02x:%02x:%02x:%02x:%02x:%02x on %s: %x\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
QETH_CARD_IFNAME(card), cmd->hdr.return_code);
@@ -166,7 +163,7 @@ static int qeth_l2_send_delgroupmac_cb(struct qeth_card *card,
cmd = (struct qeth_ipa_cmd *) data;
mac = &cmd->data.setdelmac.mac[0];
if (cmd->hdr.return_code)
- PRINT_ERR("Could not delete group MAC " \
+ QETH_DBF_MESSAGE(2, "Could not delete group MAC "
"%02x:%02x:%02x:%02x:%02x:%02x on %s: %x\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
QETH_CARD_IFNAME(card), cmd->hdr.return_code);
@@ -186,10 +183,8 @@ static void qeth_l2_add_mc(struct qeth_card *card, __u8 *mac)
mc = kmalloc(sizeof(struct qeth_mc_mac), GFP_ATOMIC);
- if (!mc) {
- PRINT_ERR("no mem vor mc mac address\n");
+ if (!mc)
return;
- }
memcpy(mc->mc_addr, mac, OSA_ADDR_LEN);
mc->mc_addrlen = OSA_ADDR_LEN;
@@ -280,7 +275,7 @@ static int qeth_l2_send_setdelvlan_cb(struct qeth_card *card,
QETH_DBF_TEXT(TRACE, 2, "L2sdvcb");
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code) {
- PRINT_ERR("Error in processing VLAN %i on %s: 0x%x. "
+ QETH_DBF_MESSAGE(2, "Error in processing VLAN %i on %s: 0x%x. "
"Continuing\n", cmd->data.setdelvlan.vlan_id,
QETH_CARD_IFNAME(card), cmd->hdr.return_code);
QETH_DBF_TEXT_(TRACE, 2, "L2VL%4x", cmd->hdr.command);
@@ -333,8 +328,6 @@ static void qeth_l2_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
spin_lock_bh(&card->vlanlock);
list_add_tail(&id->list, &card->vid_list);
spin_unlock_bh(&card->vlanlock);
- } else {
- PRINT_ERR("no memory for vid\n");
}
}
@@ -550,16 +543,15 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card)
rc = qeth_query_setadapterparms(card);
if (rc) {
- PRINT_WARN("could not query adapter parameters on device %s: "
- "x%x\n", CARD_BUS_ID(card), rc);
+ QETH_DBF_MESSAGE(2, "could not query adapter parameters on "
+ "device %s: x%x\n", CARD_BUS_ID(card), rc);
}
if (card->info.guestlan) {
rc = qeth_setadpparms_change_macaddr(card);
if (rc) {
- PRINT_WARN("couldn't get MAC address on "
- "device %s: x%x\n",
- CARD_BUS_ID(card), rc);
+ QETH_DBF_MESSAGE(2, "couldn't get MAC address on "
+ "device %s: x%x\n", CARD_BUS_ID(card), rc);
QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
return rc;
}
@@ -585,8 +577,6 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
}
if (card->info.type == QETH_CARD_TYPE_OSN) {
- PRINT_WARN("Setting MAC address on %s is not supported.\n",
- dev->name);
QETH_DBF_TEXT(TRACE, 3, "setmcOSN");
return -EOPNOTSUPP;
}
@@ -666,7 +656,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
ctx = qeth_eddp_create_context(card, new_skb, hdr,
skb->sk->sk_protocol);
if (ctx == NULL) {
- PRINT_WARN("could not create eddp context\n");
+ QETH_DBF_MESSAGE(2, "could not create eddp context\n");
goto tx_drop;
}
} else {
@@ -731,6 +721,7 @@ tx_drop:
if ((new_skb != skb) && new_skb)
dev_kfree_skb_any(new_skb);
dev_kfree_skb_any(skb);
+ netif_wake_queue(dev);
return NETDEV_TX_OK;
}
@@ -1155,7 +1146,7 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len,
(addr_t) iob, 0, 0);
spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);
if (rc) {
- PRINT_WARN("qeth_osn_send_control_data: "
+ QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: "
"ccw_device_start rc = %i\n", rc);
QETH_DBF_TEXT_(TRACE, 2, " err%d", rc);
qeth_release_buffer(iob->channel, iob);
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 94a8ead64ed4..999552c83bbe 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -311,7 +311,6 @@ static struct qeth_ipaddr *qeth_l3_get_addr_buffer(
addr = kzalloc(sizeof(struct qeth_ipaddr), GFP_ATOMIC);
if (addr == NULL) {
- PRINT_WARN("Not enough memory to add address\n");
return NULL;
}
addr->type = QETH_IP_TYPE_NORMAL;
@@ -649,15 +648,6 @@ static void qeth_l3_correct_routing_type(struct qeth_card *card,
}
}
out_inval:
- PRINT_WARN("Routing type '%s' not supported for interface %s.\n"
- "Router status set to 'no router'.\n",
- ((*type == PRIMARY_ROUTER)? "primary router" :
- (*type == SECONDARY_ROUTER)? "secondary router" :
- (*type == PRIMARY_CONNECTOR)? "primary connector" :
- (*type == SECONDARY_CONNECTOR)? "secondary connector" :
- (*type == MULTICAST_ROUTER)? "multicast router" :
- "unknown"),
- card->dev->name);
*type = NO_ROUTER;
}
@@ -674,9 +664,9 @@ int qeth_l3_setrouting_v4(struct qeth_card *card)
QETH_PROT_IPV4);
if (rc) {
card->options.route4.type = NO_ROUTER;
- PRINT_WARN("Error (0x%04x) while setting routing type on %s. "
- "Type set to 'no router'.\n",
- rc, QETH_CARD_IFNAME(card));
+ QETH_DBF_MESSAGE(2, "Error (0x%04x) while setting routing type"
+ " on %s. Type set to 'no router'.\n", rc,
+ QETH_CARD_IFNAME(card));
}
return rc;
}
@@ -697,9 +687,9 @@ int qeth_l3_setrouting_v6(struct qeth_card *card)
QETH_PROT_IPV6);
if (rc) {
card->options.route6.type = NO_ROUTER;
- PRINT_WARN("Error (0x%04x) while setting routing type on %s. "
- "Type set to 'no router'.\n",
- rc, QETH_CARD_IFNAME(card));
+ QETH_DBF_MESSAGE(2, "Error (0x%04x) while setting routing type"
+ " on %s. Type set to 'no router'.\n", rc,
+ QETH_CARD_IFNAME(card));
}
#endif
return rc;
@@ -737,7 +727,6 @@ int qeth_l3_add_ipato_entry(struct qeth_card *card,
if (!memcmp(ipatoe->addr, new->addr,
(ipatoe->proto == QETH_PROT_IPV4)? 4:16) &&
(ipatoe->mask_bits == new->mask_bits)) {
- PRINT_WARN("ipato entry already exists!\n");
rc = -EEXIST;
break;
}
@@ -802,7 +791,6 @@ int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
rc = -EEXIST;
spin_unlock_irqrestore(&card->ip_lock, flags);
if (rc) {
- PRINT_WARN("Cannot add VIPA. Address already exists!\n");
return rc;
}
if (!qeth_l3_add_ip(card, ipaddr))
@@ -867,7 +855,6 @@ int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
rc = -EEXIST;
spin_unlock_irqrestore(&card->ip_lock, flags);
if (rc) {
- PRINT_WARN("Cannot add RXIP. Address already exists!\n");
return rc;
}
if (!qeth_l3_add_ip(card, ipaddr))
@@ -1020,23 +1007,23 @@ static int qeth_l3_setadapter_hstr(struct qeth_card *card)
IPA_SETADP_SET_BROADCAST_MODE,
card->options.broadcast_mode);
if (rc)
- PRINT_WARN("couldn't set broadcast mode on "
+ QETH_DBF_MESSAGE(2, "couldn't set broadcast mode on "
"device %s: x%x\n",
CARD_BUS_ID(card), rc);
rc = qeth_l3_send_setadp_mode(card,
IPA_SETADP_ALTER_MAC_ADDRESS,
card->options.macaddr_mode);
if (rc)
- PRINT_WARN("couldn't set macaddr mode on "
+ QETH_DBF_MESSAGE(2, "couldn't set macaddr mode on "
"device %s: x%x\n", CARD_BUS_ID(card), rc);
return rc;
}
if (card->options.broadcast_mode == QETH_TR_BROADCAST_LOCAL)
- PRINT_WARN("set adapter parameters not available "
+ QETH_DBF_MESSAGE(2, "set adapter parameters not available "
"to set broadcast mode, using ALLRINGS "
"on device %s:\n", CARD_BUS_ID(card));
if (card->options.macaddr_mode == QETH_TR_MACADDR_CANONICAL)
- PRINT_WARN("set adapter parameters not available "
+ QETH_DBF_MESSAGE(2, "set adapter parameters not available "
"to set macaddr mode, using NONCANONICAL "
"on device %s:\n", CARD_BUS_ID(card));
return 0;
@@ -2070,7 +2057,7 @@ static struct qeth_card *qeth_l3_get_card_from_dev(struct net_device *dev)
card = netdev_priv(dev);
else if (rc == QETH_VLAN_CARD)
card = netdev_priv(vlan_dev_info(dev)->real_dev);
- if (card->options.layer2)
+ if (card && card->options.layer2)
card = NULL;
QETH_DBF_TEXT_(TRACE, 4, "%d", rc);
return card ;
@@ -2182,8 +2169,6 @@ static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries)
if (card->info.guestlan)
return -EOPNOTSUPP;
if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
- PRINT_WARN("ARP processing not supported "
- "on %s!\n", QETH_CARD_IFNAME(card));
return -EOPNOTSUPP;
}
rc = qeth_l3_send_simple_setassparms(card, IPA_ARP_PROCESSING,
@@ -2191,8 +2176,8 @@ static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries)
no_entries);
if (rc) {
tmp = rc;
- PRINT_WARN("Could not set number of ARP entries on %s: "
- "%s (0x%x/%d)\n", QETH_CARD_IFNAME(card),
+ QETH_DBF_MESSAGE(2, "Could not set number of ARP entries on "
+ "%s: %s (0x%x/%d)\n", QETH_CARD_IFNAME(card),
qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
}
return rc;
@@ -2260,9 +2245,6 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
qdata->no_entries * uentry_size){
QETH_DBF_TEXT_(TRACE, 4, "qaer3%i", -ENOMEM);
cmd->hdr.return_code = -ENOMEM;
- PRINT_WARN("query ARP user space buffer is too small for "
- "the returned number of ARP entries. "
- "Aborting query!\n");
goto out_error;
}
QETH_DBF_TEXT_(TRACE, 4, "anore%i",
@@ -2324,8 +2306,6 @@ static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata)
if (!qeth_is_supported(card,/*IPA_QUERY_ARP_ADDR_INFO*/
IPA_ARP_PROCESSING)) {
- PRINT_WARN("ARP processing not supported "
- "on %s!\n", QETH_CARD_IFNAME(card));
return -EOPNOTSUPP;
}
/* get size of userspace buffer and mask_bits -> 6 bytes */
@@ -2344,7 +2324,7 @@ static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata)
qeth_l3_arp_query_cb, (void *)&qinfo);
if (rc) {
tmp = rc;
- PRINT_WARN("Error while querying ARP cache on %s: %s "
+ QETH_DBF_MESSAGE(2, "Error while querying ARP cache on %s: %s "
"(0x%x/%d)\n", QETH_CARD_IFNAME(card),
qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
if (copy_to_user(udata, qinfo.udata, 4))
@@ -2375,8 +2355,6 @@ static int qeth_l3_arp_add_entry(struct qeth_card *card,
if (card->info.guestlan)
return -EOPNOTSUPP;
if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
- PRINT_WARN("ARP processing not supported "
- "on %s!\n", QETH_CARD_IFNAME(card));
return -EOPNOTSUPP;
}
@@ -2391,10 +2369,9 @@ static int qeth_l3_arp_add_entry(struct qeth_card *card,
if (rc) {
tmp = rc;
qeth_l3_ipaddr4_to_string((u8 *)entry->ipaddr, buf);
- PRINT_WARN("Could not add ARP entry for address %s on %s: "
- "%s (0x%x/%d)\n",
- buf, QETH_CARD_IFNAME(card),
- qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
+ QETH_DBF_MESSAGE(2, "Could not add ARP entry for address %s "
+ "on %s: %s (0x%x/%d)\n", buf, QETH_CARD_IFNAME(card),
+ qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
}
return rc;
}
@@ -2417,8 +2394,6 @@ static int qeth_l3_arp_remove_entry(struct qeth_card *card,
if (card->info.guestlan)
return -EOPNOTSUPP;
if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
- PRINT_WARN("ARP processing not supported "
- "on %s!\n", QETH_CARD_IFNAME(card));
return -EOPNOTSUPP;
}
memcpy(buf, entry, 12);
@@ -2433,10 +2408,9 @@ static int qeth_l3_arp_remove_entry(struct qeth_card *card,
tmp = rc;
memset(buf, 0, 16);
qeth_l3_ipaddr4_to_string((u8 *)entry->ipaddr, buf);
- PRINT_WARN("Could not delete ARP entry for address %s on %s: "
- "%s (0x%x/%d)\n",
- buf, QETH_CARD_IFNAME(card),
- qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
+ QETH_DBF_MESSAGE(2, "Could not delete ARP entry for address %s"
+ " on %s: %s (0x%x/%d)\n", buf, QETH_CARD_IFNAME(card),
+ qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
}
return rc;
}
@@ -2456,16 +2430,14 @@ static int qeth_l3_arp_flush_cache(struct qeth_card *card)
if (card->info.guestlan || (card->info.type == QETH_CARD_TYPE_IQD))
return -EOPNOTSUPP;
if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
- PRINT_WARN("ARP processing not supported "
- "on %s!\n", QETH_CARD_IFNAME(card));
return -EOPNOTSUPP;
}
rc = qeth_l3_send_simple_setassparms(card, IPA_ARP_PROCESSING,
IPA_CMD_ASS_ARP_FLUSH_CACHE, 0);
if (rc) {
tmp = rc;
- PRINT_WARN("Could not flush ARP cache on %s: %s (0x%x/%d)\n",
- QETH_CARD_IFNAME(card),
+ QETH_DBF_MESSAGE(2, "Could not flush ARP cache on %s: %s "
+ "(0x%x/%d)\n", QETH_CARD_IFNAME(card),
qeth_l3_arp_get_error_cause(&rc), tmp, tmp);
}
return rc;
@@ -2724,7 +2696,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
ctx = qeth_eddp_create_context(card, new_skb, hdr,
skb->sk->sk_protocol);
if (ctx == NULL) {
- PRINT_WARN("could not create eddp context\n");
+ QETH_DBF_MESSAGE(2, "could not create eddp context\n");
goto tx_drop;
}
} else {
@@ -2792,6 +2764,7 @@ tx_drop:
if ((new_skb != skb) && new_skb)
dev_kfree_skb_any(new_skb);
dev_kfree_skb_any(skb);
+ netif_wake_queue(dev);
return NETDEV_TX_OK;
}
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c
index 08f51fd902c4..ac1993708ae9 100644
--- a/drivers/s390/net/qeth_l3_sys.c
+++ b/drivers/s390/net/qeth_l3_sys.c
@@ -85,7 +85,6 @@ static ssize_t qeth_l3_dev_route_store(struct qeth_card *card,
} else if (!strcmp(tmp, "multicast_router")) {
route->type = MULTICAST_ROUTER;
} else {
- PRINT_WARN("Invalid routing type '%s'.\n", tmp);
return -EINVAL;
}
if (((card->state == CARD_STATE_SOFTSETUP) ||
@@ -137,9 +136,6 @@ static ssize_t qeth_l3_dev_route6_store(struct device *dev,
return -EINVAL;
if (!qeth_is_supported(card, IPA_IPV6)) {
- PRINT_WARN("IPv6 not supported for interface %s.\n"
- "Routing status no changed.\n",
- QETH_CARD_IFNAME(card));
return -ENOTSUPP;
}
@@ -179,7 +175,6 @@ static ssize_t qeth_l3_dev_fake_broadcast_store(struct device *dev,
if ((i == 0) || (i == 1))
card->options.fake_broadcast = i;
else {
- PRINT_WARN("fake_broadcast: write 0 or 1 to this file!\n");
return -EINVAL;
}
return count;
@@ -220,7 +215,6 @@ static ssize_t qeth_l3_dev_broadcast_mode_store(struct device *dev,
if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
(card->info.link_type == QETH_LINK_TYPE_LANE_TR))) {
- PRINT_WARN("Device is not a tokenring device!\n");
return -EINVAL;
}
@@ -233,8 +227,6 @@ static ssize_t qeth_l3_dev_broadcast_mode_store(struct device *dev,
card->options.broadcast_mode = QETH_TR_BROADCAST_ALLRINGS;
return count;
} else {
- PRINT_WARN("broadcast_mode: invalid mode %s!\n",
- tmp);
return -EINVAL;
}
return count;
@@ -275,7 +267,6 @@ static ssize_t qeth_l3_dev_canonical_macaddr_store(struct device *dev,
if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
(card->info.link_type == QETH_LINK_TYPE_LANE_TR))) {
- PRINT_WARN("Device is not a tokenring device!\n");
return -EINVAL;
}
@@ -285,7 +276,6 @@ static ssize_t qeth_l3_dev_canonical_macaddr_store(struct device *dev,
QETH_TR_MACADDR_CANONICAL :
QETH_TR_MACADDR_NONCANONICAL;
else {
- PRINT_WARN("canonical_macaddr: write 0 or 1 to this file!\n");
return -EINVAL;
}
return count;
@@ -327,7 +317,6 @@ static ssize_t qeth_l3_dev_checksum_store(struct device *dev,
else if (!strcmp(tmp, "no_checksumming"))
card->options.checksum_type = NO_CHECKSUMMING;
else {
- PRINT_WARN("Unknown checksumming type '%s'\n", tmp);
return -EINVAL;
}
return count;
@@ -382,8 +371,6 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
} else if (!strcmp(tmp, "0")) {
card->ipato.enabled = 0;
} else {
- PRINT_WARN("ipato_enable: write 0, 1 or 'toggle' to "
- "this file\n");
return -EINVAL;
}
return count;
@@ -422,8 +409,6 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev,
} else if (!strcmp(tmp, "0")) {
card->ipato.invert4 = 0;
} else {
- PRINT_WARN("ipato_invert4: write 0, 1 or 'toggle' to "
- "this file\n");
return -EINVAL;
}
return count;
@@ -486,13 +471,10 @@ static int qeth_l3_parse_ipatoe(const char *buf, enum qeth_prot_versions proto,
/* get address string */
end = strchr(start, '/');
if (!end || (end - start >= 40)) {
- PRINT_WARN("Invalid format for ipato_addx/delx. "
- "Use <ip addr>/<mask bits>\n");
return -EINVAL;
}
strncpy(buffer, start, end - start);
if (qeth_l3_string_to_ipaddr(buffer, proto, addr)) {
- PRINT_WARN("Invalid IP address format!\n");
return -EINVAL;
}
start = end + 1;
@@ -500,7 +482,6 @@ static int qeth_l3_parse_ipatoe(const char *buf, enum qeth_prot_versions proto,
if (!strlen(start) ||
(tmp == start) ||
(*mask_bits > ((proto == QETH_PROT_IPV4) ? 32 : 128))) {
- PRINT_WARN("Invalid mask bits for ipato_addx/delx !\n");
return -EINVAL;
}
return 0;
@@ -520,7 +501,6 @@ static ssize_t qeth_l3_dev_ipato_add_store(const char *buf, size_t count,
ipatoe = kzalloc(sizeof(struct qeth_ipato_entry), GFP_KERNEL);
if (!ipatoe) {
- PRINT_WARN("No memory to allocate ipato entry\n");
return -ENOMEM;
}
ipatoe->proto = proto;
@@ -609,8 +589,6 @@ static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev,
} else if (!strcmp(tmp, "0")) {
card->ipato.invert6 = 0;
} else {
- PRINT_WARN("ipato_invert6: write 0, 1 or 'toggle' to "
- "this file\n");
return -EINVAL;
}
return count;
@@ -724,7 +702,6 @@ static int qeth_l3_parse_vipae(const char *buf, enum qeth_prot_versions proto,
u8 *addr)
{
if (qeth_l3_string_to_ipaddr(buf, proto, addr)) {
- PRINT_WARN("Invalid IP address format!\n");
return -EINVAL;
}
return 0;
@@ -891,7 +868,6 @@ static int qeth_l3_parse_rxipe(const char *buf, enum qeth_prot_versions proto,
u8 *addr)
{
if (qeth_l3_string_to_ipaddr(buf, proto, addr)) {
- PRINT_WARN("Invalid IP address format!\n");
return -EINVAL;
}
return 0;
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index 5080f343ad74..5bfbe7659830 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -207,6 +207,7 @@ s390_handle_mcck(void)
do_exit(SIGSEGV);
}
}
+EXPORT_SYMBOL_GPL(s390_handle_mcck);
/*
* returns 0 if all registers could be validated
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
index c1c091a00575..bba21e053a1b 100644
--- a/drivers/sbus/char/bpp.c
+++ b/drivers/sbus/char/bpp.c
@@ -872,7 +872,7 @@ static void probeLptPort(unsigned idx)
instances[idx].mode = COMPATIBILITY;
instances[idx].run_length = 0;
instances[idx].run_flag = 0;
- if (!request_region(lpAddr,3, dev_name)) return;
+ if (!request_region(lpAddr,3, bpp_dev_name)) return;
/*
* First, make sure the instance exists. Do this by writing to
@@ -1024,7 +1024,7 @@ static int __init bpp_init(void)
if (rc == 0)
return -ENODEV;
- rc = register_chrdev(BPP_MAJOR, dev_name, &bpp_fops);
+ rc = register_chrdev(BPP_MAJOR, bpp_dev_name, &bpp_fops);
if (rc < 0)
return rc;
@@ -1040,7 +1040,7 @@ static void __exit bpp_cleanup(void)
{
unsigned idx;
- unregister_chrdev(BPP_MAJOR, dev_name);
+ unregister_chrdev(BPP_MAJOR, bpp_dev_name);
for (idx = 0; idx < BPP_NO; idx++) {
if (instances[idx].present)
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index eaa805df5b00..7045511f9ad2 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -1281,7 +1281,7 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance)
error = 0;
/* Check for command packet errors */
if (full_command_packet->command.newcommand.status != 0) {
- if (tw_dev->srb[request_id] != 0) {
+ if (tw_dev->srb[request_id] != NULL) {
error = twa_fill_sense(tw_dev, request_id, 1, 1);
} else {
/* Skip ioctl error prints */
@@ -1293,7 +1293,7 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance)
/* Check for correct state */
if (tw_dev->state[request_id] != TW_S_POSTED) {
- if (tw_dev->srb[request_id] != 0) {
+ if (tw_dev->srb[request_id] != NULL) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted");
TW_CLEAR_ALL_INTERRUPTS(tw_dev);
goto twa_interrupt_bail;
@@ -1301,7 +1301,7 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance)
}
/* Check for internal command completion */
- if (tw_dev->srb[request_id] == 0) {
+ if (tw_dev->srb[request_id] == NULL) {
if (request_id != tw_dev->chrdev_request_id) {
if (twa_aen_complete(tw_dev, request_id))
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt");
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 1dca1775f4b1..0899cb61e3dd 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -3582,7 +3582,7 @@ static int checksetup(struct aha152x_setup *setup)
if (i == ARRAY_SIZE(ports))
return 0;
- if ( request_region(setup->io_port, IO_RANGE, "aha152x")==0 ) {
+ if (!request_region(setup->io_port, IO_RANGE, "aha152x")) {
printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup->io_port);
return 0;
}
@@ -3842,7 +3842,7 @@ static int __init aha152x_init(void)
if ((setup_count == 1) && (setup[0].io_port == ports[i]))
continue;
- if ( request_region(ports[i], IO_RANGE, "aha152x")==0 ) {
+ if (!request_region(ports[i], IO_RANGE, "aha152x")) {
printk(KERN_ERR "aha152x: io port 0x%x busy.\n", ports[i]);
continue;
}
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index db6de5e6afb3..7d311541c76c 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -747,7 +747,7 @@ static void send_s870(struct atp_unit *dev,unsigned char c)
dev->quhd[c] = 0;
}
workreq = dev->quereq[c][dev->quhd[c]];
- if (dev->id[c][scmd_id(workreq)].curr_req == 0) {
+ if (dev->id[c][scmd_id(workreq)].curr_req == NULL) {
dev->id[c][scmd_id(workreq)].curr_req = workreq;
dev->last_cmd[c] = scmd_id(workreq);
goto cmd_subp;
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index 8e821be380f4..aa2011b64683 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -914,9 +914,9 @@ static int ch_probe(struct device *dev)
ch->minor = minor;
sprintf(ch->name,"ch%d",ch->minor);
- class_dev = device_create(ch_sysfs_class, dev,
- MKDEV(SCSI_CHANGER_MAJOR,ch->minor),
- "s%s", ch->name);
+ class_dev = device_create_drvdata(ch_sysfs_class, dev,
+ MKDEV(SCSI_CHANGER_MAJOR, ch->minor),
+ ch, "s%s", ch->name);
if (IS_ERR(class_dev)) {
printk(KERN_WARNING "ch%d: device_create failed\n",
ch->minor);
@@ -930,7 +930,6 @@ static int ch_probe(struct device *dev)
if (init)
ch_init_elem(ch);
- dev_set_drvdata(dev, ch);
sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
return 0;
diff --git a/drivers/scsi/dpt/dptsig.h b/drivers/scsi/dpt/dptsig.h
index 72c8992fdf21..a6644b332b53 100644
--- a/drivers/scsi/dpt/dptsig.h
+++ b/drivers/scsi/dpt/dptsig.h
@@ -85,7 +85,7 @@ typedef unsigned int sigINT;
/* ------------------------------------------------------------------ */
/* What type of processor the file is meant to run on. */
/* This will let us know whether to read sigWORDs as high/low or low/high. */
-#define PROC_INTEL 0x00 /* Intel 80x86 */
+#define PROC_INTEL 0x00 /* Intel 80x86/ia64 */
#define PROC_MOTOROLA 0x01 /* Motorola 68K */
#define PROC_MIPS4000 0x02 /* MIPS RISC 4000 */
#define PROC_ALPHA 0x03 /* DEC Alpha */
@@ -104,6 +104,7 @@ typedef unsigned int sigINT;
#define PROC_486 0x08 /* Intel 80486 */
#define PROC_PENTIUM 0x10 /* Intel 586 aka P5 aka Pentium */
#define PROC_SEXIUM 0x20 /* Intel 686 aka P6 aka Pentium Pro or MMX */
+#define PROC_IA64 0x40 /* Intel IA64 processor */
/* PROC_i960: */
#define PROC_960RX 0x01 /* Intel 80960RC/RD */
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index a0b6d414953d..59fbef08d690 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -2359,6 +2359,24 @@ void scsi_esp_unregister(struct esp *esp)
}
EXPORT_SYMBOL(scsi_esp_unregister);
+static int esp_target_alloc(struct scsi_target *starget)
+{
+ struct esp *esp = shost_priv(dev_to_shost(&starget->dev));
+ struct esp_target_data *tp = &esp->target[starget->id];
+
+ tp->starget = starget;
+
+ return 0;
+}
+
+static void esp_target_destroy(struct scsi_target *starget)
+{
+ struct esp *esp = shost_priv(dev_to_shost(&starget->dev));
+ struct esp_target_data *tp = &esp->target[starget->id];
+
+ tp->starget = NULL;
+}
+
static int esp_slave_alloc(struct scsi_device *dev)
{
struct esp *esp = shost_priv(dev->host);
@@ -2370,8 +2388,6 @@ static int esp_slave_alloc(struct scsi_device *dev)
return -ENOMEM;
dev->hostdata = lp;
- tp->starget = dev->sdev_target;
-
spi_min_period(tp->starget) = esp->min_period;
spi_max_offset(tp->starget) = 15;
@@ -2608,6 +2624,8 @@ struct scsi_host_template scsi_esp_template = {
.name = "esp",
.info = esp_info,
.queuecommand = esp_queuecommand,
+ .target_alloc = esp_target_alloc,
+ .target_destroy = esp_target_destroy,
.slave_alloc = esp_slave_alloc,
.slave_configure = esp_slave_configure,
.slave_destroy = esp_slave_destroy,
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 3690360d7a79..c6457bfc8a49 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -456,6 +456,10 @@ static int __scsi_host_match(struct device *dev, void *data)
*
* Return value:
* A pointer to located Scsi_Host or NULL.
+ *
+ * The caller must do a scsi_host_put() to drop the reference
+ * that scsi_host_get() took. The put_device() below dropped
+ * the reference from class_find_device().
**/
struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
{
@@ -463,9 +467,10 @@ struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
struct Scsi_Host *shost = ERR_PTR(-ENXIO);
cdev = class_find_device(&shost_class, &hostnum, __scsi_host_match);
- if (cdev)
+ if (cdev) {
shost = scsi_host_get(class_to_shost(cdev));
-
+ put_device(cdev);
+ }
return shost;
}
EXPORT_SYMBOL(scsi_host_lookup);
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index aaa48e0c8ed0..da876d3924be 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -444,7 +444,7 @@ static void __iomem *hptiop_map_pci_bar(struct hptiop_hba *hba, int index)
if (!(pci_resource_flags(pcidev, index) & IORESOURCE_MEM)) {
printk(KERN_ERR "scsi%d: pci resource invalid\n",
hba->host->host_no);
- return 0;
+ return NULL;
}
mem_base_phy = pci_resource_start(pcidev, index);
@@ -454,7 +454,7 @@ static void __iomem *hptiop_map_pci_bar(struct hptiop_hba *hba, int index)
if (!mem_base_virt) {
printk(KERN_ERR "scsi%d: Fail to ioremap memory space\n",
hba->host->host_no);
- return 0;
+ return NULL;
}
return mem_base_virt;
}
@@ -476,11 +476,11 @@ static void hptiop_unmap_pci_bar_itl(struct hptiop_hba *hba)
static int hptiop_map_pci_bar_mv(struct hptiop_hba *hba)
{
hba->u.mv.regs = hptiop_map_pci_bar(hba, 0);
- if (hba->u.mv.regs == 0)
+ if (hba->u.mv.regs == NULL)
return -1;
hba->u.mv.mu = hptiop_map_pci_bar(hba, 2);
- if (hba->u.mv.mu == 0) {
+ if (hba->u.mv.mu == NULL) {
iounmap(hba->u.mv.regs);
return -1;
}
@@ -1210,8 +1210,8 @@ static void hptiop_remove(struct pci_dev *pcidev)
static struct hptiop_adapter_ops hptiop_itl_ops = {
.iop_wait_ready = iop_wait_ready_itl,
- .internal_memalloc = 0,
- .internal_memfree = 0,
+ .internal_memalloc = NULL,
+ .internal_memfree = NULL,
.map_pci_bar = hptiop_map_pci_bar_itl,
.unmap_pci_bar = hptiop_unmap_pci_bar_itl,
.enable_intr = hptiop_enable_intr_itl,
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index ccfd8aca3765..5d23368a1bce 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -1348,7 +1348,7 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
del_timer(&evt_struct->timer);
- if (crq->status != VIOSRP_OK && evt_struct->cmnd)
+ if ((crq->status != VIOSRP_OK && crq->status != VIOSRP_OK2) && evt_struct->cmnd)
evt_struct->cmnd->result = DID_ERROR << 16;
if (evt_struct->done)
evt_struct->done(evt_struct);
diff --git a/drivers/scsi/ibmvscsi/viosrp.h b/drivers/scsi/ibmvscsi/viosrp.h
index 4c4aadb3e405..204604501ad8 100644
--- a/drivers/scsi/ibmvscsi/viosrp.h
+++ b/drivers/scsi/ibmvscsi/viosrp.h
@@ -65,7 +65,8 @@ enum viosrp_crq_status {
VIOSRP_VIOLATES_MAX_XFER = 0x2,
VIOSRP_PARTNER_PANIC = 0x3,
VIOSRP_DEVICE_BUSY = 0x8,
- VIOSRP_ADAPTER_FAIL = 0x10
+ VIOSRP_ADAPTER_FAIL = 0x10,
+ VIOSRP_OK2 = 0x99,
};
struct viosrp_crq {
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 999e91ea7451..e7a3a6554425 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -71,6 +71,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/libata.h>
+#include <linux/hdreg.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/processor.h>
@@ -4913,8 +4914,11 @@ static int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
struct ipr_resource_entry *res;
res = (struct ipr_resource_entry *)sdev->hostdata;
- if (res && ipr_is_gata(res))
+ if (res && ipr_is_gata(res)) {
+ if (cmd == HDIO_GET_IDENTITY)
+ return -ENOTTY;
return ata_scsi_ioctl(sdev, cmd, arg);
+ }
return -EINVAL;
}
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index cd37bd69a115..887682a24e36 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -650,7 +650,7 @@ static void __exit mac_esp_exit(void)
MODULE_DESCRIPTION("Mac ESP SCSI driver");
MODULE_AUTHOR("Finn Thain <fthain@telegraphics.com.au>");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
MODULE_VERSION(DRV_VERSION);
module_init(mac_esp_init);
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index 24ad89a649ce..1c79f9794f4e 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -5708,13 +5708,12 @@ static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * S
struct device *osst_member;
int err;
- osst_member = device_create(osst_sysfs_class, device, dev, "%s", name);
+ osst_member = device_create_drvdata(osst_sysfs_class, device, dev, STp, "%s", name);
if (IS_ERR(osst_member)) {
printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name);
return PTR_ERR(osst_member);
}
- dev_set_drvdata(osst_member, STp);
err = device_create_file(osst_member, &dev_attr_ADR_rev);
if (err)
goto err_out;
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 51e2f299dbbb..3754ab87f89a 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -2811,7 +2811,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
/* Check for room in outstanding command list. */
for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS &&
- ha->outstanding_cmds[cnt] != 0; cnt++);
+ ha->outstanding_cmds[cnt] != NULL; cnt++);
if (cnt >= MAX_OUTSTANDING_COMMANDS) {
status = 1;
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 287690853caf..8dd88fc1244a 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -70,6 +70,9 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj,
case 2:
qla2x00_alloc_fw_dump(ha);
break;
+ case 3:
+ qla2x00_system_error(ha);
+ break;
}
return (count);
}
@@ -886,9 +889,13 @@ qla2x00_get_host_speed(struct Scsi_Host *shost)
static void
qla2x00_get_host_port_type(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost));
+ scsi_qla_host_t *ha = shost_priv(shost);
uint32_t port_type = FC_PORTTYPE_UNKNOWN;
+ if (ha->parent) {
+ fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
+ return;
+ }
switch (ha->current_topology) {
case ISP_CFG_NL:
port_type = FC_PORTTYPE_LPORT;
@@ -1172,10 +1179,10 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
qla24xx_disable_vp(vha);
qla24xx_deallocate_vp_id(vha);
- down(&ha->vport_sem);
+ mutex_lock(&ha->vport_lock);
ha->cur_vport_count--;
clear_bit(vha->vp_idx, ha->vp_idx_map);
- up(&ha->vport_sem);
+ mutex_unlock(&ha->vport_lock);
kfree(vha->node_name);
kfree(vha->port_name);
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 299eccf6cabd..8dd600013bd1 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2457,7 +2457,7 @@ typedef struct scsi_qla_host {
#define MBX_INTR_WAIT 2
#define MBX_UPDATE_FLASH_ACTIVE 3
- struct semaphore vport_sem; /* Virtual port synchronization */
+ struct mutex vport_lock; /* Virtual port synchronization */
struct completion mbx_cmd_comp; /* Serialize mbx access */
struct completion mbx_intr_comp; /* Used for completion notification */
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index f8827068d30f..9b4bebee6879 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -228,6 +228,9 @@ extern int qla24xx_abort_target(struct fc_port *, unsigned int);
extern int qla24xx_lun_reset(struct fc_port *, unsigned int);
extern int
+qla2x00_system_error(scsi_qla_host_t *);
+
+extern int
qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t);
extern int
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index e9bae27737d1..92fafbdbbaab 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -34,7 +34,11 @@ qla2x00_debounce_register(volatile uint16_t __iomem *addr)
static inline void
qla2x00_poll(scsi_qla_host_t *ha)
{
+ unsigned long flags;
+
+ local_irq_save(flags);
ha->isp_ops->intr_handler(0, ha);
+ local_irq_restore(flags);
}
static __inline__ scsi_qla_host_t *
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 5d9a64a7879b..ec63b79f900a 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -272,8 +272,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
uint32_t rscn_entry, host_pid;
uint8_t rscn_queue_index;
unsigned long flags;
- scsi_qla_host_t *vha;
- int i;
/* Setup to process RIO completion. */
handle_cnt = 0;
@@ -544,18 +542,10 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
break;
case MBA_PORT_UPDATE: /* Port database update */
- if ((ha->flags.npiv_supported) && (ha->num_vhosts)) {
- for_each_mapped_vp_idx(ha, i) {
- list_for_each_entry(vha, &ha->vp_list,
- vp_list) {
- if ((mb[3] & 0xff)
- == vha->vp_idx) {
- ha = vha;
- break;
- }
- }
- }
- }
+ /* Only handle SCNs for our Vport index. */
+ if (ha->parent && ha->vp_idx != (mb[3] & 0xff))
+ break;
+
/*
* If PORT UPDATE is global (recieved LIP_OCCURED/LIP_RESET
* event etc. earlier indicating loop is down) then process
@@ -590,18 +580,12 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
break;
case MBA_RSCN_UPDATE: /* State Change Registration */
- if ((ha->flags.npiv_supported) && (ha->num_vhosts)) {
- for_each_mapped_vp_idx(ha, i) {
- list_for_each_entry(vha, &ha->vp_list,
- vp_list) {
- if ((mb[3] & 0xff)
- == vha->vp_idx) {
- ha = vha;
- break;
- }
- }
- }
- }
+ /* Check if the Vport has issued a SCR */
+ if (ha->parent && test_bit(VP_SCR_NEEDED, &ha->vp_flags))
+ break;
+ /* Only handle SCNs for our Vport index. */
+ if (ha->parent && ha->vp_idx != (mb[3] & 0xff))
+ break;
DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
ha->host_no));
@@ -1132,25 +1116,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
break;
qla2x00_handle_sense(sp, sense_data, sense_len);
-
- /*
- * In case of a Underrun condition, set both the lscsi
- * status and the completion status to appropriate
- * values.
- */
- if (resid &&
- ((unsigned)(scsi_bufflen(cp) - resid) <
- cp->underflow)) {
- DEBUG2(qla_printk(KERN_INFO, ha,
- "scsi(%ld:%d:%d:%d): Mid-layer underflow "
- "detected (%x of %x bytes)...returning "
- "error status.\n", ha->host_no,
- cp->device->channel, cp->device->id,
- cp->device->lun, resid,
- scsi_bufflen(cp)));
-
- cp->result = DID_ERROR << 16 | lscsi_status;
- }
} else {
/*
* If RISC reports underrun and target does not report
@@ -1639,12 +1604,12 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
ha = dev_id;
reg = &ha->iobase->isp24;
- spin_lock(&ha->hardware_lock);
+ spin_lock_irq(&ha->hardware_lock);
qla24xx_process_response_queue(ha);
WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
- spin_unlock(&ha->hardware_lock);
+ spin_unlock_irq(&ha->hardware_lock);
return IRQ_HANDLED;
}
@@ -1663,7 +1628,7 @@ qla24xx_msix_default(int irq, void *dev_id)
reg = &ha->iobase->isp24;
status = 0;
- spin_lock(&ha->hardware_lock);
+ spin_lock_irq(&ha->hardware_lock);
do {
stat = RD_REG_DWORD(&reg->host_status);
if (stat & HSRX_RISC_PAUSED) {
@@ -1716,7 +1681,7 @@ qla24xx_msix_default(int irq, void *dev_id)
}
WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
} while (0);
- spin_unlock(&ha->hardware_lock);
+ spin_unlock_irq(&ha->hardware_lock);
if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
(status & MBX_INTERRUPT) && ha->flags.mbox_int) {
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 210060420809..250d2f604397 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -2303,8 +2303,6 @@ qla24xx_lun_reset(struct fc_port *fcport, unsigned int l)
return __qla24xx_issue_tmf("Lun", TCF_LUN_RESET, fcport, l);
}
-#if 0
-
int
qla2x00_system_error(scsi_qla_host_t *ha)
{
@@ -2312,7 +2310,7 @@ qla2x00_system_error(scsi_qla_host_t *ha)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_FWI2_CAPABLE(ha))
+ if (!IS_QLA23XX(ha) && !IS_FWI2_CAPABLE(ha))
return QLA_FUNCTION_FAILED;
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
@@ -2334,8 +2332,6 @@ qla2x00_system_error(scsi_qla_host_t *ha)
return rval;
}
-#endif /* 0 */
-
/**
* qla2x00_set_serdes_params() -
* @ha: HA context
@@ -2508,7 +2504,7 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *ha, dma_addr_t fce_dma,
if (mb)
memcpy(mb, mcp->mb, 8 * sizeof(*mb));
if (dwords)
- *dwords = mcp->mb[6];
+ *dwords = buffers;
}
return rval;
@@ -2807,9 +2803,9 @@ qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
*/
map = (vp_index - 1) / 8;
pos = (vp_index - 1) & 7;
- down(&ha->vport_sem);
+ mutex_lock(&ha->vport_lock);
vce->vp_idx_map[map] |= 1 << pos;
- up(&ha->vport_sem);
+ mutex_unlock(&ha->vport_lock);
rval = qla2x00_issue_iocb(ha, vce, vce_dma, 0);
if (rval != QLA_SUCCESS) {
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index f2b04979e5f0..62a3ad6e8ecb 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -32,12 +32,12 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
scsi_qla_host_t *ha = vha->parent;
/* Find an empty slot and assign an vp_id */
- down(&ha->vport_sem);
+ mutex_lock(&ha->vport_lock);
vp_id = find_first_zero_bit(ha->vp_idx_map, ha->max_npiv_vports + 1);
if (vp_id > ha->max_npiv_vports) {
DEBUG15(printk ("vp_id %d is bigger than max-supported %d.\n",
vp_id, ha->max_npiv_vports));
- up(&ha->vport_sem);
+ mutex_unlock(&ha->vport_lock);
return vp_id;
}
@@ -45,7 +45,7 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
ha->num_vhosts++;
vha->vp_idx = vp_id;
list_add_tail(&vha->vp_list, &ha->vp_list);
- up(&ha->vport_sem);
+ mutex_unlock(&ha->vport_lock);
return vp_id;
}
@@ -55,12 +55,12 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
uint16_t vp_id;
scsi_qla_host_t *ha = vha->parent;
- down(&ha->vport_sem);
+ mutex_lock(&ha->vport_lock);
vp_id = vha->vp_idx;
ha->num_vhosts--;
clear_bit(vp_id, ha->vp_idx_map);
list_del(&vha->vp_list);
- up(&ha->vport_sem);
+ mutex_unlock(&ha->vport_lock);
}
static scsi_qla_host_t *
@@ -145,9 +145,9 @@ qla24xx_enable_vp(scsi_qla_host_t *vha)
}
/* Initialize the new vport unless it is a persistent port */
- down(&ha->vport_sem);
+ mutex_lock(&ha->vport_lock);
ret = qla24xx_modify_vp_config(vha);
- up(&ha->vport_sem);
+ mutex_unlock(&ha->vport_lock);
if (ret != QLA_SUCCESS) {
fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
@@ -406,6 +406,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
INIT_LIST_HEAD(&vha->list);
INIT_LIST_HEAD(&vha->fcports);
INIT_LIST_HEAD(&vha->vp_fcports);
+ INIT_LIST_HEAD(&vha->work_list);
vha->dpc_flags = 0L;
set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
@@ -437,10 +438,10 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
vha->flags.init_done = 1;
num_hosts++;
- down(&ha->vport_sem);
+ mutex_lock(&ha->vport_lock);
set_bit(vha->vp_idx, ha->vp_idx_map);
ha->cur_vport_count++;
- up(&ha->vport_sem);
+ mutex_unlock(&ha->vport_lock);
return vha;
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 3223fd16bcfe..48eaa3bb5433 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -10,6 +10,7 @@
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/kthread.h>
+#include <linux/mutex.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsicam.h>
@@ -1631,7 +1632,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
/* load the F/W, read paramaters, and init the H/W */
ha->instance = num_hosts;
- init_MUTEX(&ha->vport_sem);
+ mutex_init(&ha->vport_lock);
init_completion(&ha->mbx_cmd_comp);
complete(&ha->mbx_cmd_comp);
init_completion(&ha->mbx_intr_comp);
@@ -2156,13 +2157,14 @@ static int
qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked)
{
unsigned long flags;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
if (!locked)
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&pha->hardware_lock, flags);
list_add_tail(&e->list, &ha->work_list);
qla2xxx_wake_dpc(ha);
if (!locked)
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&pha->hardware_lock, flags);
return QLA_SUCCESS;
}
@@ -2202,12 +2204,13 @@ static void
qla2x00_do_work(struct scsi_qla_host *ha)
{
struct qla_work_evt *e;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
- spin_lock_irq(&ha->hardware_lock);
+ spin_lock_irq(&pha->hardware_lock);
while (!list_empty(&ha->work_list)) {
e = list_entry(ha->work_list.next, struct qla_work_evt, list);
list_del_init(&e->list);
- spin_unlock_irq(&ha->hardware_lock);
+ spin_unlock_irq(&pha->hardware_lock);
switch (e->type) {
case QLA_EVT_AEN:
@@ -2221,9 +2224,9 @@ qla2x00_do_work(struct scsi_qla_host *ha)
}
if (e->flags & QLA_EVT_FLAG_FREE)
kfree(e);
- spin_lock_irq(&ha->hardware_lock);
+ spin_lock_irq(&pha->hardware_lock);
}
- spin_unlock_irq(&ha->hardware_lock);
+ spin_unlock_irq(&pha->hardware_lock);
}
/**************************************************************************
@@ -2634,7 +2637,7 @@ qla2x00_timer(scsi_qla_host_t *ha)
#define FW_FILE_ISP24XX "ql2400_fw.bin"
#define FW_FILE_ISP25XX "ql2500_fw.bin"
-static DECLARE_MUTEX(qla_fw_lock);
+static DEFINE_MUTEX(qla_fw_lock);
static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
{ .name = FW_FILE_ISP21XX, .segs = { 0x1000, 0 }, },
@@ -2665,7 +2668,7 @@ qla2x00_request_firmware(scsi_qla_host_t *ha)
blob = &qla_fw_blobs[FW_ISP25XX];
}
- down(&qla_fw_lock);
+ mutex_lock(&qla_fw_lock);
if (blob->fw)
goto out;
@@ -2678,7 +2681,7 @@ qla2x00_request_firmware(scsi_qla_host_t *ha)
}
out:
- up(&qla_fw_lock);
+ mutex_unlock(&qla_fw_lock);
return blob;
}
@@ -2687,11 +2690,11 @@ qla2x00_release_firmware(void)
{
int idx;
- down(&qla_fw_lock);
+ mutex_lock(&qla_fw_lock);
for (idx = 0; idx < FW_BLOBS; idx++)
if (qla_fw_blobs[idx].fw)
release_firmware(qla_fw_blobs[idx].fw);
- up(&qla_fw_lock);
+ mutex_unlock(&qla_fw_lock);
}
static pci_ers_result_t
@@ -2864,7 +2867,8 @@ qla2x00_module_init(void)
return -ENODEV;
}
- printk(KERN_INFO "QLogic Fibre Channel HBA Driver\n");
+ printk(KERN_INFO "QLogic Fibre Channel HBA Driver: %s\n",
+ qla2x00_version_str);
ret = pci_register_driver(&qla2xxx_pci_driver);
if (ret) {
kmem_cache_destroy(srb_cachep);
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index afeae2bfe7eb..d058c8862b35 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.02.01-k2"
+#define QLA2XXX_VERSION "8.02.01-k4"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 2
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index a82d2fe80fb5..cbf55d59a54c 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -207,6 +207,15 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
*/
blk_execute_rq(req->q, NULL, req, 1);
+ /*
+ * Some devices (USB mass-storage in particular) may transfer
+ * garbage data together with a residue indicating that the data
+ * is invalid. Prevent the garbage from being misinterpreted
+ * and prevent security leaks by zeroing out the excess data.
+ */
+ if (unlikely(req->data_len > 0 && req->data_len <= bufflen))
+ memset(buffer + (bufflen - req->data_len), 0, req->data_len);
+
ret = req->errors;
out:
blk_put_request(req);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 049103f1d16f..93d2b6714453 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -359,7 +359,12 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
- struct scsi_device *sdev = to_scsi_device(dev);
+ struct scsi_device *sdev;
+
+ if (dev->type != &scsi_dev_type)
+ return 0;
+
+ sdev = to_scsi_device(dev);
add_uevent_var(env, "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
return 0;
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index 45df83b9d847..0fe031f003e7 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -61,7 +61,7 @@ static int ses_probe(struct device *dev)
return err;
}
-#define SES_TIMEOUT 30
+#define SES_TIMEOUT (30 * HZ)
#define SES_RETRIES 3
static int ses_recv_diag(struct scsi_device *sdev, int page_code,
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 4284625ed035..cee1e4c6d83c 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1451,17 +1451,18 @@ sg_add(struct device *cl_dev, struct class_interface *cl_intf)
if (sg_sysfs_valid) {
struct device *sg_class_member;
- sg_class_member = device_create(sg_sysfs_class, cl_dev->parent,
- MKDEV(SCSI_GENERIC_MAJOR,
- sdp->index),
- "%s", disk->disk_name);
+ sg_class_member = device_create_drvdata(sg_sysfs_class,
+ cl_dev->parent,
+ MKDEV(SCSI_GENERIC_MAJOR,
+ sdp->index),
+ sdp,
+ "%s", disk->disk_name);
if (IS_ERR(sg_class_member)) {
printk(KERN_ERR "sg_add: "
"device_create failed\n");
error = PTR_ERR(sg_class_member);
goto cdev_add_err;
}
- dev_set_drvdata(sg_class_member, sdp);
error = sysfs_create_link(&scsidp->sdev_gendev.kobj,
&sg_class_member->kobj, "generic");
if (error)
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 7ee86d4a7618..c82df8bd4d89 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -178,6 +178,9 @@ int sr_test_unit_ready(struct scsi_device *sdev, struct scsi_sense_hdr *sshdr)
the_result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL,
0, sshdr, SR_TIMEOUT,
retries--);
+ if (scsi_sense_valid(sshdr) &&
+ sshdr->sense_key == UNIT_ATTENTION)
+ sdev->changed = 1;
} while (retries > 0 &&
(!scsi_status_is_good(the_result) ||
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index e93544dd81bf..4684cc716aa4 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -4431,17 +4431,19 @@ static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
snprintf(name, 10, "%s%s%s", rew ? "n" : "",
STp->disk->disk_name, st_formats[i]);
st_class_member =
- device_create(st_sysfs_class, &STp->device->sdev_gendev,
- MKDEV(SCSI_TAPE_MAJOR,
- TAPE_MINOR(dev_num, mode, rew)),
- "%s", name);
+ device_create_drvdata(st_sysfs_class,
+ &STp->device->sdev_gendev,
+ MKDEV(SCSI_TAPE_MAJOR,
+ TAPE_MINOR(dev_num,
+ mode, rew)),
+ &STp->modes[mode],
+ "%s", name);
if (IS_ERR(st_class_member)) {
printk(KERN_WARNING "st%d: device_create failed\n",
dev_num);
error = PTR_ERR(st_class_member);
goto out;
}
- dev_set_drvdata(st_class_member, &STp->modes[mode]);
error = device_create_file(st_class_member,
&dev_attr_defined);
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index a1ca9b7bf2d5..be95e55b228b 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -93,7 +93,6 @@ static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
#define CONFIG_HUB6 1
#include <asm/serial.h>
-
/*
* SERIAL_PORT_DFNS tells us about built-in ports that have no
* standard enumeration mechanism. Platforms that can find all
@@ -2624,6 +2623,9 @@ static struct console serial8250_console = {
static int __init serial8250_console_init(void)
{
+ if (nr_uarts > UART_NR)
+ nr_uarts = UART_NR;
+
serial8250_isa_init_ports();
register_console(&serial8250_console);
return 0;
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 53fa19cf2f06..788c3559522d 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -2602,7 +2602,12 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS200,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0811 */
pbn_b2_2_115200 },
-
+ /*
+ * IntaShield IS-400
+ */
+ { PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0dc0 */
+ pbn_b2_4_115200 },
/*
* Perle PCI-RAS cards
*/
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 62e6eb136a3c..9bc42763623c 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1361,7 +1361,7 @@ config SERIAL_SC26XX_CONSOLE
config SERIAL_BFIN_SPORT
tristate "Blackfin SPORT emulate UART (EXPERIMENTAL)"
- depends on BFIN && EXPERIMENTAL
+ depends on BLACKFIN && EXPERIMENTAL
select SERIAL_CORE
help
Enble support SPORT emulate UART on Blackfin series.
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index c065a704a93a..42be8b01a40f 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -1318,7 +1318,7 @@ static void __init atmel_console_get_options(struct uart_port *port, int *baud,
* If the baud rate generator isn't running, the port wasn't
* initialized by the boot loader.
*/
- quot = UART_GET_BRGR(port);
+ quot = UART_GET_BRGR(port) & ATMEL_US_CD;
if (!quot)
return;
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index d6b4ead693b7..fd9bb777df28 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -49,6 +49,7 @@
#define DMA_RX_YCOUNT (PAGE_SIZE / DMA_RX_XCOUNT)
#define DMA_RX_FLUSH_JIFFIES (HZ / 50)
+#define CTS_CHECK_JIFFIES (HZ / 50)
#ifdef CONFIG_SERIAL_BFIN_DMA
static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);
@@ -290,11 +291,6 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
{
struct circ_buf *xmit = &uart->port.info->xmit;
- if (uart->port.x_char) {
- UART_PUT_CHAR(uart, uart->port.x_char);
- uart->port.icount.tx++;
- uart->port.x_char = 0;
- }
/*
* Check the modem control lines before
* transmitting anything.
@@ -306,6 +302,12 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
return;
}
+ if (uart->port.x_char) {
+ UART_PUT_CHAR(uart, uart->port.x_char);
+ uart->port.icount.tx++;
+ uart->port.x_char = 0;
+ }
+
while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) {
UART_PUT_CHAR(uart, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
@@ -345,15 +347,6 @@ static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
}
#endif
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
-static void bfin_serial_do_work(struct work_struct *work)
-{
- struct bfin_serial_port *uart = container_of(work, struct bfin_serial_port, cts_workqueue);
-
- bfin_serial_mctrl_check(uart);
-}
-#endif
-
#ifdef CONFIG_SERIAL_BFIN_DMA
static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
{
@@ -361,6 +354,12 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
uart->tx_done = 0;
+ /*
+ * Check the modem control lines before
+ * transmitting anything.
+ */
+ bfin_serial_mctrl_check(uart);
+
if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
uart->tx_count = 0;
uart->tx_done = 1;
@@ -373,12 +372,6 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
uart->port.x_char = 0;
}
- /*
- * Check the modem control lines before
- * transmitting anything.
- */
- bfin_serial_mctrl_check(uart);
-
uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail))
uart->tx_count = UART_XMIT_SIZE - xmit->tail;
@@ -530,11 +523,7 @@ static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
if (uart->cts_pin < 0)
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-# ifdef BF54x
- if (UART_GET_MSR(uart) & CTS)
-# else
- if (gpio_get_value(uart->cts_pin))
-# endif
+ if (UART_GET_CTS(uart))
return TIOCM_DSR | TIOCM_CAR;
else
#endif
@@ -549,17 +538,9 @@ static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
return;
if (mctrl & TIOCM_RTS)
-# ifdef BF54x
- UART_PUT_MCR(uart, UART_GET_MCR(uart) & ~MRTS);
-# else
- gpio_set_value(uart->rts_pin, 0);
-# endif
+ UART_CLEAR_RTS(uart);
else
-# ifdef BF54x
- UART_PUT_MCR(uart, UART_GET_MCR(uart) | MRTS);
-# else
- gpio_set_value(uart->rts_pin, 1);
-# endif
+ UART_SET_RTS(uart);
#endif
}
@@ -577,7 +558,10 @@ static void bfin_serial_mctrl_check(struct bfin_serial_port *uart)
uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
if (!(status & TIOCM_CTS)) {
tty->hw_stopped = 1;
- schedule_work(&uart->cts_workqueue);
+ uart->cts_timer.data = (unsigned long)(uart);
+ uart->cts_timer.function = (void *)bfin_serial_mctrl_check;
+ uart->cts_timer.expires = jiffies + CTS_CHECK_JIFFIES;
+ add_timer(&(uart->cts_timer));
} else {
tty->hw_stopped = 0;
}
@@ -752,11 +736,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
/* Disable UART */
ier = UART_GET_IER(uart);
-#ifdef CONFIG_BF54x
- UART_CLEAR_IER(uart, 0xF);
-#else
- UART_PUT_IER(uart, 0);
-#endif
+ UART_DISABLE_INTS(uart);
/* Set DLAB in LCR to Access DLL and DLH */
UART_SET_DLAB(uart);
@@ -771,11 +751,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
UART_PUT_LCR(uart, lcr);
/* Enable UART */
-#ifdef CONFIG_BF54x
- UART_SET_IER(uart, ier);
-#else
- UART_PUT_IER(uart, ier);
-#endif
+ UART_ENABLE_INTS(uart, ier);
val = UART_GET_GCTL(uart);
val |= UCEN;
@@ -833,15 +809,15 @@ bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
* Enable the IrDA function if tty->ldisc.num is N_IRDA.
* In other cases, disable IrDA function.
*/
-static void bfin_set_ldisc(struct tty_struct *tty)
+static void bfin_serial_set_ldisc(struct uart_port *port)
{
- int line = tty->index;
+ int line = port->line;
unsigned short val;
- if (line >= tty->driver->num)
+ if (line >= port->info->tty->driver->num)
return;
- switch (tty->ldisc.num) {
+ switch (port->info->tty->ldisc.num) {
case N_IRDA:
val = UART_GET_GCTL(&bfin_serial_ports[line]);
val |= (IREN | RPOLC);
@@ -866,6 +842,7 @@ static struct uart_ops bfin_serial_pops = {
.startup = bfin_serial_startup,
.shutdown = bfin_serial_shutdown,
.set_termios = bfin_serial_set_termios,
+ .set_ldisc = bfin_serial_set_ldisc,
.type = bfin_serial_type,
.release_port = bfin_serial_release_port,
.request_port = bfin_serial_request_port,
@@ -904,7 +881,7 @@ static void __init bfin_serial_init_ports(void)
init_timer(&(bfin_serial_ports[i].rx_dma_timer));
#endif
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
- INIT_WORK(&bfin_serial_ports[i].cts_workqueue, bfin_serial_do_work);
+ init_timer(&(bfin_serial_ports[i].cts_timer));
bfin_serial_ports[i].cts_pin =
bfin_serial_resource[i].uart_cts_pin;
bfin_serial_ports[i].rts_pin =
@@ -1206,7 +1183,6 @@ static int __init bfin_serial_init(void)
ret = uart_register_driver(&bfin_serial_reg);
if (ret == 0) {
- bfin_serial_reg.tty_driver->set_ldisc = bfin_set_ldisc;
ret = platform_driver_register(&bfin_serial_driver);
if (ret) {
pr_debug("uart register failed\n");
diff --git a/drivers/serial/sb1250-duart.c b/drivers/serial/sb1250-duart.c
index 2d6c08b3dbcf..f8e1447a022a 100644
--- a/drivers/serial/sb1250-duart.c
+++ b/drivers/serial/sb1250-duart.c
@@ -924,7 +924,7 @@ console_initcall(sbd_serial_console_init);
static struct uart_driver sbd_reg = {
.owner = THIS_MODULE,
- .driver_name = "serial",
+ .driver_name = "sb1250_duart",
.dev_name = "duart",
.major = TTY_MAJOR,
.minor = SB1250_DUART_MINOR_BASE,
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index eab032733790..42d2e108b679 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1165,6 +1165,15 @@ out:
return ret;
}
+static void uart_set_ldisc(struct tty_struct *tty)
+{
+ struct uart_state *state = tty->driver_data;
+ struct uart_port *port = state->port;
+
+ if (port->ops->set_ldisc)
+ port->ops->set_ldisc(port);
+}
+
static void uart_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
@@ -1982,7 +1991,9 @@ struct uart_match {
static int serial_match_port(struct device *dev, void *data)
{
struct uart_match *match = data;
- dev_t devt = MKDEV(match->driver->major, match->driver->minor) + match->port->line;
+ struct tty_driver *tty_drv = match->driver->tty_driver;
+ dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) +
+ match->port->line;
return dev->devt == devt; /* Actually, only one tty per port */
}
@@ -2054,6 +2065,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
{
struct uart_state *state = drv->state + port->line;
+ struct device *tty_dev;
+ struct uart_match match = {port, drv};
mutex_lock(&state->mutex);
@@ -2063,7 +2076,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
return 0;
}
- if (!port->suspended) {
+ tty_dev = device_find_child(port->dev, &match, serial_match_port);
+ if (!port->suspended && device_may_wakeup(tty_dev)) {
disable_irq_wake(port->irq);
mutex_unlock(&state->mutex);
return 0;
@@ -2285,6 +2299,7 @@ static const struct tty_operations uart_ops = {
.unthrottle = uart_unthrottle,
.send_xchar = uart_send_xchar,
.set_termios = uart_set_termios,
+ .set_ldisc = uart_set_ldisc,
.stop = uart_stop,
.start = uart_start,
.hangup = uart_hangup,
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 8fdafc27fce8..ce6ee92b3a1b 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -184,15 +184,15 @@ static void put_string(struct sci_port *sci_port, const char *buffer, int count)
int h, l;
c = *p++;
- h = highhex(c);
- l = lowhex(c);
+ h = hex_asc_hi(c);
+ l = hex_asc_lo(c);
put_char(port, h);
put_char(port, l);
checksum += h + l;
}
put_char(port, '#');
- put_char(port, highhex(checksum));
- put_char(port, lowhex(checksum));
+ put_char(port, hex_asc_hi(checksum));
+ put_char(port, hex_asc_lo(checksum));
} while (get_char(port) != '+');
} else
#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index 145c0281495d..2847336742d7 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -499,7 +499,6 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig
} else
spin_lock(&port->lock);
- spin_lock_irqsave(&port->lock, flags);
for (i = 0; i < n; i++) {
if (*s == '\n')
sunhv_console_putchar(port, '\r');
diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c
index 01917c433f17..566a8b42e05a 100644
--- a/drivers/serial/ucc_uart.c
+++ b/drivers/serial/ucc_uart.c
@@ -195,7 +195,7 @@ struct uart_qe_port {
static struct uart_driver ucc_uart_driver = {
.owner = THIS_MODULE,
- .driver_name = "serial",
+ .driver_name = "ucc_uart",
.dev_name = "ttyQE",
.major = SERIAL_QE_MAJOR,
.minor = SERIAL_QE_MINOR,
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index ab2b769c83ca..ddbe1a5e970e 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -25,6 +25,7 @@
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
@@ -68,10 +69,12 @@ static unsigned long minors[N_SPI_MINORS / BITS_PER_LONG];
| SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP)
struct spidev_data {
- struct device dev;
+ dev_t devt;
+ spinlock_t spi_lock;
struct spi_device *spi;
struct list_head device_entry;
+ /* buffer is NULL unless this device is open (users > 0) */
struct mutex buf_lock;
unsigned users;
u8 *buffer;
@@ -86,12 +89,75 @@ MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");
/*-------------------------------------------------------------------------*/
+/*
+ * We can't use the standard synchronous wrappers for file I/O; we
+ * need to protect against async removal of the underlying spi_device.
+ */
+static void spidev_complete(void *arg)
+{
+ complete(arg);
+}
+
+static ssize_t
+spidev_sync(struct spidev_data *spidev, struct spi_message *message)
+{
+ DECLARE_COMPLETION_ONSTACK(done);
+ int status;
+
+ message->complete = spidev_complete;
+ message->context = &done;
+
+ spin_lock_irq(&spidev->spi_lock);
+ if (spidev->spi == NULL)
+ status = -ESHUTDOWN;
+ else
+ status = spi_async(spidev->spi, message);
+ spin_unlock_irq(&spidev->spi_lock);
+
+ if (status == 0) {
+ wait_for_completion(&done);
+ status = message->status;
+ if (status == 0)
+ status = message->actual_length;
+ }
+ return status;
+}
+
+static inline ssize_t
+spidev_sync_write(struct spidev_data *spidev, size_t len)
+{
+ struct spi_transfer t = {
+ .tx_buf = spidev->buffer,
+ .len = len,
+ };
+ struct spi_message m;
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t, &m);
+ return spidev_sync(spidev, &m);
+}
+
+static inline ssize_t
+spidev_sync_read(struct spidev_data *spidev, size_t len)
+{
+ struct spi_transfer t = {
+ .rx_buf = spidev->buffer,
+ .len = len,
+ };
+ struct spi_message m;
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t, &m);
+ return spidev_sync(spidev, &m);
+}
+
+/*-------------------------------------------------------------------------*/
+
/* Read-only message with current device setup */
static ssize_t
spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
struct spidev_data *spidev;
- struct spi_device *spi;
ssize_t status = 0;
/* chipselect only toggles at start or end of operation */
@@ -99,18 +165,17 @@ spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
return -EMSGSIZE;
spidev = filp->private_data;
- spi = spidev->spi;
mutex_lock(&spidev->buf_lock);
- status = spi_read(spi, spidev->buffer, count);
- if (status == 0) {
+ status = spidev_sync_read(spidev, count);
+ if (status > 0) {
unsigned long missing;
- missing = copy_to_user(buf, spidev->buffer, count);
- if (count && missing == count)
+ missing = copy_to_user(buf, spidev->buffer, status);
+ if (missing == status)
status = -EFAULT;
else
- status = count - missing;
+ status = status - missing;
}
mutex_unlock(&spidev->buf_lock);
@@ -123,7 +188,6 @@ spidev_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos)
{
struct spidev_data *spidev;
- struct spi_device *spi;
ssize_t status = 0;
unsigned long missing;
@@ -132,14 +196,11 @@ spidev_write(struct file *filp, const char __user *buf,
return -EMSGSIZE;
spidev = filp->private_data;
- spi = spidev->spi;
mutex_lock(&spidev->buf_lock);
missing = copy_from_user(spidev->buffer, buf, count);
if (missing == 0) {
- status = spi_write(spi, spidev->buffer, count);
- if (status == 0)
- status = count;
+ status = spidev_sync_write(spidev, count);
} else
status = -EFAULT;
mutex_unlock(&spidev->buf_lock);
@@ -154,7 +215,6 @@ static int spidev_message(struct spidev_data *spidev,
struct spi_transfer *k_xfers;
struct spi_transfer *k_tmp;
struct spi_ioc_transfer *u_tmp;
- struct spi_device *spi = spidev->spi;
unsigned n, total;
u8 *buf;
int status = -EFAULT;
@@ -216,7 +276,7 @@ static int spidev_message(struct spidev_data *spidev,
spi_message_add_tail(k_tmp, &msg);
}
- status = spi_sync(spi, &msg);
+ status = spidev_sync(spidev, &msg);
if (status < 0)
goto done;
@@ -270,8 +330,16 @@ spidev_ioctl(struct inode *inode, struct file *filp,
if (err)
return -EFAULT;
+ /* guard against device removal before, or while,
+ * we issue this ioctl.
+ */
spidev = filp->private_data;
- spi = spidev->spi;
+ spin_lock_irq(&spidev->spi_lock);
+ spi = spi_dev_get(spidev->spi);
+ spin_unlock_irq(&spidev->spi_lock);
+
+ if (spi == NULL)
+ return -ESHUTDOWN;
switch (cmd) {
/* read requests */
@@ -357,8 +425,10 @@ spidev_ioctl(struct inode *inode, struct file *filp,
default:
/* segmented and/or full-duplex I/O request */
if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))
- || _IOC_DIR(cmd) != _IOC_WRITE)
- return -ENOTTY;
+ || _IOC_DIR(cmd) != _IOC_WRITE) {
+ retval = -ENOTTY;
+ break;
+ }
tmp = _IOC_SIZE(cmd);
if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {
@@ -386,6 +456,7 @@ spidev_ioctl(struct inode *inode, struct file *filp,
kfree(ioc);
break;
}
+ spi_dev_put(spi);
return retval;
}
@@ -398,7 +469,7 @@ static int spidev_open(struct inode *inode, struct file *filp)
mutex_lock(&device_list_lock);
list_for_each_entry(spidev, &device_list, device_entry) {
- if (spidev->dev.devt == inode->i_rdev) {
+ if (spidev->devt == inode->i_rdev) {
status = 0;
break;
}
@@ -432,10 +503,22 @@ static int spidev_release(struct inode *inode, struct file *filp)
mutex_lock(&device_list_lock);
spidev = filp->private_data;
filp->private_data = NULL;
+
+ /* last close? */
spidev->users--;
if (!spidev->users) {
+ int dofree;
+
kfree(spidev->buffer);
spidev->buffer = NULL;
+
+ /* ... after we unbound from the underlying device? */
+ spin_lock_irq(&spidev->spi_lock);
+ dofree = (spidev->spi == NULL);
+ spin_unlock_irq(&spidev->spi_lock);
+
+ if (dofree)
+ kfree(spidev);
}
mutex_unlock(&device_list_lock);
@@ -462,19 +545,7 @@ static struct file_operations spidev_fops = {
* It also simplifies memory management.
*/
-static void spidev_classdev_release(struct device *dev)
-{
- struct spidev_data *spidev;
-
- spidev = container_of(dev, struct spidev_data, dev);
- kfree(spidev);
-}
-
-static struct class spidev_class = {
- .name = "spidev",
- .owner = THIS_MODULE,
- .dev_release = spidev_classdev_release,
-};
+static struct class *spidev_class;
/*-------------------------------------------------------------------------*/
@@ -491,6 +562,7 @@ static int spidev_probe(struct spi_device *spi)
/* Initialize the driver data */
spidev->spi = spi;
+ spin_lock_init(&spidev->spi_lock);
mutex_init(&spidev->buf_lock);
INIT_LIST_HEAD(&spidev->device_entry);
@@ -501,20 +573,20 @@ static int spidev_probe(struct spi_device *spi)
mutex_lock(&device_list_lock);
minor = find_first_zero_bit(minors, N_SPI_MINORS);
if (minor < N_SPI_MINORS) {
- spidev->dev.parent = &spi->dev;
- spidev->dev.class = &spidev_class;
- spidev->dev.devt = MKDEV(SPIDEV_MAJOR, minor);
- snprintf(spidev->dev.bus_id, sizeof spidev->dev.bus_id,
+ struct device *dev;
+
+ spidev->devt = MKDEV(SPIDEV_MAJOR, minor);
+ dev = device_create(spidev_class, &spi->dev, spidev->devt,
"spidev%d.%d",
spi->master->bus_num, spi->chip_select);
- status = device_register(&spidev->dev);
+ status = IS_ERR(dev) ? PTR_ERR(dev) : 0;
} else {
dev_dbg(&spi->dev, "no minor number available!\n");
status = -ENODEV;
}
if (status == 0) {
set_bit(minor, minors);
- dev_set_drvdata(&spi->dev, spidev);
+ spi_set_drvdata(spi, spidev);
list_add(&spidev->device_entry, &device_list);
}
mutex_unlock(&device_list_lock);
@@ -527,15 +599,21 @@ static int spidev_probe(struct spi_device *spi)
static int spidev_remove(struct spi_device *spi)
{
- struct spidev_data *spidev = dev_get_drvdata(&spi->dev);
+ struct spidev_data *spidev = spi_get_drvdata(spi);
- mutex_lock(&device_list_lock);
+ /* make sure ops on existing fds can abort cleanly */
+ spin_lock_irq(&spidev->spi_lock);
+ spidev->spi = NULL;
+ spi_set_drvdata(spi, NULL);
+ spin_unlock_irq(&spidev->spi_lock);
+ /* prevent new opens */
+ mutex_lock(&device_list_lock);
list_del(&spidev->device_entry);
- dev_set_drvdata(&spi->dev, NULL);
- clear_bit(MINOR(spidev->dev.devt), minors);
- device_unregister(&spidev->dev);
-
+ device_destroy(spidev_class, spidev->devt);
+ clear_bit(MINOR(spidev->devt), minors);
+ if (spidev->users == 0)
+ kfree(spidev);
mutex_unlock(&device_list_lock);
return 0;
@@ -571,15 +649,15 @@ static int __init spidev_init(void)
if (status < 0)
return status;
- status = class_register(&spidev_class);
- if (status < 0) {
+ spidev_class = class_create(THIS_MODULE, "spidev");
+ if (IS_ERR(spidev_class)) {
unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
- return status;
+ return PTR_ERR(spidev_class);
}
status = spi_register_driver(&spidev_spi);
if (status < 0) {
- class_unregister(&spidev_class);
+ class_destroy(spidev_class);
unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
}
return status;
@@ -589,7 +667,7 @@ module_init(spidev_init);
static void __exit spidev_exit(void)
{
spi_unregister_driver(&spidev_spi);
- class_unregister(&spidev_class);
+ class_destroy(spidev_class);
unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
}
module_exit(spidev_exit);
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
index 75def13e797d..538c570df337 100644
--- a/drivers/ssb/driver_pcicore.c
+++ b/drivers/ssb/driver_pcicore.c
@@ -537,12 +537,19 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
int err = 0;
u32 tmp;
- might_sleep();
+ if (dev->bus->bustype != SSB_BUSTYPE_PCI) {
+ /* This SSB device is not on a PCI host-bus. So the IRQs are
+ * not routed through the PCI core.
+ * So we must not enable routing through the PCI core. */
+ goto out;
+ }
if (!pdev)
goto out;
bus = pdev->bus;
+ might_sleep_if(pdev->id.coreid != SSB_DEV_PCI);
+
/* Enable interrupts for this device. */
if (bus->host_pci &&
((pdev->id.revision >= 6) || (pdev->id.coreid == SSB_DEV_PCIE))) {
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 7cf8851286b5..d184f2aea78d 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -1168,15 +1168,21 @@ EXPORT_SYMBOL(ssb_dma_translation);
int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask)
{
struct device *dma_dev = ssb_dev->dma_dev;
+ int err = 0;
#ifdef CONFIG_SSB_PCIHOST
- if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI)
- return dma_set_mask(dma_dev, mask);
+ if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI) {
+ err = pci_set_dma_mask(ssb_dev->bus->host_pci, mask);
+ if (err)
+ return err;
+ err = pci_set_consistent_dma_mask(ssb_dev->bus->host_pci, mask);
+ return err;
+ }
#endif
dma_dev->coherent_dma_mask = mask;
dma_dev->dma_mask = &dma_dev->coherent_dma_mask;
- return 0;
+ return err;
}
EXPORT_SYMBOL(ssb_dma_set_mask);
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 4b628526df09..a86e952ed4ca 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -12,3 +12,12 @@ menuconfig THERMAL
cooling devices.
All platforms with ACPI thermal support can use this driver.
If you want this support, you should say Y or M here.
+
+config THERMAL_HWMON
+ bool "Hardware monitoring support"
+ depends on HWMON=y || HWMON=THERMAL
+ help
+ The generic thermal sysfs driver's hardware monitoring support
+ requires a 2.10.7/3.0.2 or later lm-sensors userspace.
+
+ Say Y if your user-space is new enough.
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 6098787341f3..fe07462d5947 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -295,8 +295,8 @@ thermal_cooling_device_trip_point_show(struct device *dev,
/* Device management */
-#if defined(CONFIG_HWMON) || \
- (defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE))
+#if defined(CONFIG_THERMAL_HWMON)
+
/* hwmon sys I/F */
#include <linux/hwmon.h>
static LIST_HEAD(thermal_hwmon_list);
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 1a0415e77a30..5a7ca2e6094d 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -656,15 +656,14 @@ int __uio_register_device(struct module *owner,
if (ret)
goto err_get_minor;
- idev->dev = device_create(uio_class->class, parent,
- MKDEV(uio_major, idev->minor),
- "uio%d", idev->minor);
+ idev->dev = device_create_drvdata(uio_class->class, parent,
+ MKDEV(uio_major, idev->minor), idev,
+ "uio%d", idev->minor);
if (IS_ERR(idev->dev)) {
printk(KERN_ERR "UIO: device register failed\n");
ret = PTR_ERR(idev->dev);
goto err_device_create;
}
- dev_set_drvdata(idev->dev, idev);
ret = uio_dev_add_attributes(idev);
if (ret)
diff --git a/drivers/usb/c67x00/c67x00-ll-hpi.c b/drivers/usb/c67x00/c67x00-ll-hpi.c
index 5100fbbf6cb0..a9636f43bca2 100644
--- a/drivers/usb/c67x00/c67x00-ll-hpi.c
+++ b/drivers/usb/c67x00/c67x00-ll-hpi.c
@@ -120,7 +120,7 @@ static void hpi_write_word(struct c67x00_device *dev, u16 reg, u16 value)
* Only data is little endian, addr has cpu endianess
*/
static void hpi_write_words_le16(struct c67x00_device *dev, u16 addr,
- u16 *data, u16 count)
+ __le16 *data, u16 count)
{
unsigned long flags;
int i;
@@ -129,7 +129,7 @@ static void hpi_write_words_le16(struct c67x00_device *dev, u16 addr,
hpi_write_reg(dev, HPI_ADDR, addr);
for (i = 0; i < count; i++)
- hpi_write_reg(dev, HPI_DATA, cpu_to_le16(*data++));
+ hpi_write_reg(dev, HPI_DATA, le16_to_cpu(*data++));
spin_unlock_irqrestore(&dev->hpi.lock, flags);
}
@@ -138,7 +138,7 @@ static void hpi_write_words_le16(struct c67x00_device *dev, u16 addr,
* Only data is little endian, addr has cpu endianess
*/
static void hpi_read_words_le16(struct c67x00_device *dev, u16 addr,
- u16 *data, u16 count)
+ __le16 *data, u16 count)
{
unsigned long flags;
int i;
@@ -146,7 +146,7 @@ static void hpi_read_words_le16(struct c67x00_device *dev, u16 addr,
spin_lock_irqsave(&dev->hpi.lock, flags);
hpi_write_reg(dev, HPI_ADDR, addr);
for (i = 0; i < count; i++)
- *data++ = le16_to_cpu(hpi_read_reg(dev, HPI_DATA));
+ *data++ = cpu_to_le16(hpi_read_reg(dev, HPI_DATA));
spin_unlock_irqrestore(&dev->hpi.lock, flags);
}
@@ -425,7 +425,7 @@ void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
len--;
}
- hpi_write_words_le16(dev, addr, (u16 *)buf, len / 2);
+ hpi_write_words_le16(dev, addr, (__le16 *)buf, len / 2);
buf += len & ~0x01;
addr += len & ~0x01;
len &= 0x01;
@@ -456,7 +456,7 @@ void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
len--;
}
- hpi_read_words_le16(dev, addr, (u16 *)buf, len / 2);
+ hpi_read_words_le16(dev, addr, (__le16 *)buf, len / 2);
buf += len & ~0x01;
addr += len & ~0x01;
len &= 0x01;
diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig
index 3a9102d2591b..66f17ed88cb5 100644
--- a/drivers/usb/class/Kconfig
+++ b/drivers/usb/class/Kconfig
@@ -29,3 +29,14 @@ config USB_PRINTER
To compile this driver as a module, choose M here: the
module will be called usblp.
+config USB_WDM
+ tristate "USB Wireless Device Management support"
+ depends on USB
+ ---help---
+ This driver supports the WMC Device Management functionality
+ of cell phones compliant to the CDC WMC specification. You can use
+ AT commands over this device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cdc-wdm.
+
diff --git a/drivers/usb/class/Makefile b/drivers/usb/class/Makefile
index cc391e6c2af8..535d59a30600 100644
--- a/drivers/usb/class/Makefile
+++ b/drivers/usb/class/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_USB_ACM) += cdc-acm.o
obj-$(CONFIG_USB_PRINTER) += usblp.o
+obj-$(CONFIG_USB_WDM) += cdc-wdm.o
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 63c34043b4d9..c3201affa0b6 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1125,9 +1125,6 @@ static void stop_data_traffic(struct acm *acm)
for (i = 0; i < acm->rx_buflimit; i++)
usb_kill_urb(acm->ru[i].urb);
- INIT_LIST_HEAD(&acm->filled_read_bufs);
- INIT_LIST_HEAD(&acm->spare_read_bufs);
-
tasklet_enable(&acm->urb_task);
cancel_work_sync(&acm->work);
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
new file mode 100644
index 000000000000..731db051070a
--- /dev/null
+++ b/drivers/usb/class/cdc-wdm.c
@@ -0,0 +1,740 @@
+/*
+ * cdc-wdm.c
+ *
+ * This driver supports USB CDC WCM Device Management.
+ *
+ * Copyright (c) 2007-2008 Oliver Neukum
+ *
+ * Some code taken from cdc-acm.c
+ *
+ * Released under the GPLv2.
+ *
+ * Many thanks to Carl Nordbeck
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/bitops.h>
+#include <linux/poll.h>
+#include <linux/usb.h>
+#include <linux/usb/cdc.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.02"
+#define DRIVER_AUTHOR "Oliver Neukum"
+
+static struct usb_device_id wdm_ids[] = {
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_DMM
+ },
+ { }
+};
+
+#define WDM_MINOR_BASE 176
+
+
+#define WDM_IN_USE 1
+#define WDM_DISCONNECTING 2
+#define WDM_RESULT 3
+#define WDM_READ 4
+#define WDM_INT_STALL 5
+#define WDM_POLL_RUNNING 6
+
+
+#define WDM_MAX 16
+
+
+static DEFINE_MUTEX(wdm_mutex);
+
+/* --- method tables --- */
+
+struct wdm_device {
+ u8 *inbuf; /* buffer for response */
+ u8 *outbuf; /* buffer for command */
+ u8 *sbuf; /* buffer for status */
+ u8 *ubuf; /* buffer for copy to user space */
+
+ struct urb *command;
+ struct urb *response;
+ struct urb *validity;
+ struct usb_interface *intf;
+ struct usb_ctrlrequest *orq;
+ struct usb_ctrlrequest *irq;
+ spinlock_t iuspin;
+
+ unsigned long flags;
+ u16 bufsize;
+ u16 wMaxCommand;
+ u16 wMaxPacketSize;
+ u16 bMaxPacketSize0;
+ __le16 inum;
+ int reslength;
+ int length;
+ int read;
+ int count;
+ dma_addr_t shandle;
+ dma_addr_t ihandle;
+ struct mutex wlock;
+ struct mutex rlock;
+ wait_queue_head_t wait;
+ struct work_struct rxwork;
+ int werr;
+ int rerr;
+};
+
+static struct usb_driver wdm_driver;
+
+/* --- callbacks --- */
+static void wdm_out_callback(struct urb *urb)
+{
+ struct wdm_device *desc;
+ desc = urb->context;
+ spin_lock(&desc->iuspin);
+ desc->werr = urb->status;
+ spin_unlock(&desc->iuspin);
+ clear_bit(WDM_IN_USE, &desc->flags);
+ kfree(desc->outbuf);
+ wake_up(&desc->wait);
+}
+
+static void wdm_in_callback(struct urb *urb)
+{
+ struct wdm_device *desc = urb->context;
+ int status = urb->status;
+
+ spin_lock(&desc->iuspin);
+
+ if (status) {
+ switch (status) {
+ case -ENOENT:
+ dev_dbg(&desc->intf->dev,
+ "nonzero urb status received: -ENOENT");
+ break;
+ case -ECONNRESET:
+ dev_dbg(&desc->intf->dev,
+ "nonzero urb status received: -ECONNRESET");
+ break;
+ case -ESHUTDOWN:
+ dev_dbg(&desc->intf->dev,
+ "nonzero urb status received: -ESHUTDOWN");
+ break;
+ case -EPIPE:
+ err("nonzero urb status received: -EPIPE");
+ break;
+ default:
+ err("Unexpected error %d", status);
+ break;
+ }
+ }
+
+ desc->rerr = status;
+ desc->reslength = urb->actual_length;
+ memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength);
+ desc->length += desc->reslength;
+ wake_up(&desc->wait);
+
+ set_bit(WDM_READ, &desc->flags);
+ spin_unlock(&desc->iuspin);
+}
+
+static void wdm_int_callback(struct urb *urb)
+{
+ int rv = 0;
+ int status = urb->status;
+ struct wdm_device *desc;
+ struct usb_ctrlrequest *req;
+ struct usb_cdc_notification *dr;
+
+ desc = urb->context;
+ req = desc->irq;
+ dr = (struct usb_cdc_notification *)desc->sbuf;
+
+ if (status) {
+ switch (status) {
+ case -ESHUTDOWN:
+ case -ENOENT:
+ case -ECONNRESET:
+ return; /* unplug */
+ case -EPIPE:
+ set_bit(WDM_INT_STALL, &desc->flags);
+ err("Stall on int endpoint");
+ goto sw; /* halt is cleared in work */
+ default:
+ err("nonzero urb status received: %d", status);
+ break;
+ }
+ }
+
+ if (urb->actual_length < sizeof(struct usb_cdc_notification)) {
+ err("wdm_int_callback - %d bytes", urb->actual_length);
+ goto exit;
+ }
+
+ switch (dr->bNotificationType) {
+ case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:
+ dev_dbg(&desc->intf->dev,
+ "NOTIFY_RESPONSE_AVAILABLE received: index %d len %d",
+ dr->wIndex, dr->wLength);
+ break;
+
+ case USB_CDC_NOTIFY_NETWORK_CONNECTION:
+
+ dev_dbg(&desc->intf->dev,
+ "NOTIFY_NETWORK_CONNECTION %s network",
+ dr->wValue ? "connected to" : "disconnected from");
+ goto exit;
+ default:
+ clear_bit(WDM_POLL_RUNNING, &desc->flags);
+ err("unknown notification %d received: index %d len %d",
+ dr->bNotificationType, dr->wIndex, dr->wLength);
+ goto exit;
+ }
+
+ req->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
+ req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
+ req->wValue = 0;
+ req->wIndex = desc->inum;
+ req->wLength = cpu_to_le16(desc->bMaxPacketSize0);
+
+ usb_fill_control_urb(
+ desc->response,
+ interface_to_usbdev(desc->intf),
+ /* using common endpoint 0 */
+ usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0),
+ (unsigned char *)req,
+ desc->inbuf,
+ desc->bMaxPacketSize0,
+ wdm_in_callback,
+ desc
+ );
+ desc->response->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ spin_lock(&desc->iuspin);
+ clear_bit(WDM_READ, &desc->flags);
+ if (!test_bit(WDM_DISCONNECTING, &desc->flags)) {
+ rv = usb_submit_urb(desc->response, GFP_ATOMIC);
+ dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d",
+ __func__, rv);
+ }
+ spin_unlock(&desc->iuspin);
+ if (rv < 0) {
+ if (rv == -EPERM)
+ return;
+ if (rv == -ENOMEM) {
+sw:
+ rv = schedule_work(&desc->rxwork);
+ if (rv)
+ err("Cannot schedule work");
+ }
+ }
+exit:
+ rv = usb_submit_urb(urb, GFP_ATOMIC);
+ if (rv)
+ err("%s - usb_submit_urb failed with result %d",
+ __func__, rv);
+
+}
+
+static void kill_urbs(struct wdm_device *desc)
+{
+ usb_kill_urb(desc->command);
+ usb_kill_urb(desc->validity);
+ usb_kill_urb(desc->response);
+}
+
+static void free_urbs(struct wdm_device *desc)
+{
+ usb_free_urb(desc->validity);
+ usb_free_urb(desc->response);
+ usb_free_urb(desc->command);
+}
+
+static void cleanup(struct wdm_device *desc)
+{
+ usb_buffer_free(interface_to_usbdev(desc->intf),
+ desc->wMaxPacketSize,
+ desc->sbuf,
+ desc->validity->transfer_dma);
+ usb_buffer_free(interface_to_usbdev(desc->intf),
+ desc->wMaxPacketSize,
+ desc->inbuf,
+ desc->response->transfer_dma);
+ kfree(desc->orq);
+ kfree(desc->irq);
+ kfree(desc->ubuf);
+ free_urbs(desc);
+ kfree(desc);
+}
+
+static ssize_t wdm_write
+(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+{
+ u8 *buf;
+ int rv = -EMSGSIZE, r, we;
+ struct wdm_device *desc = file->private_data;
+ struct usb_ctrlrequest *req;
+
+ if (count > desc->wMaxCommand)
+ count = desc->wMaxCommand;
+
+ spin_lock_irq(&desc->iuspin);
+ we = desc->werr;
+ desc->werr = 0;
+ spin_unlock_irq(&desc->iuspin);
+ if (we < 0)
+ return -EIO;
+
+ r = mutex_lock_interruptible(&desc->wlock); /* concurrent writes */
+ rv = -ERESTARTSYS;
+ if (r)
+ goto outnl;
+
+ r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE,
+ &desc->flags));
+ if (r < 0)
+ goto out;
+
+ if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
+ rv = -ENODEV;
+ goto out;
+ }
+
+ desc->outbuf = buf = kmalloc(count, GFP_KERNEL);
+ if (!buf) {
+ rv = -ENOMEM;
+ goto out;
+ }
+
+ r = copy_from_user(buf, buffer, count);
+ if (r > 0) {
+ kfree(buf);
+ rv = -EFAULT;
+ goto out;
+ }
+
+ req = desc->orq;
+ usb_fill_control_urb(
+ desc->command,
+ interface_to_usbdev(desc->intf),
+ /* using common endpoint 0 */
+ usb_sndctrlpipe(interface_to_usbdev(desc->intf), 0),
+ (unsigned char *)req,
+ buf,
+ count,
+ wdm_out_callback,
+ desc
+ );
+
+ req->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE);
+ req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND;
+ req->wValue = 0;
+ req->wIndex = desc->inum;
+ req->wLength = cpu_to_le16(count);
+ set_bit(WDM_IN_USE, &desc->flags);
+
+ rv = usb_submit_urb(desc->command, GFP_KERNEL);
+ if (rv < 0) {
+ kfree(buf);
+ clear_bit(WDM_IN_USE, &desc->flags);
+ } else {
+ dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d",
+ req->wIndex);
+ }
+out:
+ mutex_unlock(&desc->wlock);
+outnl:
+ return rv < 0 ? rv : count;
+}
+
+static ssize_t wdm_read
+(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+{
+ int rv, cntr;
+ int i = 0;
+ struct wdm_device *desc = file->private_data;
+
+
+ rv = mutex_lock_interruptible(&desc->rlock); /*concurrent reads */
+ if (rv < 0)
+ return -ERESTARTSYS;
+
+ if (desc->length == 0) {
+ desc->read = 0;
+retry:
+ i++;
+ rv = wait_event_interruptible(desc->wait,
+ test_bit(WDM_READ, &desc->flags));
+
+ if (rv < 0) {
+ rv = -ERESTARTSYS;
+ goto err;
+ }
+
+ spin_lock_irq(&desc->iuspin);
+
+ if (desc->rerr) { /* read completed, error happened */
+ int t = desc->rerr;
+ desc->rerr = 0;
+ spin_unlock_irq(&desc->iuspin);
+ err("reading had resulted in %d", t);
+ rv = -EIO;
+ goto err;
+ }
+ /*
+ * recheck whether we've lost the race
+ * against the completion handler
+ */
+ if (!test_bit(WDM_READ, &desc->flags)) { /* lost race */
+ spin_unlock_irq(&desc->iuspin);
+ goto retry;
+ }
+ if (!desc->reslength) { /* zero length read */
+ spin_unlock_irq(&desc->iuspin);
+ goto retry;
+ }
+ clear_bit(WDM_READ, &desc->flags);
+ spin_unlock_irq(&desc->iuspin);
+ }
+
+ cntr = count > desc->length ? desc->length : count;
+ rv = copy_to_user(buffer, desc->ubuf, cntr);
+ if (rv > 0) {
+ rv = -EFAULT;
+ goto err;
+ }
+
+ for (i = 0; i < desc->length - cntr; i++)
+ desc->ubuf[i] = desc->ubuf[i + cntr];
+
+ desc->length -= cntr;
+ rv = cntr;
+
+err:
+ mutex_unlock(&desc->rlock);
+ if (rv < 0)
+ err("wdm_read: exit error");
+ return rv;
+}
+
+static int wdm_flush(struct file *file, fl_owner_t id)
+{
+ struct wdm_device *desc = file->private_data;
+
+ wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags));
+ if (desc->werr < 0)
+ err("Error in flush path: %d", desc->werr);
+
+ return desc->werr;
+}
+
+static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct wdm_device *desc = file->private_data;
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ spin_lock_irqsave(&desc->iuspin, flags);
+ if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
+ mask = POLLERR;
+ spin_unlock_irqrestore(&desc->iuspin, flags);
+ goto desc_out;
+ }
+ if (test_bit(WDM_READ, &desc->flags))
+ mask = POLLIN | POLLRDNORM;
+ if (desc->rerr || desc->werr)
+ mask |= POLLERR;
+ if (!test_bit(WDM_IN_USE, &desc->flags))
+ mask |= POLLOUT | POLLWRNORM;
+ spin_unlock_irqrestore(&desc->iuspin, flags);
+
+ poll_wait(file, &desc->wait, wait);
+
+desc_out:
+ return mask;
+}
+
+static int wdm_open(struct inode *inode, struct file *file)
+{
+ int minor = iminor(inode);
+ int rv = -ENODEV;
+ struct usb_interface *intf;
+ struct wdm_device *desc;
+
+ mutex_lock(&wdm_mutex);
+ intf = usb_find_interface(&wdm_driver, minor);
+ if (!intf)
+ goto out;
+
+ desc = usb_get_intfdata(intf);
+ if (test_bit(WDM_DISCONNECTING, &desc->flags))
+ goto out;
+
+ desc->count++;
+ file->private_data = desc;
+
+ rv = usb_submit_urb(desc->validity, GFP_KERNEL);
+
+ if (rv < 0) {
+ desc->count--;
+ err("Error submitting int urb - %d", rv);
+ goto out;
+ }
+ rv = 0;
+
+out:
+ mutex_unlock(&wdm_mutex);
+ return rv;
+}
+
+static int wdm_release(struct inode *inode, struct file *file)
+{
+ struct wdm_device *desc = file->private_data;
+
+ mutex_lock(&wdm_mutex);
+ desc->count--;
+ if (!desc->count) {
+ dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
+ kill_urbs(desc);
+ }
+ mutex_unlock(&wdm_mutex);
+ return 0;
+}
+
+static const struct file_operations wdm_fops = {
+ .owner = THIS_MODULE,
+ .read = wdm_read,
+ .write = wdm_write,
+ .open = wdm_open,
+ .flush = wdm_flush,
+ .release = wdm_release,
+ .poll = wdm_poll
+};
+
+static struct usb_class_driver wdm_class = {
+ .name = "cdc-wdm%d",
+ .fops = &wdm_fops,
+ .minor_base = WDM_MINOR_BASE,
+};
+
+/* --- error handling --- */
+static void wdm_rxwork(struct work_struct *work)
+{
+ struct wdm_device *desc = container_of(work, struct wdm_device, rxwork);
+ unsigned long flags;
+ int rv;
+
+ spin_lock_irqsave(&desc->iuspin, flags);
+ if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
+ spin_unlock_irqrestore(&desc->iuspin, flags);
+ } else {
+ spin_unlock_irqrestore(&desc->iuspin, flags);
+ rv = usb_submit_urb(desc->response, GFP_KERNEL);
+ if (rv < 0 && rv != -EPERM) {
+ spin_lock_irqsave(&desc->iuspin, flags);
+ if (!test_bit(WDM_DISCONNECTING, &desc->flags))
+ schedule_work(&desc->rxwork);
+ spin_unlock_irqrestore(&desc->iuspin, flags);
+ }
+ }
+}
+
+/* --- hotplug --- */
+
+static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ int rv = -EINVAL;
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct wdm_device *desc;
+ struct usb_host_interface *iface;
+ struct usb_endpoint_descriptor *ep;
+ struct usb_cdc_dmm_desc *dmhd;
+ u8 *buffer = intf->altsetting->extra;
+ int buflen = intf->altsetting->extralen;
+ u16 maxcom = 0;
+
+ if (!buffer)
+ goto out;
+
+ while (buflen > 0) {
+ if (buffer [1] != USB_DT_CS_INTERFACE) {
+ err("skipping garbage");
+ goto next_desc;
+ }
+
+ switch (buffer [2]) {
+ case USB_CDC_HEADER_TYPE:
+ break;
+ case USB_CDC_DMM_TYPE:
+ dmhd = (struct usb_cdc_dmm_desc *)buffer;
+ maxcom = le16_to_cpu(dmhd->wMaxCommand);
+ dev_dbg(&intf->dev,
+ "Finding maximum buffer length: %d", maxcom);
+ break;
+ default:
+ err("Ignoring extra header, type %d, length %d",
+ buffer[2], buffer[0]);
+ break;
+ }
+next_desc:
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ rv = -ENOMEM;
+ desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL);
+ if (!desc)
+ goto out;
+ mutex_init(&desc->wlock);
+ mutex_init(&desc->rlock);
+ spin_lock_init(&desc->iuspin);
+ init_waitqueue_head(&desc->wait);
+ desc->wMaxCommand = maxcom;
+ desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber);
+ desc->intf = intf;
+ INIT_WORK(&desc->rxwork, wdm_rxwork);
+
+ iface = &intf->altsetting[0];
+ ep = &iface->endpoint[0].desc;
+ if (!usb_endpoint_is_int_in(ep)) {
+ rv = -EINVAL;
+ goto err;
+ }
+
+ desc->wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize);
+ desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0;
+
+ desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!desc->orq)
+ goto err;
+ desc->irq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!desc->irq)
+ goto err;
+
+ desc->validity = usb_alloc_urb(0, GFP_KERNEL);
+ if (!desc->validity)
+ goto err;
+
+ desc->response = usb_alloc_urb(0, GFP_KERNEL);
+ if (!desc->response)
+ goto err;
+
+ desc->command = usb_alloc_urb(0, GFP_KERNEL);
+ if (!desc->command)
+ goto err;
+
+ desc->ubuf = kmalloc(desc->wMaxCommand, GFP_KERNEL);
+ if (!desc->ubuf)
+ goto err;
+
+ desc->sbuf = usb_buffer_alloc(interface_to_usbdev(intf),
+ desc->wMaxPacketSize,
+ GFP_KERNEL,
+ &desc->validity->transfer_dma);
+ if (!desc->sbuf)
+ goto err;
+
+ desc->inbuf = usb_buffer_alloc(interface_to_usbdev(intf),
+ desc->bMaxPacketSize0,
+ GFP_KERNEL,
+ &desc->response->transfer_dma);
+ if (!desc->inbuf)
+ goto err2;
+
+ usb_fill_int_urb(
+ desc->validity,
+ interface_to_usbdev(intf),
+ usb_rcvintpipe(interface_to_usbdev(intf), ep->bEndpointAddress),
+ desc->sbuf,
+ desc->wMaxPacketSize,
+ wdm_int_callback,
+ desc,
+ ep->bInterval
+ );
+ desc->validity->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ usb_set_intfdata(intf, desc);
+ rv = usb_register_dev(intf, &wdm_class);
+ dev_info(&intf->dev, "cdc-wdm%d: USB WDM device\n",
+ intf->minor - WDM_MINOR_BASE);
+ if (rv < 0)
+ goto err;
+out:
+ return rv;
+err2:
+ usb_buffer_free(interface_to_usbdev(desc->intf),
+ desc->wMaxPacketSize,
+ desc->sbuf,
+ desc->validity->transfer_dma);
+err:
+ free_urbs(desc);
+ kfree(desc->ubuf);
+ kfree(desc->orq);
+ kfree(desc->irq);
+ kfree(desc);
+ return rv;
+}
+
+static void wdm_disconnect(struct usb_interface *intf)
+{
+ struct wdm_device *desc;
+ unsigned long flags;
+
+ usb_deregister_dev(intf, &wdm_class);
+ mutex_lock(&wdm_mutex);
+ desc = usb_get_intfdata(intf);
+
+ /* the spinlock makes sure no new urbs are generated in the callbacks */
+ spin_lock_irqsave(&desc->iuspin, flags);
+ set_bit(WDM_DISCONNECTING, &desc->flags);
+ set_bit(WDM_READ, &desc->flags);
+ clear_bit(WDM_IN_USE, &desc->flags);
+ spin_unlock_irqrestore(&desc->iuspin, flags);
+ cancel_work_sync(&desc->rxwork);
+ kill_urbs(desc);
+ wake_up_all(&desc->wait);
+ if (!desc->count)
+ cleanup(desc);
+ mutex_unlock(&wdm_mutex);
+}
+
+static struct usb_driver wdm_driver = {
+ .name = "cdc_wdm",
+ .probe = wdm_probe,
+ .disconnect = wdm_disconnect,
+ .id_table = wdm_ids,
+};
+
+/* --- low level module stuff --- */
+
+static int __init wdm_init(void)
+{
+ int rv;
+
+ rv = usb_register(&wdm_driver);
+
+ return rv;
+}
+
+static void __exit wdm_exit(void)
+{
+ usb_deregister(&wdm_driver);
+}
+
+module_init(wdm_init);
+module_exit(wdm_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION("USB Abstract Control Model driver for "
+ "USB WCM Device Management");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index c1cb94e9f242..7e912f21fd36 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -155,9 +155,6 @@ static int generic_probe(struct usb_device *udev)
{
int err, c;
- /* put device-specific files into sysfs */
- usb_create_sysfs_dev_files(udev);
-
/* Choose and set the configuration. This registers the interfaces
* with the driver core and lets interface drivers bind to them.
*/
@@ -189,8 +186,6 @@ static void generic_disconnect(struct usb_device *udev)
* unconfigure the device */
if (udev->actconfig)
usb_set_configuration(udev, -1);
-
- usb_remove_sysfs_dev_files(udev);
}
#ifdef CONFIG_PM
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index bf10e9c4195e..42a436478b78 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -818,12 +818,12 @@ static int usb_register_bus(struct usb_bus *bus)
set_bit (busnum, busmap.busmap);
bus->busnum = busnum;
- bus->dev = device_create(usb_host_class, bus->controller, MKDEV(0, 0),
- "usb_host%d", busnum);
+ bus->dev = device_create_drvdata(usb_host_class, bus->controller,
+ MKDEV(0, 0), bus,
+ "usb_host%d", busnum);
result = PTR_ERR(bus->dev);
if (IS_ERR(bus->dev))
goto error_create_class_dev;
- dev_set_drvdata(bus->dev, bus);
/* Add it to the local list of buses */
list_add (&bus->bus_list, &usb_bus_list);
@@ -924,6 +924,15 @@ static int register_root_hub(struct usb_hcd *hcd)
return retval;
}
+void usb_enable_root_hub_irq (struct usb_bus *bus)
+{
+ struct usb_hcd *hcd;
+
+ hcd = container_of (bus, struct usb_hcd, self);
+ if (hcd->driver->hub_irq_enable && hcd->state != HC_STATE_HALT)
+ hcd->driver->hub_irq_enable (hcd);
+}
+
/*-------------------------------------------------------------------------*/
@@ -1684,19 +1693,30 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum);
irqreturn_t usb_hcd_irq (int irq, void *__hcd)
{
struct usb_hcd *hcd = __hcd;
- int start = hcd->state;
+ unsigned long flags;
+ irqreturn_t rc;
- if (unlikely(start == HC_STATE_HALT ||
- !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
- return IRQ_NONE;
- if (hcd->driver->irq (hcd) == IRQ_NONE)
- return IRQ_NONE;
+ /* IRQF_DISABLED doesn't work correctly with shared IRQs
+ * when the first handler doesn't use it. So let's just
+ * assume it's never used.
+ */
+ local_irq_save(flags);
- set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+ if (unlikely(hcd->state == HC_STATE_HALT ||
+ !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
+ rc = IRQ_NONE;
+ } else if (hcd->driver->irq(hcd) == IRQ_NONE) {
+ rc = IRQ_NONE;
+ } else {
+ set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+
+ if (unlikely(hcd->state == HC_STATE_HALT))
+ usb_hc_died(hcd);
+ rc = IRQ_HANDLED;
+ }
- if (unlikely(hcd->state == HC_STATE_HALT))
- usb_hc_died (hcd);
- return IRQ_HANDLED;
+ local_irq_restore(flags);
+ return rc;
}
/*-------------------------------------------------------------------------*/
@@ -1860,6 +1880,13 @@ int usb_add_hcd(struct usb_hcd *hcd,
/* enable irqs just before we start the controller */
if (hcd->driver->irq) {
+
+ /* IRQF_DISABLED doesn't work as advertised when used together
+ * with IRQF_SHARED. As usb_hcd_irq() will always disable
+ * interrupts we can remove it here.
+ */
+ irqflags &= ~IRQF_DISABLED;
+
snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
hcd->driver->description, hcd->self.busnum);
if ((retval = request_irq(irqnum, &usb_hcd_irq, irqflags,
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 1e4b81e9eb50..b9de1569b39e 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -210,9 +210,13 @@ struct hc_driver {
int (*bus_suspend)(struct usb_hcd *);
int (*bus_resume)(struct usb_hcd *);
int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
+ void (*hub_irq_enable)(struct usb_hcd *);
+ /* Needed only if port-change IRQs are level-triggered */
/* force handover of high-speed port to full-speed companion */
void (*relinquish_port)(struct usb_hcd *, int);
+ /* has a port been handed over to a companion? */
+ int (*port_handed_over)(struct usb_hcd *, int);
};
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index eb57fcc701d7..4cfe32a16c37 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -644,6 +644,48 @@ static void hub_stop(struct usb_hub *hub)
#ifdef CONFIG_PM
+/* Try to identify which devices need USB-PERSIST handling */
+static int persistent_device(struct usb_device *udev)
+{
+ int i;
+ int retval;
+ struct usb_host_config *actconfig;
+
+ /* Explicitly not marked persistent? */
+ if (!udev->persist_enabled)
+ return 0;
+
+ /* No active config? */
+ actconfig = udev->actconfig;
+ if (!actconfig)
+ return 0;
+
+ /* FIXME! We should check whether it's open here or not! */
+
+ /*
+ * Check that all the interface drivers have a
+ * 'reset_resume' entrypoint
+ */
+ retval = 0;
+ for (i = 0; i < actconfig->desc.bNumInterfaces; i++) {
+ struct usb_interface *intf;
+ struct usb_driver *driver;
+
+ intf = actconfig->interface[i];
+ if (!intf->dev.driver)
+ continue;
+ driver = to_usb_driver(intf->dev.driver);
+ if (!driver->reset_resume)
+ return 0;
+ /*
+ * We have at least one driver, and that one
+ * has a reset_resume method.
+ */
+ retval = 1;
+ }
+ return retval;
+}
+
static void hub_restart(struct usb_hub *hub, int type)
{
struct usb_device *hdev = hub->hdev;
@@ -671,26 +713,19 @@ static void hub_restart(struct usb_hub *hub, int type)
}
/* Was the power session lost while we were suspended? */
- switch (type) {
- case HUB_RESET_RESUME:
- portstatus = 0;
- portchange = USB_PORT_STAT_C_CONNECTION;
- break;
+ status = hub_port_status(hub, port1, &portstatus, &portchange);
- case HUB_RESET:
- case HUB_RESUME:
- status = hub_port_status(hub, port1,
- &portstatus, &portchange);
- break;
- }
+ /* If the device is gone, khubd will handle it later */
+ if (status == 0 && !(portstatus & USB_PORT_STAT_CONNECTION))
+ continue;
/* For "USB_PERSIST"-enabled children we must
* mark the child device for reset-resume and
* turn off the various status changes to prevent
* khubd from disconnecting it later.
*/
- if (udev->persist_enabled && status == 0 &&
- !(portstatus & USB_PORT_STAT_ENABLE)) {
+ if (status == 0 && !(portstatus & USB_PORT_STAT_ENABLE) &&
+ persistent_device(udev)) {
if (portchange & USB_PORT_STAT_C_ENABLE)
clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_ENABLE);
@@ -1326,6 +1361,12 @@ void usb_disconnect(struct usb_device **pdev)
usb_unlock_device(udev);
+ /* Remove the device-specific files from sysfs. This must be
+ * done with udev unlocked, because some of the attribute
+ * routines try to acquire the device lock.
+ */
+ usb_remove_sysfs_dev_files(udev);
+
/* Unregister the device. The device driver is responsible
* for removing the device files from usbfs and sysfs and for
* de-configuring the device.
@@ -1541,6 +1582,9 @@ int usb_new_device(struct usb_device *udev)
goto fail;
}
+ /* put device-specific files into sysfs */
+ usb_create_sysfs_dev_files(udev);
+
/* Tell the world! */
announce_device(udev);
return err;
@@ -2029,6 +2073,8 @@ int usb_port_resume(struct usb_device *udev)
}
clear_bit(port1, hub->busy_bits);
+ if (!hub->hdev->parent && !hub->busy_bits[0])
+ usb_enable_root_hub_irq(hub->hdev->bus);
if (status == 0)
status = finish_port_resume(udev);
@@ -2744,7 +2790,11 @@ loop:
if ((status == -ENOTCONN) || (status == -ENOTSUPP))
break;
}
- dev_err(hub_dev, "unable to enumerate USB device on port %d\n", port1);
+ if (hub->hdev->parent ||
+ !hcd->driver->port_handed_over ||
+ !(hcd->driver->port_handed_over)(hcd, port1))
+ dev_err(hub_dev, "unable to enumerate USB device on port %d\n",
+ port1);
done:
hub_port_disable(hub, port1, 1);
@@ -2954,6 +3004,11 @@ static void hub_events(void)
hub->activating = 0;
+ /* If this is a root hub, tell the HCD it's okay to
+ * re-enable port-change interrupts now. */
+ if (!hdev->parent && !hub->busy_bits[0])
+ usb_enable_root_hub_irq(hdev->bus);
+
loop_autopm:
/* Allow autosuspend if we're not going to run again */
if (list_empty(&hub->event_list))
@@ -3179,6 +3234,8 @@ int usb_reset_device(struct usb_device *udev)
break;
}
clear_bit(port1, parent_hub->busy_bits);
+ if (!parent_hdev->parent && !parent_hub->busy_bits[0])
+ usb_enable_root_hub_irq(parent_hdev->bus);
if (ret < 0)
goto re_enumerate;
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 2e2019390290..c070b34b669d 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -47,6 +47,13 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Edirol SD-20 */
{ USB_DEVICE(0x0582, 0x0027), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* appletouch */
+ { USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* Avision AV600U */
+ { USB_DEVICE(0x0638, 0x0a13), .driver_info =
+ USB_QUIRK_STRING_FETCH_255 },
+
/* M-Systems Flash Disk Pioneers */
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index c783cb111847..5e1f5d55bf04 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -588,35 +588,33 @@ read_descriptors(struct kobject *kobj, struct bin_attribute *attr,
container_of(kobj, struct device, kobj));
size_t nleft = count;
size_t srclen, n;
+ int cfgno;
+ void *src;
- usb_lock_device(udev);
-
- /* The binary attribute begins with the device descriptor */
- srclen = sizeof(struct usb_device_descriptor);
- if (off < srclen) {
- n = min_t(size_t, nleft, srclen - off);
- memcpy(buf, off + (char *) &udev->descriptor, n);
- nleft -= n;
- buf += n;
- off = 0;
- } else {
- off -= srclen;
- }
-
- /* Then follows the raw descriptor entry for the current
- * configuration (config plus subsidiary descriptors).
+ /* The binary attribute begins with the device descriptor.
+ * Following that are the raw descriptor entries for all the
+ * configurations (config plus subsidiary descriptors).
*/
- if (udev->actconfig) {
- int cfgno = udev->actconfig - udev->config;
-
- srclen = __le16_to_cpu(udev->actconfig->desc.wTotalLength);
+ for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations &&
+ nleft > 0; ++cfgno) {
+ if (cfgno < 0) {
+ src = &udev->descriptor;
+ srclen = sizeof(struct usb_device_descriptor);
+ } else {
+ src = udev->rawdescriptors[cfgno];
+ srclen = __le16_to_cpu(udev->config[cfgno].desc.
+ wTotalLength);
+ }
if (off < srclen) {
- n = min_t(size_t, nleft, srclen - off);
- memcpy(buf, off + udev->rawdescriptors[cfgno], n);
+ n = min(nleft, srclen - (size_t) off);
+ memcpy(buf, src + off, n);
nleft -= n;
+ buf += n;
+ off = 0;
+ } else {
+ off -= srclen;
}
}
- usb_unlock_device(udev);
return count - nleft;
}
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
index 651b82701394..18687543d7fa 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.c
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -1627,7 +1627,9 @@ static int reset_queues(struct fsl_udc *udc)
udc_reset_ep_queue(udc, pipe);
/* report disconnect; the driver is already quiesced */
+ spin_unlock(&udc->lock);
udc->driver->disconnect(&udc->gadget);
+ spin_lock(&udc->lock);
return 0;
}
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 499b7a23f351..e02bfd4df3a6 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -1526,7 +1526,8 @@ static void udc_disable(struct pxa_udc *udc)
ep0_idle(udc);
udc->gadget.speed = USB_SPEED_UNKNOWN;
- udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
+ if (udc->mach->udc_command)
+ udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
}
/**
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 1ef6df395e0c..228797e54f9c 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -300,8 +300,8 @@ config USB_R8A66597_HCD
module will be called r8a66597-hcd.
config SUPERH_ON_CHIP_R8A66597
- boolean "Enable SuperH on-chip USB like the R8A66597"
- depends on USB_R8A66597_HCD && CPU_SUBTYPE_SH7366
+ boolean "Enable SuperH on-chip R8A66597 USB"
+ depends on USB_R8A66597_HCD && (CPU_SUBTYPE_SH7366 || CPU_SUBTYPE_SH7723)
help
- Renesas SuperH processor has USB like the R8A66597.
- This driver supported processor is SH7366.
+ This driver enables support for the on-chip R8A66597 in the
+ SH7366 and SH7723 processors.
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index 8b5f991e949c..08a4335401a9 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -223,6 +223,7 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
.relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 6d9bed6c1f48..7370d6187c64 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -269,7 +269,7 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
if (retval)
return retval;
- ehci->is_tdi_rh_tt = 1;
+ hcd->has_tt = 1;
ehci->sbrn = 0x20;
@@ -295,10 +295,6 @@ static const struct hc_driver ehci_fsl_hc_driver = {
*/
.reset = ehci_fsl_setup,
.start = ehci_run,
-#ifdef CONFIG_PM
- .suspend = ehci_bus_suspend,
- .resume = ehci_bus_resume,
-#endif
.stop = ehci_stop,
.shutdown = ehci_shutdown,
@@ -322,6 +318,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
.relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
};
static int ehci_fsl_drv_probe(struct platform_device *pdev)
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 382587c4457c..740835bb8575 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -609,7 +609,7 @@ static int ehci_hub_control (
}
break;
case USB_PORT_FEAT_C_SUSPEND:
- /* we auto-clear this feature */
+ clear_bit(wIndex, &ehci->port_c_suspend);
break;
case USB_PORT_FEAT_POWER:
if (HCS_PPC (ehci->hcs_params))
@@ -688,7 +688,7 @@ static int ehci_hub_control (
/* resume completed? */
else if (time_after_eq(jiffies,
ehci->reset_done[wIndex])) {
- status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+ set_bit(wIndex, &ehci->port_c_suspend);
ehci->reset_done[wIndex] = 0;
/* stop resume signaling */
@@ -765,6 +765,8 @@ static int ehci_hub_control (
status |= 1 << USB_PORT_FEAT_RESET;
if (temp & PORT_POWER)
status |= 1 << USB_PORT_FEAT_POWER;
+ if (test_bit(wIndex, &ehci->port_c_suspend))
+ status |= 1 << USB_PORT_FEAT_C_SUSPEND;
#ifndef VERBOSE_DEBUG
if (status & ~0xffff) /* only if wPortChange is interesting */
@@ -875,3 +877,13 @@ static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum)
set_owner(ehci, --portnum, PORT_OWNER);
}
+static int ehci_port_handed_over(struct usb_hcd *hcd, int portnum)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ u32 __iomem *reg;
+
+ if (ehci_is_TDI(ehci))
+ return 0;
+ reg = &ehci->regs->port_status[portnum - 1];
+ return ehci_readl(ehci, reg) & PORT_OWNER;
+}
diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c
index 601c8795a854..9d042f220097 100644
--- a/drivers/usb/host/ehci-ixp4xx.c
+++ b/drivers/usb/host/ehci-ixp4xx.c
@@ -26,7 +26,7 @@ static int ixp4xx_ehci_init(struct usb_hcd *hcd)
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
- ehci->is_tdi_rh_tt = 1;
+ hcd->has_tt = 1;
ehci_reset(ehci);
retval = ehci_init(hcd);
@@ -58,6 +58,8 @@ static const struct hc_driver ixp4xx_ehci_hc_driver = {
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
#endif
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
};
static int ixp4xx_ehci_probe(struct platform_device *pdev)
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index d187d0313742..ab625f0ba1d9 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -115,6 +115,8 @@ static int ehci_orion_setup(struct usb_hcd *hcd)
if (retval)
return retval;
+ hcd->has_tt = 1;
+
ehci_reset(ehci);
ehci_port_power(ehci, 0);
@@ -137,10 +139,6 @@ static const struct hc_driver ehci_orion_hc_driver = {
*/
.reset = ehci_orion_setup,
.start = ehci_run,
-#ifdef CONFIG_PM
- .suspend = ehci_bus_suspend,
- .resume = ehci_bus_resume,
-#endif
.stop = ehci_stop,
.shutdown = ehci_shutdown,
@@ -163,6 +161,8 @@ static const struct hc_driver ehci_orion_hc_driver = {
.hub_control = ehci_hub_control,
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
};
static void __init
@@ -248,7 +248,7 @@ static int __init ehci_orion_drv_probe(struct platform_device *pdev)
ehci->regs = hcd->regs + 0x100 +
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
- ehci->is_tdi_rh_tt = 1;
+ hcd->has_tt = 1;
ehci->sbrn = 0x20;
/*
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 5bb7f6bb13f3..c46a58f9181d 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -129,7 +129,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
switch (pdev->vendor) {
case PCI_VENDOR_ID_TDI:
if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
- ehci->is_tdi_rh_tt = 1;
hcd->has_tt = 1;
tdi_reset(ehci);
}
@@ -379,7 +378,8 @@ static const struct hc_driver ehci_pci_hc_driver = {
.hub_control = ehci_hub_control,
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
- .relinquish_port = ehci_relinquish_port,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
index ee305b1f99ff..b018deed2e8f 100644
--- a/drivers/usb/host/ehci-ppc-of.c
+++ b/drivers/usb/host/ehci-ppc-of.c
@@ -76,6 +76,8 @@ static const struct hc_driver ehci_ppc_of_hc_driver = {
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
#endif
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
};
diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c
index 6c76036783a1..529590eb4037 100644
--- a/drivers/usb/host/ehci-ppc-soc.c
+++ b/drivers/usb/host/ehci-ppc-soc.c
@@ -163,6 +163,7 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = {
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
.relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
};
static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index 69782221bcf3..37e6abeb794c 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -73,6 +73,7 @@ static const struct hc_driver ps3_ehci_hc_driver = {
.bus_resume = ehci_bus_resume,
#endif
.relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
};
static int ps3_ehci_probe(struct ps3_system_bus_device *dev)
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index be575e46eac3..b7853c8bac0f 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1349,18 +1349,27 @@ iso_stream_schedule (
/* when's the last uframe this urb could start? */
max = now + mod;
- /* typical case: reuse current schedule. stream is still active,
- * and no gaps from host falling behind (irq delays etc)
+ /* Typical case: reuse current schedule, stream is still active.
+ * Hopefully there are no gaps from the host falling behind
+ * (irq delays etc), but if there are we'll take the next
+ * slot in the schedule, implicitly assuming URB_ISO_ASAP.
*/
if (likely (!list_empty (&stream->td_list))) {
start = stream->next_uframe;
if (start < now)
start += mod;
- if (likely ((start + sched->span) < max))
- goto ready;
- /* else fell behind; someday, try to reschedule */
- status = -EL2NSYNC;
- goto fail;
+
+ /* Fell behind (by up to twice the slop amount)? */
+ if (start >= max - 2 * 8 * SCHEDULE_SLOP)
+ start += stream->interval * DIV_ROUND_UP(
+ max - start, stream->interval) - mod;
+
+ /* Tried to schedule too far into the future? */
+ if (unlikely((start + sched->span) >= max)) {
+ status = -EFBIG;
+ goto fail;
+ }
+ goto ready;
}
/* need to schedule; when's the next (u)frame we could start?
@@ -1613,6 +1622,9 @@ itd_complete (
} else if (likely ((t & EHCI_ISOC_ACTIVE) == 0)) {
desc->status = 0;
desc->actual_length = EHCI_ITD_LENGTH (t);
+ } else {
+ /* URB was too late */
+ desc->status = -EXDEV;
}
}
@@ -2095,7 +2107,7 @@ done:
static void
scan_periodic (struct ehci_hcd *ehci)
{
- unsigned frame, clock, now_uframe, mod;
+ unsigned now_uframe, frame, clock, clock_frame, mod;
unsigned modified;
mod = ehci->periodic_size << 3;
@@ -2111,6 +2123,7 @@ scan_periodic (struct ehci_hcd *ehci)
else
clock = now_uframe + mod - 1;
clock %= mod;
+ clock_frame = clock >> 3;
for (;;) {
union ehci_shadow q, *q_p;
@@ -2157,22 +2170,26 @@ restart:
case Q_TYPE_ITD:
/* If this ITD is still active, leave it for
* later processing ... check the next entry.
+ * No need to check for activity unless the
+ * frame is current.
*/
- rmb ();
- for (uf = 0; uf < 8 && live; uf++) {
- if (0 == (q.itd->hw_transaction [uf]
- & ITD_ACTIVE(ehci)))
- continue;
- incomplete = true;
- q_p = &q.itd->itd_next;
- hw_p = &q.itd->hw_next;
- type = Q_NEXT_TYPE(ehci,
+ if (frame == clock_frame && live) {
+ rmb();
+ for (uf = 0; uf < 8; uf++) {
+ if (q.itd->hw_transaction[uf] &
+ ITD_ACTIVE(ehci))
+ break;
+ }
+ if (uf < 8) {
+ incomplete = true;
+ q_p = &q.itd->itd_next;
+ hw_p = &q.itd->hw_next;
+ type = Q_NEXT_TYPE(ehci,
q.itd->hw_next);
- q = *q_p;
- break;
+ q = *q_p;
+ break;
+ }
}
- if (uf < 8 && live)
- break;
/* Take finished ITDs out of the schedule
* and process them: recycle, maybe report
@@ -2189,9 +2206,12 @@ restart:
case Q_TYPE_SITD:
/* If this SITD is still active, leave it for
* later processing ... check the next entry.
+ * No need to check for activity unless the
+ * frame is current.
*/
- if ((q.sitd->hw_results & SITD_ACTIVE(ehci))
- && live) {
+ if (frame == clock_frame && live &&
+ (q.sitd->hw_results &
+ SITD_ACTIVE(ehci))) {
incomplete = true;
q_p = &q.sitd->sitd_next;
hw_p = &q.sitd->hw_next;
@@ -2260,6 +2280,7 @@ restart:
/* rescan the rest of this frame, then ... */
clock = now;
+ clock_frame = clock >> 3;
} else {
now_uframe++;
now_uframe %= mod;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index bf92d209a1a9..90245fd8bac4 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -97,6 +97,8 @@ struct ehci_hcd { /* one per controller */
dedicated to the companion controller */
unsigned long owned_ports; /* which ports are
owned by the companion during a bus suspend */
+ unsigned long port_c_suspend; /* which ports have
+ the change-suspend feature turned on */
/* per-HC memory pools (could be per-bus, but ...) */
struct dma_pool *qh_pool; /* qh per active urb */
@@ -112,7 +114,6 @@ struct ehci_hcd { /* one per controller */
u32 command;
/* SILICON QUIRKS */
- unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */
unsigned no_selective_suspend:1;
unsigned has_fsl_port_bug:1; /* FreeScale */
unsigned big_endian_mmio:1;
@@ -176,6 +177,15 @@ timer_action_done (struct ehci_hcd *ehci, enum ehci_timer_action action)
static inline void
timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
{
+ /* Don't override timeouts which shrink or (later) disable
+ * the async ring; just the I/O watchdog. Note that if a
+ * SHRINK were pending, OFF would never be requested.
+ */
+ if (timer_pending(&ehci->watchdog)
+ && ((BIT(TIMER_ASYNC_SHRINK) | BIT(TIMER_ASYNC_OFF))
+ & ehci->actions))
+ return;
+
if (!test_and_set_bit (action, &ehci->actions)) {
unsigned long t;
@@ -191,15 +201,7 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
t = EHCI_SHRINK_JIFFIES;
break;
}
- t += jiffies;
- // all timings except IAA watchdog can be overridden.
- // async queue SHRINK often precedes IAA. while it's ready
- // to go OFF neither can matter, and afterwards the IO
- // watchdog stops unless there's still periodic traffic.
- if (time_before_eq(t, ehci->watchdog.expires)
- && timer_pending (&ehci->watchdog))
- return;
- mod_timer (&ehci->watchdog, t);
+ mod_timer(&ehci->watchdog, t + jiffies);
}
}
@@ -678,7 +680,7 @@ struct ehci_fstn {
* needed (mostly in root hub code).
*/
-#define ehci_is_TDI(e) ((e)->is_tdi_rh_tt)
+#define ehci_is_TDI(e) (ehci_to_hcd(e)->has_tt)
/* Returns the speed of a device attached to a port on the root hub. */
static inline unsigned int
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index c9cec8738261..65aa5ecf569a 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -2207,14 +2207,14 @@ struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq,
goto err_put;
}
- ret = usb_add_hcd(hcd, irq, irqflags);
- if (ret)
- goto err_unmap;
-
hcd->irq = irq;
hcd->rsrc_start = res_start;
hcd->rsrc_len = res_len;
+ ret = usb_add_hcd(hcd, irq, irqflags);
+ if (ret)
+ goto err_unmap;
+
return hcd;
err_unmap:
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
index 440bf94f0d4c..c9db3fe98726 100644
--- a/drivers/usb/host/isp1760-if.c
+++ b/drivers/usb/host/isp1760-if.c
@@ -104,8 +104,8 @@ static u32 nxp_pci_io_base;
static u32 iolength;
static u32 pci_mem_phy0;
static u32 length;
-static u8 *chip_addr;
-static u8 *iobase;
+static u8 __iomem *chip_addr;
+static u8 __iomem *iobase;
static int __devinit isp1761_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index c96db1153dcf..e534f9de0f05 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -261,6 +261,7 @@ static const struct hc_driver ohci_at91_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index 1b9abdba920b..68c17f5ea8ea 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -8,7 +8,7 @@
* Bus Glue for AMD Alchemy Au1xxx
*
* Written by Christopher Hoover <ch@hpl.hp.com>
- * Based on fragments of previous driver by Rusell King et al.
+ * Based on fragments of previous driver by Russell King et al.
*
* Modified for LH7A404 from ohci-sa1111.c
* by Durgesh Pattamatta <pattamattad@sharpsec.com>
@@ -288,6 +288,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index 06aadfb0ec29..5adaf36e47d0 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -135,6 +135,7 @@ static struct hc_driver ohci_ep93xx_hc_driver = {
.get_frame_number = ohci_get_frame,
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 33f1c1c32edf..a8160d65f32b 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1054,7 +1054,7 @@ MODULE_LICENSE ("GPL");
#ifdef CONFIG_MFD_SM501
#include "ohci-sm501.c"
-#define PLATFORM_DRIVER ohci_hcd_sm501_driver
+#define SM501_OHCI_DRIVER ohci_hcd_sm501_driver
#endif
#if !defined(PCI_DRIVER) && \
@@ -1062,6 +1062,7 @@ MODULE_LICENSE ("GPL");
!defined(OF_PLATFORM_DRIVER) && \
!defined(SA1111_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && \
+ !defined(SM501_OHCI_DRIVER) && \
!defined(SSB_OHCI_DRIVER)
#error "missing bus glue for ohci-hcd"
#endif
@@ -1121,9 +1122,18 @@ static int __init ohci_hcd_mod_init(void)
goto error_ssb;
#endif
+#ifdef SM501_OHCI_DRIVER
+ retval = platform_driver_register(&SM501_OHCI_DRIVER);
+ if (retval < 0)
+ goto error_sm501;
+#endif
+
return retval;
/* Error path */
+#ifdef SM501_OHCI_DRIVER
+ error_sm501:
+#endif
#ifdef SSB_OHCI_DRIVER
error_ssb:
#endif
@@ -1159,6 +1169,9 @@ module_init(ohci_hcd_mod_init);
static void __exit ohci_hcd_mod_exit(void)
{
+#ifdef SM501_OHCI_DRIVER
+ platform_driver_unregister(&SM501_OHCI_DRIVER);
+#endif
#ifdef SSB_OHCI_DRIVER
ssb_driver_unregister(&SSB_OHCI_DRIVER);
#endif
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 79a78029f896..b56739221d11 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -36,6 +36,18 @@
/*-------------------------------------------------------------------------*/
+/* hcd->hub_irq_enable() */
+static void ohci_rhsc_enable (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+ spin_lock_irq(&ohci->lock);
+ if (!ohci->autostop)
+ del_timer(&hcd->rh_timer); /* Prevent next poll */
+ ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
+ spin_unlock_irq(&ohci->lock);
+}
+
#define OHCI_SCHED_ENABLES \
(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
@@ -362,28 +374,18 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
int any_connected)
{
int poll_rh = 1;
- int rhsc;
- rhsc = ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC;
switch (ohci->hc_control & OHCI_CTRL_HCFS) {
case OHCI_USB_OPER:
- /* If no status changes are pending, enable status-change
- * interrupts.
- */
- if (!rhsc && !changed) {
- rhsc = OHCI_INTR_RHSC;
- ohci_writel(ohci, rhsc, &ohci->regs->intrenable);
- }
-
- /* Keep on polling until we know a device is connected
- * and RHSC is enabled, or until we autostop.
- */
+ /* keep on polling until we know a device is connected
+ * and RHSC is enabled */
if (!ohci->autostop) {
if (any_connected ||
!device_may_wakeup(&ohci_to_hcd(ohci)
->self.root_hub->dev)) {
- if (rhsc)
+ if (ohci_readl(ohci, &ohci->regs->intrenable) &
+ OHCI_INTR_RHSC)
poll_rh = 0;
} else {
ohci->autostop = 1;
@@ -396,13 +398,12 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
ohci->autostop = 0;
ohci->next_statechange = jiffies +
STATECHANGE_DELAY;
- } else if (rhsc && time_after_eq(jiffies,
+ } else if (time_after_eq(jiffies,
ohci->next_statechange)
&& !ohci->ed_rm_list
&& !(ohci->hc_control &
OHCI_SCHED_ENABLES)) {
ohci_rh_suspend(ohci, 1);
- poll_rh = 0;
}
}
break;
@@ -416,12 +417,6 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
else
usb_hcd_resume_root_hub(ohci_to_hcd(ohci));
} else {
- if (!rhsc && (ohci->autostop ||
- ohci_to_hcd(ohci)->self.root_hub->
- do_remote_wakeup))
- ohci_writel(ohci, OHCI_INTR_RHSC,
- &ohci->regs->intrenable);
-
/* everything is idle, no need for polling */
poll_rh = 0;
}
@@ -443,16 +438,12 @@ static inline int ohci_rh_resume(struct ohci_hcd *ohci)
static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
int any_connected)
{
- /* If RHSC is enabled, don't poll */
- if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
- return 0;
+ int poll_rh = 1;
- /* If no status changes are pending, enable status-change interrupts */
- if (!changed) {
- ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
- return 0;
- }
- return 1;
+ /* keep on polling until RHSC is enabled */
+ if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
+ poll_rh = 0;
+ return poll_rh;
}
#endif /* CONFIG_PM */
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
index 96d14fa1d833..1ef5d482c145 100644
--- a/drivers/usb/host/ohci-lh7a404.c
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -8,7 +8,7 @@
* Bus Glue for Sharp LH7A404
*
* Written by Christopher Hoover <ch@hpl.hp.com>
- * Based on fragments of previous driver by Rusell King et al.
+ * Based on fragments of previous driver by Russell King et al.
*
* Modified for LH7A404 from ohci-sa1111.c
* by Durgesh Pattamatta <pattamattad@sharpsec.com>
@@ -193,6 +193,7 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 6859fb5f1d6f..3a7c24c03671 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -466,6 +466,7 @@ static const struct hc_driver ohci_omap_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 3bf175d95a23..4696cc912e16 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -327,6 +327,7 @@ static const struct hc_driver ohci_pci_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
index 664f07ee8732..28b458f20cc3 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -280,6 +280,7 @@ static const struct hc_driver ohci_pnx4008_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c
index 28467e288a93..605d59cba28e 100644
--- a/drivers/usb/host/ohci-pnx8550.c
+++ b/drivers/usb/host/ohci-pnx8550.c
@@ -201,6 +201,7 @@ static const struct hc_driver ohci_pnx8550_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index 50e55db13636..a67252791223 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -72,6 +72,7 @@ static const struct hc_driver ohci_ppc_of_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index cd3398b675b2..523c30125577 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -172,6 +172,7 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
index bfdeb0d22d05..c1935ae537f8 100644
--- a/drivers/usb/host/ohci-ps3.c
+++ b/drivers/usb/host/ohci-ps3.c
@@ -68,6 +68,7 @@ static const struct hc_driver ps3_ohci_hc_driver = {
.get_frame_number = ohci_get_frame,
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
.start_port_reset = ohci_start_port_reset,
#if defined(CONFIG_PM)
.bus_suspend = ohci_bus_suspend,
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 70b0d4b459e7..d4ee27d92be8 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -298,6 +298,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index 9c9f3b59186f..9b547407c934 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -952,6 +952,7 @@ rescan_this:
struct urb *urb;
urb_priv_t *urb_priv;
__hc32 savebits;
+ u32 tdINFO;
td = list_entry (entry, struct td, td_list);
urb = td->urb;
@@ -966,6 +967,17 @@ rescan_this:
savebits = *prev & ~cpu_to_hc32 (ohci, TD_MASK);
*prev = td->hwNextTD | savebits;
+ /* If this was unlinked, the TD may not have been
+ * retired ... so manually save the data toggle.
+ * The controller ignores the value we save for
+ * control and ISO endpoints.
+ */
+ tdINFO = hc32_to_cpup(ohci, &td->hwINFO);
+ if ((tdINFO & TD_T) == TD_T_DATA0)
+ ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_C);
+ else if ((tdINFO & TD_T) == TD_T_DATA1)
+ ed->hwHeadP |= cpu_to_hc32(ohci, ED_C);
+
/* HC may have partly processed this TD */
td_done (ohci, urb, td);
urb_priv->td_cnt++;
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index a73d2ff322e2..3c7a740cfe0c 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -8,7 +8,7 @@
* USB Bus Glue for Samsung S3C2410
*
* Written by Christopher Hoover <ch@hpl.hp.com>
- * Based on fragments of previous driver by Rusell King et al.
+ * Based on fragments of previous driver by Russell King et al.
*
* Modified for S3C2410 from ohci-sa1111.c, ohci-omap.c and ohci-lh7a40.c
* by Ben Dooks, <ben@simtec.co.uk>
@@ -466,6 +466,7 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
*/
.hub_status_data = ohci_s3c2410_hub_status_data,
.hub_control = ohci_s3c2410_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index 99438c65981b..2e9dceb9bb99 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -8,7 +8,7 @@
* SA1111 Bus Glue
*
* Written by Christopher Hoover <ch@hpl.hp.com>
- * Based on fragments of previous driver by Rusell King et al.
+ * Based on fragments of previous driver by Russell King et al.
*
* This file is licenced under the GPL.
*/
@@ -231,6 +231,7 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c
index 60f03cc7ec4f..e7ee607278fe 100644
--- a/drivers/usb/host/ohci-sh.c
+++ b/drivers/usb/host/ohci-sh.c
@@ -68,6 +68,7 @@ static const struct hc_driver ohci_sh_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c
index e899a77dfb83..e610698c6b60 100644
--- a/drivers/usb/host/ohci-sm501.c
+++ b/drivers/usb/host/ohci-sm501.c
@@ -75,6 +75,7 @@ static const struct hc_driver ohci_sm501_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
index c4265caec780..7275186db315 100644
--- a/drivers/usb/host/ohci-ssb.c
+++ b/drivers/usb/host/ohci-ssb.c
@@ -81,6 +81,7 @@ static const struct hc_driver ssb_ohci_hc_driver = {
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index f29307405bb3..9b6323f768b2 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -2934,6 +2934,16 @@ static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num)
return 0;
}
+static void u132_hub_irq_enable(struct usb_hcd *hcd)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ } else if (u132->going > 0)
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+}
+
#ifdef CONFIG_PM
static int u132_bus_suspend(struct usb_hcd *hcd)
@@ -2985,6 +2995,7 @@ static struct hc_driver u132_hc_driver = {
.bus_suspend = u132_bus_suspend,
.bus_resume = u132_bus_resume,
.start_port_reset = u132_start_port_reset,
+ .hub_irq_enable = u132_hub_irq_enable,
};
/*
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index a53db1d4e07a..001789c9a11a 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -269,3 +269,15 @@ config USB_TEST
See <http://www.linux-usb.org/usbtest/> for more information,
including sample test device firmware and "how to use it".
+config USB_ISIGHTFW
+ tristate "iSight firmware loading support"
+ depends on USB
+ select FW_LOADER
+ help
+ This driver loads firmware for USB Apple iSight cameras, allowing
+ them to be driven by the USB video class driver available at
+ http://linux-uvc.berlios.de
+
+ The firmware for this driver must be extracted from the MacOS
+ driver beforehand. Tools for doing so are available at
+ http://bersace03.free.fr
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index b68e6b774f1a..aba091cb5ec0 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_EMI62) += emi62.o
obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o
obj-$(CONFIG_USB_IDMOUSE) += idmouse.o
obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o
+obj-$(CONFIG_USB_ISIGHTFW) += isight_firmware.o
obj-$(CONFIG_USB_LCD) += usblcd.o
obj-$(CONFIG_USB_LD) += ldusb.o
obj-$(CONFIG_USB_LED) += usbled.o
diff --git a/drivers/usb/misc/isight_firmware.c b/drivers/usb/misc/isight_firmware.c
new file mode 100644
index 000000000000..9f30aa1f8a5d
--- /dev/null
+++ b/drivers/usb/misc/isight_firmware.c
@@ -0,0 +1,140 @@
+/*
+ * Driver for loading USB isight firmware
+ *
+ * Copyright (C) 2008 Matthew Garrett <mjg@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ * The USB isight cameras in recent Apples are roughly compatible with the USB
+ * video class specification, and can be driven by uvcvideo. However, they
+ * need firmware to be loaded beforehand. After firmware loading, the device
+ * detaches from the USB bus and reattaches with a new device ID. It can then
+ * be claimed by the uvc driver.
+ *
+ * The firmware is non-free and must be extracted by the user. Tools to do this
+ * are available at http://bersace03.free.fr/ift/
+ *
+ * The isight firmware loading was reverse engineered by Johannes Berg
+ * <johannes@sipsolutions.de>, and this driver is based on code by Ronald
+ * Bultje <rbultje@ronald.bitfreak.net>
+ */
+
+#include <linux/usb.h>
+#include <linux/firmware.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+
+static struct usb_device_id id_table[] = {
+ {USB_DEVICE(0x05ac, 0x8300)},
+ {},
+};
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static int isight_firmware_load(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ int llen, len, req, ret = 0;
+ const struct firmware *firmware;
+ unsigned char *buf = kmalloc(50, GFP_KERNEL);
+ unsigned char data[4];
+ u8 *ptr;
+
+ if (!buf)
+ return -ENOMEM;
+
+ if (request_firmware(&firmware, "isight.fw", &dev->dev) != 0) {
+ printk(KERN_ERR "Unable to load isight firmware\n");
+ return -ENODEV;
+ }
+
+ ptr = firmware->data;
+
+ if (usb_control_msg
+ (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\1", 1,
+ 300) != 1) {
+ printk(KERN_ERR
+ "Failed to initialise isight firmware loader\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ while (ptr+4 <= firmware->data+firmware->size) {
+ memcpy(data, ptr, 4);
+ len = (data[0] << 8 | data[1]);
+ req = (data[2] << 8 | data[3]);
+ ptr += 4;
+
+ if (len == 0x8001)
+ break; /* success */
+ else if (len == 0)
+ continue;
+
+ for (; len > 0; req += 50) {
+ llen = min(len, 50);
+ len -= llen;
+ if (ptr+llen > firmware->data+firmware->size) {
+ printk(KERN_ERR
+ "Malformed isight firmware");
+ ret = -ENODEV;
+ goto out;
+ }
+ memcpy(buf, ptr, llen);
+
+ ptr += llen;
+
+ if (usb_control_msg
+ (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, req, 0,
+ buf, llen, 300) != llen) {
+ printk(KERN_ERR
+ "Failed to load isight firmware\n");
+ kfree(buf);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ }
+ }
+
+ if (usb_control_msg
+ (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\0", 1,
+ 300) != 1) {
+ printk(KERN_ERR "isight firmware loading completion failed\n");
+ ret = -ENODEV;
+ }
+
+out:
+ kfree(buf);
+ release_firmware(firmware);
+ return ret;
+}
+
+static void isight_firmware_disconnect(struct usb_interface *intf)
+{
+}
+
+static struct usb_driver isight_firmware_driver = {
+ .name = "isight_firmware",
+ .probe = isight_firmware_load,
+ .disconnect = isight_firmware_disconnect,
+ .id_table = id_table,
+};
+
+static int __init isight_firmware_init(void)
+{
+ return usb_register(&isight_firmware_driver);
+}
+
+static void __exit isight_firmware_exit(void)
+{
+ usb_deregister(&isight_firmware_driver);
+}
+
+module_init(isight_firmware_init);
+module_exit(isight_firmware_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c
index 24230c638b8e..4cfa25b0f44e 100644
--- a/drivers/usb/misc/phidgetkit.c
+++ b/drivers/usb/misc/phidgetkit.c
@@ -595,14 +595,14 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
} while(value);
kit->dev_no = bit;
- kit->dev = device_create(phidget_class, &kit->udev->dev, 0,
- "interfacekit%d", kit->dev_no);
+ kit->dev = device_create_drvdata(phidget_class, &kit->udev->dev,
+ MKDEV(0, 0), kit,
+ "interfacekit%d", kit->dev_no);
if (IS_ERR(kit->dev)) {
rc = PTR_ERR(kit->dev);
kit->dev = NULL;
goto out;
}
- dev_set_drvdata(kit->dev, kit);
if (usb_submit_urb(kit->irq, GFP_KERNEL)) {
rc = -EIO;
diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c
index f0113c17cc5a..9b4696f21b22 100644
--- a/drivers/usb/misc/phidgetmotorcontrol.c
+++ b/drivers/usb/misc/phidgetmotorcontrol.c
@@ -365,16 +365,15 @@ static int motorcontrol_probe(struct usb_interface *intf, const struct usb_devic
} while(value);
mc->dev_no = bit;
- mc->dev = device_create(phidget_class, &mc->udev->dev, 0,
- "motorcontrol%d", mc->dev_no);
+ mc->dev = device_create_drvdata(phidget_class, &mc->udev->dev,
+ MKDEV(0, 0), mc,
+ "motorcontrol%d", mc->dev_no);
if (IS_ERR(mc->dev)) {
rc = PTR_ERR(mc->dev);
mc->dev = NULL;
goto out;
}
- dev_set_drvdata(mc->dev, mc);
-
if (usb_submit_urb(mc->irq, GFP_KERNEL)) {
rc = -EIO;
goto out;
diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c
index 7d590c09434a..1ca7ddb41d4d 100644
--- a/drivers/usb/misc/phidgetservo.c
+++ b/drivers/usb/misc/phidgetservo.c
@@ -275,14 +275,14 @@ servo_probe(struct usb_interface *interface, const struct usb_device_id *id)
} while (value);
dev->dev_no = bit;
- dev->dev = device_create(phidget_class, &dev->udev->dev, 0,
- "servo%d", dev->dev_no);
+ dev->dev = device_create_drvdata(phidget_class, &dev->udev->dev,
+ MKDEV(0, 0), dev,
+ "servo%d", dev->dev_no);
if (IS_ERR(dev->dev)) {
rc = PTR_ERR(dev->dev);
dev->dev = NULL;
goto out;
}
- dev_set_drvdata(dev->dev, dev);
servo_count = dev->type & SERVO_COUNT_QUAD ? 4 : 1;
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index cb7fa0eaf3ae..33182f4c2267 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -3264,8 +3264,6 @@ static void sisusb_disconnect(struct usb_interface *intf)
/* decrement our usage count */
kref_put(&sisusb->kref, sisusb_delete);
-
- dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n");
}
static struct usb_device_id sisusb_table [] = {
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index ba28fdc9ccd2..1f7c86bd8297 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -28,6 +28,7 @@ static int debug;
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x4348, 0x5523) },
+ { USB_DEVICE(0x1a86, 0x7523) },
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 5b349ece7247..0ff4a3971e45 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -174,8 +174,270 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) },
- { USB_DEVICE(MTXORB_VK_VID, MTXORB_VK_PID),
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0100_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0101_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0102_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0103_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0104_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0105_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0106_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0107_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0108_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0109_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_010A_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_010B_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_010C_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_010D_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_010E_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_010F_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0110_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0111_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0112_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0113_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0114_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0115_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0116_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0117_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0118_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0119_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_011A_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_011B_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_011C_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_011D_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_011E_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_011F_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0120_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0121_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0122_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0123_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0124_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0125_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0126_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0127_PID),
.driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0128_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0129_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_012A_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_012B_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_012C_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_012D_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_012E_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_012F_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0130_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0131_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0132_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0133_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0134_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0135_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0136_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0137_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0138_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0139_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_013A_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_013B_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_013C_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_013D_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_013E_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_013F_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0140_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0141_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0142_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0143_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0144_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0145_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0146_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0147_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0148_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0149_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_014A_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_014B_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_014C_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_014D_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_014E_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_014F_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0150_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0151_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0152_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0153_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0154_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0155_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0156_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0157_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0158_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0159_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_015A_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_015B_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_015C_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_015D_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_015E_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_015F_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0160_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0161_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0162_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0163_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0164_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0165_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0166_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0167_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0168_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0169_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_016A_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_016B_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_016C_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_016D_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_016E_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_016F_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0170_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0171_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0172_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0173_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0174_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0175_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0176_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0177_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0178_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0179_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_017A_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_017B_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_017C_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_017D_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_017E_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_017F_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0180_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0181_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0182_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0183_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0184_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0185_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0186_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0187_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0188_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0189_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_018A_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_018B_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_018C_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_018D_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_018E_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_018F_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0190_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0191_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0192_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0193_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0194_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0195_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0196_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0197_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0198_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_0199_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_019A_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_019B_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_019C_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_019D_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_019E_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_019F_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A0_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A1_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A2_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A3_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A4_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A5_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A6_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A7_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A8_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01A9_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01AA_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01AB_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01AC_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01AD_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01AE_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01AF_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B0_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B1_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B2_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B3_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B4_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B5_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B6_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B7_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B8_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01B9_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01BA_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01BB_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01BC_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01BD_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01BE_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01BF_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C0_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C1_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C2_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C3_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C4_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C5_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C6_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C7_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C8_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01C9_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01CA_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01CB_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01CC_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01CD_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01CE_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01CF_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D0_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D1_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D2_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D3_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D4_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D5_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D6_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D7_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D8_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01D9_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01DA_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01DB_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01DC_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01DD_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01DE_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01DF_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E0_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E1_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E2_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E3_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E4_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E5_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E6_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E7_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E8_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01E9_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01EA_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01EB_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01EC_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01ED_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01EE_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01EF_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F0_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F1_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F2_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F3_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F4_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F5_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F6_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F7_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F8_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01F9_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01FA_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01FB_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01FC_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01FD_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01FE_PID) },
+ { USB_DEVICE(MTXORB_VID,MTXORB_FTDI_RANGE_01FF_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) },
@@ -374,6 +636,8 @@ static struct usb_device_id id_table_combined [] = {
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
+ { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 504edf8c3a3f..8302eca893ea 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -114,11 +114,268 @@
#define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */
/*
- * The following are the values for the Matrix Orbital VK204-25-USB
- * display, which use the FT232RL.
- */
-#define MTXORB_VK_VID 0x1b3d
-#define MTXORB_VK_PID 0x0158
+ * The following are the values for the Matrix Orbital FTDI Range
+ * Anything in this range will use an FT232RL.
+ */
+#define MTXORB_VID 0x1B3D
+#define MTXORB_FTDI_RANGE_0100_PID 0x0100
+#define MTXORB_FTDI_RANGE_0101_PID 0x0101
+#define MTXORB_FTDI_RANGE_0102_PID 0x0102
+#define MTXORB_FTDI_RANGE_0103_PID 0x0103
+#define MTXORB_FTDI_RANGE_0104_PID 0x0104
+#define MTXORB_FTDI_RANGE_0105_PID 0x0105
+#define MTXORB_FTDI_RANGE_0106_PID 0x0106
+#define MTXORB_FTDI_RANGE_0107_PID 0x0107
+#define MTXORB_FTDI_RANGE_0108_PID 0x0108
+#define MTXORB_FTDI_RANGE_0109_PID 0x0109
+#define MTXORB_FTDI_RANGE_010A_PID 0x010A
+#define MTXORB_FTDI_RANGE_010B_PID 0x010B
+#define MTXORB_FTDI_RANGE_010C_PID 0x010C
+#define MTXORB_FTDI_RANGE_010D_PID 0x010D
+#define MTXORB_FTDI_RANGE_010E_PID 0x010E
+#define MTXORB_FTDI_RANGE_010F_PID 0x010F
+#define MTXORB_FTDI_RANGE_0110_PID 0x0110
+#define MTXORB_FTDI_RANGE_0111_PID 0x0111
+#define MTXORB_FTDI_RANGE_0112_PID 0x0112
+#define MTXORB_FTDI_RANGE_0113_PID 0x0113
+#define MTXORB_FTDI_RANGE_0114_PID 0x0114
+#define MTXORB_FTDI_RANGE_0115_PID 0x0115
+#define MTXORB_FTDI_RANGE_0116_PID 0x0116
+#define MTXORB_FTDI_RANGE_0117_PID 0x0117
+#define MTXORB_FTDI_RANGE_0118_PID 0x0118
+#define MTXORB_FTDI_RANGE_0119_PID 0x0119
+#define MTXORB_FTDI_RANGE_011A_PID 0x011A
+#define MTXORB_FTDI_RANGE_011B_PID 0x011B
+#define MTXORB_FTDI_RANGE_011C_PID 0x011C
+#define MTXORB_FTDI_RANGE_011D_PID 0x011D
+#define MTXORB_FTDI_RANGE_011E_PID 0x011E
+#define MTXORB_FTDI_RANGE_011F_PID 0x011F
+#define MTXORB_FTDI_RANGE_0120_PID 0x0120
+#define MTXORB_FTDI_RANGE_0121_PID 0x0121
+#define MTXORB_FTDI_RANGE_0122_PID 0x0122
+#define MTXORB_FTDI_RANGE_0123_PID 0x0123
+#define MTXORB_FTDI_RANGE_0124_PID 0x0124
+#define MTXORB_FTDI_RANGE_0125_PID 0x0125
+#define MTXORB_FTDI_RANGE_0126_PID 0x0126
+#define MTXORB_FTDI_RANGE_0127_PID 0x0127
+#define MTXORB_FTDI_RANGE_0128_PID 0x0128
+#define MTXORB_FTDI_RANGE_0129_PID 0x0129
+#define MTXORB_FTDI_RANGE_012A_PID 0x012A
+#define MTXORB_FTDI_RANGE_012B_PID 0x012B
+#define MTXORB_FTDI_RANGE_012C_PID 0x012C
+#define MTXORB_FTDI_RANGE_012D_PID 0x012D
+#define MTXORB_FTDI_RANGE_012E_PID 0x012E
+#define MTXORB_FTDI_RANGE_012F_PID 0x012F
+#define MTXORB_FTDI_RANGE_0130_PID 0x0130
+#define MTXORB_FTDI_RANGE_0131_PID 0x0131
+#define MTXORB_FTDI_RANGE_0132_PID 0x0132
+#define MTXORB_FTDI_RANGE_0133_PID 0x0133
+#define MTXORB_FTDI_RANGE_0134_PID 0x0134
+#define MTXORB_FTDI_RANGE_0135_PID 0x0135
+#define MTXORB_FTDI_RANGE_0136_PID 0x0136
+#define MTXORB_FTDI_RANGE_0137_PID 0x0137
+#define MTXORB_FTDI_RANGE_0138_PID 0x0138
+#define MTXORB_FTDI_RANGE_0139_PID 0x0139
+#define MTXORB_FTDI_RANGE_013A_PID 0x013A
+#define MTXORB_FTDI_RANGE_013B_PID 0x013B
+#define MTXORB_FTDI_RANGE_013C_PID 0x013C
+#define MTXORB_FTDI_RANGE_013D_PID 0x013D
+#define MTXORB_FTDI_RANGE_013E_PID 0x013E
+#define MTXORB_FTDI_RANGE_013F_PID 0x013F
+#define MTXORB_FTDI_RANGE_0140_PID 0x0140
+#define MTXORB_FTDI_RANGE_0141_PID 0x0141
+#define MTXORB_FTDI_RANGE_0142_PID 0x0142
+#define MTXORB_FTDI_RANGE_0143_PID 0x0143
+#define MTXORB_FTDI_RANGE_0144_PID 0x0144
+#define MTXORB_FTDI_RANGE_0145_PID 0x0145
+#define MTXORB_FTDI_RANGE_0146_PID 0x0146
+#define MTXORB_FTDI_RANGE_0147_PID 0x0147
+#define MTXORB_FTDI_RANGE_0148_PID 0x0148
+#define MTXORB_FTDI_RANGE_0149_PID 0x0149
+#define MTXORB_FTDI_RANGE_014A_PID 0x014A
+#define MTXORB_FTDI_RANGE_014B_PID 0x014B
+#define MTXORB_FTDI_RANGE_014C_PID 0x014C
+#define MTXORB_FTDI_RANGE_014D_PID 0x014D
+#define MTXORB_FTDI_RANGE_014E_PID 0x014E
+#define MTXORB_FTDI_RANGE_014F_PID 0x014F
+#define MTXORB_FTDI_RANGE_0150_PID 0x0150
+#define MTXORB_FTDI_RANGE_0151_PID 0x0151
+#define MTXORB_FTDI_RANGE_0152_PID 0x0152
+#define MTXORB_FTDI_RANGE_0153_PID 0x0153
+#define MTXORB_FTDI_RANGE_0154_PID 0x0154
+#define MTXORB_FTDI_RANGE_0155_PID 0x0155
+#define MTXORB_FTDI_RANGE_0156_PID 0x0156
+#define MTXORB_FTDI_RANGE_0157_PID 0x0157
+#define MTXORB_FTDI_RANGE_0158_PID 0x0158
+#define MTXORB_FTDI_RANGE_0159_PID 0x0159
+#define MTXORB_FTDI_RANGE_015A_PID 0x015A
+#define MTXORB_FTDI_RANGE_015B_PID 0x015B
+#define MTXORB_FTDI_RANGE_015C_PID 0x015C
+#define MTXORB_FTDI_RANGE_015D_PID 0x015D
+#define MTXORB_FTDI_RANGE_015E_PID 0x015E
+#define MTXORB_FTDI_RANGE_015F_PID 0x015F
+#define MTXORB_FTDI_RANGE_0160_PID 0x0160
+#define MTXORB_FTDI_RANGE_0161_PID 0x0161
+#define MTXORB_FTDI_RANGE_0162_PID 0x0162
+#define MTXORB_FTDI_RANGE_0163_PID 0x0163
+#define MTXORB_FTDI_RANGE_0164_PID 0x0164
+#define MTXORB_FTDI_RANGE_0165_PID 0x0165
+#define MTXORB_FTDI_RANGE_0166_PID 0x0166
+#define MTXORB_FTDI_RANGE_0167_PID 0x0167
+#define MTXORB_FTDI_RANGE_0168_PID 0x0168
+#define MTXORB_FTDI_RANGE_0169_PID 0x0169
+#define MTXORB_FTDI_RANGE_016A_PID 0x016A
+#define MTXORB_FTDI_RANGE_016B_PID 0x016B
+#define MTXORB_FTDI_RANGE_016C_PID 0x016C
+#define MTXORB_FTDI_RANGE_016D_PID 0x016D
+#define MTXORB_FTDI_RANGE_016E_PID 0x016E
+#define MTXORB_FTDI_RANGE_016F_PID 0x016F
+#define MTXORB_FTDI_RANGE_0170_PID 0x0170
+#define MTXORB_FTDI_RANGE_0171_PID 0x0171
+#define MTXORB_FTDI_RANGE_0172_PID 0x0172
+#define MTXORB_FTDI_RANGE_0173_PID 0x0173
+#define MTXORB_FTDI_RANGE_0174_PID 0x0174
+#define MTXORB_FTDI_RANGE_0175_PID 0x0175
+#define MTXORB_FTDI_RANGE_0176_PID 0x0176
+#define MTXORB_FTDI_RANGE_0177_PID 0x0177
+#define MTXORB_FTDI_RANGE_0178_PID 0x0178
+#define MTXORB_FTDI_RANGE_0179_PID 0x0179
+#define MTXORB_FTDI_RANGE_017A_PID 0x017A
+#define MTXORB_FTDI_RANGE_017B_PID 0x017B
+#define MTXORB_FTDI_RANGE_017C_PID 0x017C
+#define MTXORB_FTDI_RANGE_017D_PID 0x017D
+#define MTXORB_FTDI_RANGE_017E_PID 0x017E
+#define MTXORB_FTDI_RANGE_017F_PID 0x017F
+#define MTXORB_FTDI_RANGE_0180_PID 0x0180
+#define MTXORB_FTDI_RANGE_0181_PID 0x0181
+#define MTXORB_FTDI_RANGE_0182_PID 0x0182
+#define MTXORB_FTDI_RANGE_0183_PID 0x0183
+#define MTXORB_FTDI_RANGE_0184_PID 0x0184
+#define MTXORB_FTDI_RANGE_0185_PID 0x0185
+#define MTXORB_FTDI_RANGE_0186_PID 0x0186
+#define MTXORB_FTDI_RANGE_0187_PID 0x0187
+#define MTXORB_FTDI_RANGE_0188_PID 0x0188
+#define MTXORB_FTDI_RANGE_0189_PID 0x0189
+#define MTXORB_FTDI_RANGE_018A_PID 0x018A
+#define MTXORB_FTDI_RANGE_018B_PID 0x018B
+#define MTXORB_FTDI_RANGE_018C_PID 0x018C
+#define MTXORB_FTDI_RANGE_018D_PID 0x018D
+#define MTXORB_FTDI_RANGE_018E_PID 0x018E
+#define MTXORB_FTDI_RANGE_018F_PID 0x018F
+#define MTXORB_FTDI_RANGE_0190_PID 0x0190
+#define MTXORB_FTDI_RANGE_0191_PID 0x0191
+#define MTXORB_FTDI_RANGE_0192_PID 0x0192
+#define MTXORB_FTDI_RANGE_0193_PID 0x0193
+#define MTXORB_FTDI_RANGE_0194_PID 0x0194
+#define MTXORB_FTDI_RANGE_0195_PID 0x0195
+#define MTXORB_FTDI_RANGE_0196_PID 0x0196
+#define MTXORB_FTDI_RANGE_0197_PID 0x0197
+#define MTXORB_FTDI_RANGE_0198_PID 0x0198
+#define MTXORB_FTDI_RANGE_0199_PID 0x0199
+#define MTXORB_FTDI_RANGE_019A_PID 0x019A
+#define MTXORB_FTDI_RANGE_019B_PID 0x019B
+#define MTXORB_FTDI_RANGE_019C_PID 0x019C
+#define MTXORB_FTDI_RANGE_019D_PID 0x019D
+#define MTXORB_FTDI_RANGE_019E_PID 0x019E
+#define MTXORB_FTDI_RANGE_019F_PID 0x019F
+#define MTXORB_FTDI_RANGE_01A0_PID 0x01A0
+#define MTXORB_FTDI_RANGE_01A1_PID 0x01A1
+#define MTXORB_FTDI_RANGE_01A2_PID 0x01A2
+#define MTXORB_FTDI_RANGE_01A3_PID 0x01A3
+#define MTXORB_FTDI_RANGE_01A4_PID 0x01A4
+#define MTXORB_FTDI_RANGE_01A5_PID 0x01A5
+#define MTXORB_FTDI_RANGE_01A6_PID 0x01A6
+#define MTXORB_FTDI_RANGE_01A7_PID 0x01A7
+#define MTXORB_FTDI_RANGE_01A8_PID 0x01A8
+#define MTXORB_FTDI_RANGE_01A9_PID 0x01A9
+#define MTXORB_FTDI_RANGE_01AA_PID 0x01AA
+#define MTXORB_FTDI_RANGE_01AB_PID 0x01AB
+#define MTXORB_FTDI_RANGE_01AC_PID 0x01AC
+#define MTXORB_FTDI_RANGE_01AD_PID 0x01AD
+#define MTXORB_FTDI_RANGE_01AE_PID 0x01AE
+#define MTXORB_FTDI_RANGE_01AF_PID 0x01AF
+#define MTXORB_FTDI_RANGE_01B0_PID 0x01B0
+#define MTXORB_FTDI_RANGE_01B1_PID 0x01B1
+#define MTXORB_FTDI_RANGE_01B2_PID 0x01B2
+#define MTXORB_FTDI_RANGE_01B3_PID 0x01B3
+#define MTXORB_FTDI_RANGE_01B4_PID 0x01B4
+#define MTXORB_FTDI_RANGE_01B5_PID 0x01B5
+#define MTXORB_FTDI_RANGE_01B6_PID 0x01B6
+#define MTXORB_FTDI_RANGE_01B7_PID 0x01B7
+#define MTXORB_FTDI_RANGE_01B8_PID 0x01B8
+#define MTXORB_FTDI_RANGE_01B9_PID 0x01B9
+#define MTXORB_FTDI_RANGE_01BA_PID 0x01BA
+#define MTXORB_FTDI_RANGE_01BB_PID 0x01BB
+#define MTXORB_FTDI_RANGE_01BC_PID 0x01BC
+#define MTXORB_FTDI_RANGE_01BD_PID 0x01BD
+#define MTXORB_FTDI_RANGE_01BE_PID 0x01BE
+#define MTXORB_FTDI_RANGE_01BF_PID 0x01BF
+#define MTXORB_FTDI_RANGE_01C0_PID 0x01C0
+#define MTXORB_FTDI_RANGE_01C1_PID 0x01C1
+#define MTXORB_FTDI_RANGE_01C2_PID 0x01C2
+#define MTXORB_FTDI_RANGE_01C3_PID 0x01C3
+#define MTXORB_FTDI_RANGE_01C4_PID 0x01C4
+#define MTXORB_FTDI_RANGE_01C5_PID 0x01C5
+#define MTXORB_FTDI_RANGE_01C6_PID 0x01C6
+#define MTXORB_FTDI_RANGE_01C7_PID 0x01C7
+#define MTXORB_FTDI_RANGE_01C8_PID 0x01C8
+#define MTXORB_FTDI_RANGE_01C9_PID 0x01C9
+#define MTXORB_FTDI_RANGE_01CA_PID 0x01CA
+#define MTXORB_FTDI_RANGE_01CB_PID 0x01CB
+#define MTXORB_FTDI_RANGE_01CC_PID 0x01CC
+#define MTXORB_FTDI_RANGE_01CD_PID 0x01CD
+#define MTXORB_FTDI_RANGE_01CE_PID 0x01CE
+#define MTXORB_FTDI_RANGE_01CF_PID 0x01CF
+#define MTXORB_FTDI_RANGE_01D0_PID 0x01D0
+#define MTXORB_FTDI_RANGE_01D1_PID 0x01D1
+#define MTXORB_FTDI_RANGE_01D2_PID 0x01D2
+#define MTXORB_FTDI_RANGE_01D3_PID 0x01D3
+#define MTXORB_FTDI_RANGE_01D4_PID 0x01D4
+#define MTXORB_FTDI_RANGE_01D5_PID 0x01D5
+#define MTXORB_FTDI_RANGE_01D6_PID 0x01D6
+#define MTXORB_FTDI_RANGE_01D7_PID 0x01D7
+#define MTXORB_FTDI_RANGE_01D8_PID 0x01D8
+#define MTXORB_FTDI_RANGE_01D9_PID 0x01D9
+#define MTXORB_FTDI_RANGE_01DA_PID 0x01DA
+#define MTXORB_FTDI_RANGE_01DB_PID 0x01DB
+#define MTXORB_FTDI_RANGE_01DC_PID 0x01DC
+#define MTXORB_FTDI_RANGE_01DD_PID 0x01DD
+#define MTXORB_FTDI_RANGE_01DE_PID 0x01DE
+#define MTXORB_FTDI_RANGE_01DF_PID 0x01DF
+#define MTXORB_FTDI_RANGE_01E0_PID 0x01E0
+#define MTXORB_FTDI_RANGE_01E1_PID 0x01E1
+#define MTXORB_FTDI_RANGE_01E2_PID 0x01E2
+#define MTXORB_FTDI_RANGE_01E3_PID 0x01E3
+#define MTXORB_FTDI_RANGE_01E4_PID 0x01E4
+#define MTXORB_FTDI_RANGE_01E5_PID 0x01E5
+#define MTXORB_FTDI_RANGE_01E6_PID 0x01E6
+#define MTXORB_FTDI_RANGE_01E7_PID 0x01E7
+#define MTXORB_FTDI_RANGE_01E8_PID 0x01E8
+#define MTXORB_FTDI_RANGE_01E9_PID 0x01E9
+#define MTXORB_FTDI_RANGE_01EA_PID 0x01EA
+#define MTXORB_FTDI_RANGE_01EB_PID 0x01EB
+#define MTXORB_FTDI_RANGE_01EC_PID 0x01EC
+#define MTXORB_FTDI_RANGE_01ED_PID 0x01ED
+#define MTXORB_FTDI_RANGE_01EE_PID 0x01EE
+#define MTXORB_FTDI_RANGE_01EF_PID 0x01EF
+#define MTXORB_FTDI_RANGE_01F0_PID 0x01F0
+#define MTXORB_FTDI_RANGE_01F1_PID 0x01F1
+#define MTXORB_FTDI_RANGE_01F2_PID 0x01F2
+#define MTXORB_FTDI_RANGE_01F3_PID 0x01F3
+#define MTXORB_FTDI_RANGE_01F4_PID 0x01F4
+#define MTXORB_FTDI_RANGE_01F5_PID 0x01F5
+#define MTXORB_FTDI_RANGE_01F6_PID 0x01F6
+#define MTXORB_FTDI_RANGE_01F7_PID 0x01F7
+#define MTXORB_FTDI_RANGE_01F8_PID 0x01F8
+#define MTXORB_FTDI_RANGE_01F9_PID 0x01F9
+#define MTXORB_FTDI_RANGE_01FA_PID 0x01FA
+#define MTXORB_FTDI_RANGE_01FB_PID 0x01FB
+#define MTXORB_FTDI_RANGE_01FC_PID 0x01FC
+#define MTXORB_FTDI_RANGE_01FD_PID 0x01FD
+#define MTXORB_FTDI_RANGE_01FE_PID 0x01FE
+#define MTXORB_FTDI_RANGE_01FF_PID 0x01FF
+
+
/* Interbiometrics USB I/O Board */
/* Developed for Interbiometrics by Rudolf Gugler */
@@ -571,6 +828,9 @@
/* Propox devices */
#define FTDI_PROPOX_JTAGCABLEII_PID 0xD738
+/* Rig Expert Ukraine devices */
+#define FTDI_REU_TINY_PID 0xED22 /* RigExpert Tiny */
+
/* Commands */
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
@@ -592,6 +852,12 @@
#define FIC_NEO1973_DEBUG_PID 0x5118
/*
+ * RATOC REX-USB60F
+ */
+#define RATOC_VENDOR_ID 0x0584
+#define RATOC_PRODUCT_ID_USB60F 0xb020
+
+/*
* BmRequestType: 1100 0000b
* bRequest: FTDI_E2_READ
* wValue: 0
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index ea924dc48496..d9fb3768a2d7 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -570,7 +570,12 @@ static struct usb_serial_driver ipaq_device = {
.description = "PocketPC PDA",
.usb_driver = &ipaq_driver,
.id_table = ipaq_id_table,
- .num_ports = 2,
+ /*
+ * some devices have an extra endpoint, which
+ * must be ignored as it would make the core
+ * create a second port which oopses when used
+ */
+ .num_ports = 1,
.open = ipaq_open,
.close = ipaq_close,
.attach = ipaq_startup,
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index e7e016e60333..a73420dd052a 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -183,6 +183,7 @@ static int option_send_setup(struct usb_serial_port *port);
#define AXESSTEL_PRODUCT_MV110H 0x1000
#define ONDA_VENDOR_ID 0x19d2
+#define ONDA_PRODUCT_MSA501HS 0x0001
#define ONDA_PRODUCT_ET502HS 0x0002
#define BANDRICH_VENDOR_ID 0x1A8D
@@ -196,6 +197,9 @@ static int option_send_setup(struct usb_serial_port *port);
#define MAXON_VENDOR_ID 0x16d8
+#define TELIT_VENDOR_ID 0x1bc7
+#define TELIT_PRODUCT_UC864E 0x1003
+
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -232,25 +236,25 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_EX) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_MODEM) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_NETWORK) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS, 0xff, 0xff, 0xff) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1401) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1403) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1405) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1406) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1408) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1409) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1410) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1411) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1412) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1413) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1414) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1415) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1416) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1417) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1418) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1419) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1401, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1403, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1405, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1406, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1408, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1409, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1410, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1411, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1412, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1413, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1414, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1415, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1416, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1417, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1418, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1419, 0xff, 0xff, 0xff) },
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_9508) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, /* Novatel Merlin V640/XV620 */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) }, /* Novatel Merlin V620/S620 */
@@ -297,13 +301,15 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
{ USB_DEVICE(AXESSTEL_VENDOR_ID, AXESSTEL_PRODUCT_MV110H) },
+ { USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_MSA501HS) },
{ USB_DEVICE(ONDA_VENDOR_ID, ONDA_PRODUCT_ET502HS) },
{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) },
{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) },
{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) },
+ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
{ USB_DEVICE(MAXON_VENDOR_ID, 0x6280) }, /* BP3-USB & BP3-EXT HSDPA */
- { USB_DEVICE(0x19d2, 0x0001) }, /* Telstra NextG CDMA */
+ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index c605fb68f807..2a0dd1b50dc4 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -56,6 +56,8 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
+ { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
+ { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
@@ -66,7 +68,6 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
- { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index 10cf872e5ecb..6ac3bbcf7a22 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -14,6 +14,8 @@
#define PL2303_PRODUCT_ID_PHAROS 0xaaa0
#define PL2303_PRODUCT_ID_RSAQ3 0xaaa2
#define PL2303_PRODUCT_ID_ALDIGA 0x0611
+#define PL2303_PRODUCT_ID_MMX 0x0612
+#define PL2303_PRODUCT_ID_GPRS 0x0609
#define ATEN_VENDOR_ID 0x0557
#define ATEN_VENDOR_ID2 0x0547
@@ -36,7 +38,6 @@
#define RATOC_VENDOR_ID 0x0584
#define RATOC_PRODUCT_ID 0xb000
-#define RATOC_PRODUCT_ID_USB60F 0xb020
#define TRIPP_VENDOR_ID 0x2478
#define TRIPP_PRODUCT_ID 0x2008
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 1b09578cbb10..39a7c11795c4 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -402,10 +402,18 @@ UNUSUAL_DEV( 0x04a5, 0x3010, 0x0100, 0x0100,
US_FL_IGNORE_RESIDUE ),
#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+/* CY7C68300 : support atacb */
UNUSUAL_DEV( 0x04b4, 0x6830, 0x0000, 0x9999,
"Cypress",
"Cypress AT2LP",
- US_SC_CYP_ATACB, US_PR_BULK, NULL,
+ US_SC_CYP_ATACB, US_PR_DEVICE, NULL,
+ 0),
+
+/* CY7C68310 : support atacb and atacb2 */
+UNUSUAL_DEV( 0x04b4, 0x6831, 0x0000, 0x9999,
+ "Cypress",
+ "Cypress ISD-300LP",
+ US_SC_CYP_ATACB, US_PR_DEVICE, NULL,
0),
#endif
@@ -1522,7 +1530,7 @@ UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000,
"Sony Ericsson",
"M600i",
US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
+ US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
/* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
* Tested on hardware version 1.10.
@@ -1716,10 +1724,12 @@ UNUSUAL_DEV( 0x22b8, 0x3010, 0x0001, 0x0001,
/*
* Patch by Pete Zaitcev <zaitcev@redhat.com>
* Report by Mark Patton. Red Hat bz#208928.
+ * Added support for rev 0x0002 (Motorola ROKR W5)
+ * by Javier Smaldone <javier@smaldone.com.ar>
*/
-UNUSUAL_DEV( 0x22b8, 0x4810, 0x0001, 0x0001,
+UNUSUAL_DEV( 0x22b8, 0x4810, 0x0001, 0x0002,
"Motorola",
- "RAZR V3i",
+ "RAZR V3i/ROKR W5",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY),
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 002b61b4f0f6..e0c5f96b273d 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1825,12 +1825,13 @@ config FB_FSL_DIU
config FB_W100
tristate "W100 frame buffer support"
- depends on FB && PXA_SHARPSL
+ depends on FB && ARCH_PXA
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
---help---
Frame buffer driver for the w100 as found on the Sharp SL-Cxx series.
+ It can also drive the w3220 chip found on iPAQ hx4700.
This driver is also available as a module ( = code which can be
inserted and removed from the running kernel whenever you want). The
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index e4bcf5376a99..bd4ac0bafecb 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -3356,7 +3356,7 @@ static int __devinit atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *i
info->fix.mmio_start = raddr;
par->ati_regbase = ioremap(info->fix.mmio_start, 0x1000);
- if (par->ati_regbase == 0)
+ if (par->ati_regbase == NULL)
return -ENOMEM;
info->fix.mmio_start += par->aux_start ? 0x400 : 0xc00;
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 72cd0d2f14ec..400e9264e456 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -2277,8 +2277,8 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
do {
rinfo->fb_base = ioremap (rinfo->fb_base_phys,
rinfo->mapped_vram);
- } while ( rinfo->fb_base == 0 &&
- ((rinfo->mapped_vram /=2) >= MIN_MAPPED_VRAM) );
+ } while (rinfo->fb_base == NULL &&
+ ((rinfo->mapped_vram /= 2) >= MIN_MAPPED_VRAM));
if (rinfo->fb_base == NULL) {
printk (KERN_ERR "radeonfb (%s): cannot map FB\n",
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
index 35ac9d956b3d..c14b2435d23e 100644
--- a/drivers/video/cirrusfb.c
+++ b/drivers/video/cirrusfb.c
@@ -2432,9 +2432,9 @@ static int cirrusfb_pci_register(struct pci_dev *pdev,
info->screen_size = board_size;
cinfo->unmap = cirrusfb_pci_unmap;
- printk(KERN_INFO " RAM (%lu kB) at 0xx%lx, ",
- info->screen_size >> 10, board_addr);
- printk(KERN_INFO "Cirrus Logic chipset on PCI bus\n");
+ printk(KERN_INFO "RAM (%lu kB) at 0x%lx, Cirrus "
+ "Logic chipset on PCI bus\n",
+ info->screen_size >> 10, board_addr);
pci_set_drvdata(pdev, info);
ret = cirrusfb_register(info);
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 5fa8b76673cb..97aff8db10bf 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -2275,9 +2275,7 @@ static int fbcon_switch(struct vc_data *vc)
* in fb_set_var()
*/
info->var.activate = var.activate;
- var.yoffset = info->var.yoffset;
- var.xoffset = info->var.xoffset;
- var.vmode = info->var.vmode;
+ var.vmode |= info->var.vmode & ~FB_VMODE_MASK;
fb_set_var(info, &var);
ops->var = info->var;
diff --git a/drivers/video/display/display-sysfs.c b/drivers/video/display/display-sysfs.c
index 35477177bef4..6ef800bdf482 100644
--- a/drivers/video/display/display-sysfs.c
+++ b/drivers/video/display/display-sysfs.c
@@ -26,6 +26,7 @@
#include <linux/ctype.h>
#include <linux/idr.h>
#include <linux/err.h>
+#include <linux/kdev_t.h>
static ssize_t display_show_name(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -152,10 +153,13 @@ struct display_device *display_device_register(struct display_driver *driver,
mutex_unlock(&allocated_dsp_lock);
if (!ret) {
- new_dev->dev = device_create(display_class, parent, 0,
- "display%d", new_dev->idx);
+ new_dev->dev = device_create_drvdata(display_class,
+ parent,
+ MKDEV(0,0),
+ new_dev,
+ "display%d",
+ new_dev->idx);
if (!IS_ERR(new_dev->dev)) {
- dev_set_drvdata(new_dev->dev, new_dev);
new_dev->parent = parent;
new_dev->driver = driver;
mutex_init(&new_dev->lock);
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
index 24843fdd5395..59df132cc375 100644
--- a/drivers/video/fb_defio.c
+++ b/drivers/video/fb_defio.c
@@ -74,6 +74,7 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
{
struct fb_info *info = vma->vm_private_data;
struct fb_deferred_io *fbdefio = info->fbdefio;
+ struct page *cur;
/* this is a callback we get when userspace first tries to
write to the page. we schedule a workqueue. that workqueue
@@ -83,7 +84,24 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
/* protect against the workqueue changing the page list */
mutex_lock(&fbdefio->lock);
- list_add(&page->lru, &fbdefio->pagelist);
+
+ /* we loop through the pagelist before adding in order
+ to keep the pagelist sorted */
+ list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+ /* this check is to catch the case where a new
+ process could start writing to the same page
+ through a new pte. this new access can cause the
+ mkwrite even when the original ps's pte is marked
+ writable */
+ if (unlikely(cur == page))
+ goto page_already_added;
+ else if (cur->index > page->index)
+ break;
+ }
+
+ list_add_tail(&page->lru, &cur->lru);
+
+page_already_added:
mutex_unlock(&fbdefio->lock);
/* come back after delay to process the deferred IO */
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index b50bb03cb5ab..09d7e22c6fef 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -286,7 +286,7 @@ static struct diu_pool pool;
* rheap and make the furture large allocation fail.
*/
-void *fsl_diu_alloc(unsigned long size, phys_addr_t *phys)
+static void *fsl_diu_alloc(unsigned long size, phys_addr_t *phys)
{
void *virt;
@@ -311,12 +311,12 @@ void *fsl_diu_alloc(unsigned long size, phys_addr_t *phys)
memset(virt, 0, size);
}
- pr_debug("rh virt=%p phys=%lx\n", virt, *phys);
+ pr_debug("rh virt=%p phys=%llx\n", virt, (unsigned long long)*phys);
return virt;
}
-void fsl_diu_free(void *p, unsigned long size)
+static void fsl_diu_free(void *p, unsigned long size)
{
pr_debug("p=%p size=%lu\n", p, size);
@@ -770,7 +770,7 @@ static int map_video_memory(struct fb_info *info)
info->fix.smem_len = info->fix.line_length * info->var.yres_virtual;
pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len);
info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys);
- if (info->screen_base == 0) {
+ if (info->screen_base == NULL) {
printk(KERN_ERR "Unable to allocate fb memory\n");
return -ENOMEM;
}
@@ -788,7 +788,7 @@ static int map_video_memory(struct fb_info *info)
static void unmap_video_memory(struct fb_info *info)
{
fsl_diu_free(info->screen_base, info->fix.smem_len);
- info->screen_base = 0;
+ info->screen_base = NULL;
info->fix.smem_start = 0;
info->fix.smem_len = 0;
}
@@ -1158,7 +1158,7 @@ static int init_fbinfo(struct fb_info *info)
return 0;
}
-static int install_fb(struct fb_info *info)
+static int __devinit install_fb(struct fb_info *info)
{
int rc;
struct mfb_info *mfbi = info->par;
@@ -1233,7 +1233,7 @@ static int install_fb(struct fb_info *info)
return 0;
}
-static void __exit uninstall_fb(struct fb_info *info)
+static void uninstall_fb(struct fb_info *info)
{
struct mfb_info *mfbi = info->par;
@@ -1287,7 +1287,7 @@ static int request_irq_local(int irq)
/* Read to clear the status */
status = in_be32(&hw->int_status);
- ret = request_irq(irq, fsl_diu_isr, 0, "diu", 0);
+ ret = request_irq(irq, fsl_diu_isr, 0, "diu", NULL);
if (ret)
pr_info("Request diu IRQ failed.\n");
else {
@@ -1312,7 +1312,7 @@ static void free_irq_local(int irq)
/* Disable all LCDC interrupt */
out_be32(&hw->int_mask, 0x1f);
- free_irq(irq, 0);
+ free_irq(irq, NULL);
}
#ifdef CONFIG_PM
@@ -1320,7 +1320,7 @@ static void free_irq_local(int irq)
* Power management hooks. Note that we won't be called from IRQ context,
* unlike the blank functions above, so we may sleep.
*/
-static int fsl_diu_suspend(struct of_device *dev, pm_message_t state)
+static int fsl_diu_suspend(struct of_device *ofdev, pm_message_t state)
{
struct fsl_diu_data *machine_data;
@@ -1330,7 +1330,7 @@ static int fsl_diu_suspend(struct of_device *dev, pm_message_t state)
return 0;
}
-static int fsl_diu_resume(struct of_device *dev)
+static int fsl_diu_resume(struct of_device *ofdev)
{
struct fsl_diu_data *machine_data;
@@ -1353,7 +1353,8 @@ static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
dma_addr_t paddr = 0;
ssize = size + bytes_align;
- buf->vaddr = dma_alloc_coherent(0, ssize, &paddr, GFP_DMA | __GFP_ZERO);
+ buf->vaddr = dma_alloc_coherent(NULL, ssize, &paddr, GFP_DMA |
+ __GFP_ZERO);
if (!buf->vaddr)
return -ENOMEM;
@@ -1371,7 +1372,7 @@ static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
static void free_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
{
- dma_free_coherent(0, size + bytes_align,
+ dma_free_coherent(NULL, size + bytes_align,
buf->vaddr, (buf->paddr - buf->offset));
return;
}
@@ -1411,7 +1412,7 @@ static ssize_t show_monitor(struct device *device,
return diu_ops.show_monitor_port(machine_data->monitor_port, buf);
}
-static int fsl_diu_probe(struct of_device *ofdev,
+static int __devinit fsl_diu_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
struct device_node *np = ofdev->node;
diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c
index fb9e67228543..c18880d9db1f 100644
--- a/drivers/video/hgafb.c
+++ b/drivers/video/hgafb.c
@@ -279,7 +279,7 @@ static void hga_blank(int blank_mode)
static int __init hga_card_detect(void)
{
- int count=0;
+ int count = 0;
void __iomem *p, *q;
unsigned short p_save, q_save;
@@ -303,20 +303,18 @@ static int __init hga_card_detect(void)
writew(0x55aa, p); if (readw(p) == 0x55aa) count++;
writew(p_save, p);
- if (count != 2) {
- return 0;
- }
+ if (count != 2)
+ goto error;
/* Ok, there is definitely a card registering at the correct
* memory location, so now we do an I/O port test.
*/
- if (!test_hga_b(0x66, 0x0f)) { /* cursor low register */
- return 0;
- }
- if (!test_hga_b(0x99, 0x0f)) { /* cursor low register */
- return 0;
- }
+ if (!test_hga_b(0x66, 0x0f)) /* cursor low register */
+ goto error;
+
+ if (!test_hga_b(0x99, 0x0f)) /* cursor low register */
+ goto error;
/* See if the card is a Hercules, by checking whether the vsync
* bit of the status register is changing. This test lasts for
@@ -331,7 +329,7 @@ static int __init hga_card_detect(void)
}
if (p_save == q_save)
- return 0;
+ goto error;
switch (inb_p(HGA_STATUS_PORT) & 0x70) {
case 0x10:
@@ -348,6 +346,12 @@ static int __init hga_card_detect(void)
break;
}
return 1;
+error:
+ if (release_io_ports)
+ release_region(0x3b0, 12);
+ if (release_io_port)
+ release_region(0x3bf, 1);
+ return 0;
}
/**
diff --git a/drivers/video/leo.c b/drivers/video/leo.c
index 8bc46e930340..13fea61d6ae4 100644
--- a/drivers/video/leo.c
+++ b/drivers/video/leo.c
@@ -17,8 +17,8 @@
#include <linux/fb.h>
#include <linux/mm.h>
#include <linux/of_device.h>
+#include <linux/io.h>
-#include <asm/io.h>
#include <asm/fbio.h>
#include "sbuslib.h"
@@ -33,7 +33,6 @@ static int leo_blank(int, struct fb_info *);
static int leo_mmap(struct fb_info *, struct vm_area_struct *);
static int leo_ioctl(struct fb_info *, unsigned int, unsigned long);
-static int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *);
/*
* Frame buffer operations
@@ -43,7 +42,6 @@ static struct fb_ops leo_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = leo_setcolreg,
.fb_blank = leo_blank,
- .fb_pan_display = leo_pan_display,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
@@ -78,7 +76,7 @@ static struct fb_ops leo_ops = {
#define LEO_CUR_TYPE_CMAP 0x00000050
struct leo_cursor {
- u8 xxx0[16];
+ u8 xxx0[16];
u32 cur_type;
u32 cur_misc;
u32 cur_cursxy;
@@ -105,7 +103,7 @@ struct leo_lx_krn {
struct leo_lc_ss0_krn {
u32 misc;
- u8 xxx0[0x800-4];
+ u8 xxx0[0x800-4];
u32 rev;
};
@@ -116,7 +114,7 @@ struct leo_lc_ss0_usr {
u32 fontt;
u32 extent;
u32 src;
- u32 dst;
+ u32 dst;
u32 copy;
u32 fill;
};
@@ -129,8 +127,8 @@ struct leo_lc_ss1_usr {
u8 unknown;
};
-struct leo_ld {
- u8 xxx0[0xe00];
+struct leo_ld_ss0 {
+ u8 xxx0[0xe00];
u32 csr;
u32 wid;
u32 wmask;
@@ -144,13 +142,13 @@ struct leo_ld {
u32 src; /* Copy/Scroll (SS0 only) */
u32 dst; /* Copy/Scroll/Fill (SS0 only) */
u32 extent; /* Copy/Scroll/Fill size (SS0 only) */
- u32 xxx1[3];
+ u32 xxx1[3];
u32 setsem; /* SS1 only */
u32 clrsem; /* SS1 only */
u32 clrpick; /* SS1 only */
u32 clrdat; /* SS1 only */
u32 alpha; /* SS1 only */
- u8 xxx2[0x2c];
+ u8 xxx2[0x2c];
u32 winbg;
u32 planemask;
u32 rop;
@@ -199,11 +197,12 @@ struct leo_par {
static void leo_wait(struct leo_lx_krn __iomem *lx_krn)
{
int i;
-
+
for (i = 0;
- (sbus_readl(&lx_krn->krn_csr) & LEO_KRN_CSR_PROGRESS) && i < 300000;
+ (sbus_readl(&lx_krn->krn_csr) & LEO_KRN_CSR_PROGRESS) &&
+ i < 300000;
i++)
- udelay (1); /* Busy wait at most 0.3 sec */
+ udelay(1); /* Busy wait at most 0.3 sec */
return;
}
@@ -221,7 +220,7 @@ static int leo_setcolreg(unsigned regno,
unsigned transp, struct fb_info *info)
{
struct leo_par *par = (struct leo_par *) info->par;
- struct leo_lx_krn __iomem *lx_krn = par->lx_krn;
+ struct leo_lx_krn __iomem *lx_krn = par->lx_krn;
unsigned long flags;
u32 val;
int i;
@@ -408,7 +407,7 @@ static void leo_wid_put(struct fb_info *info, struct fb_wid_list *wl)
leo_wait(lx_krn);
for (i = 0, wi = wl->wl_list; i < wl->wl_count; i++, wi++) {
- switch(wi->wi_type) {
+ switch (wi->wi_type) {
case FB_WID_DBL_8:
j = (wi->wi_index & 0xf) + 0x40;
break;
@@ -453,13 +452,12 @@ static void leo_init_wids(struct fb_info *info)
wi.wi_index = 1;
wi.wi_values [0] = 0x30;
leo_wid_put(info, &wl);
-
}
static void leo_switch_from_graph(struct fb_info *info)
{
struct leo_par *par = (struct leo_par *) info->par;
- struct leo_ld __iomem *ss = (struct leo_ld __iomem *) par->ld_ss0;
+ struct leo_ld_ss0 __iomem *ss = par->ld_ss0;
unsigned long flags;
u32 val;
@@ -485,19 +483,13 @@ static void leo_switch_from_graph(struct fb_info *info)
val = sbus_readl(&par->lc_ss0_usr->csr);
} while (val & 0x20000000);
- spin_unlock_irqrestore(&par->lock, flags);
-}
-
-static int leo_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
-{
- /* We just use this to catch switches out of
- * graphics mode.
- */
- leo_switch_from_graph(info);
+ /* setup screen buffer for cfb_* functions */
+ sbus_writel(1, &ss->wid);
+ sbus_writel(0x00ffffff, &ss->planemask);
+ sbus_writel(0x310b90, &ss->rop);
+ sbus_writel(0, &par->lc_ss0_usr->addrspace);
- if (var->xoffset || var->yoffset || var->vmode)
- return -EINVAL;
- return 0;
+ spin_unlock_irqrestore(&par->lock, flags);
}
static void leo_init_hw(struct fb_info *info)
@@ -542,7 +534,8 @@ static void leo_unmap_regs(struct of_device *op, struct fb_info *info,
of_iounmap(&op->resource[0], info->screen_base, 0x800000);
}
-static int __devinit leo_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit leo_probe(struct of_device *op,
+ const struct of_device_id *match)
{
struct device_node *dp = op->node;
struct fb_info *info;
@@ -594,8 +587,9 @@ static int __devinit leo_probe(struct of_device *op, const struct of_device_id *
!info->screen_base)
goto out_unmap_regs;
- info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+ info->flags = FBINFO_DEFAULT;
info->fbops = &leo_ops;
+ info->pseudo_palette = par->clut_data;
leo_init_wids(info);
leo_init_hw(info);
@@ -649,7 +643,7 @@ static int __devexit leo_remove(struct of_device *op)
static struct of_device_id leo_match[] = {
{
- .name = "leo",
+ .name = "SUNW,leo",
},
{},
};
diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h
index f3107ad7e545..95883236c0cd 100644
--- a/drivers/video/matrox/matroxfb_base.h
+++ b/drivers/video/matrox/matroxfb_base.h
@@ -200,7 +200,7 @@ static inline int mga_ioremap(unsigned long phys, unsigned long size, int flags,
virt->vaddr = ioremap_nocache(phys, size);
else
virt->vaddr = ioremap(phys, size);
- return (virt->vaddr == 0); /* 0, !0... 0, error_code in future */
+ return (virt->vaddr == NULL); /* 0, !0... 0, error_code in future */
}
static inline void mga_iounmap(vaddr_t va) {
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 473562191586..d3c3af53a290 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -28,6 +28,7 @@
#endif
const char *fb_mode_option;
+EXPORT_SYMBOL_GPL(fb_mode_option);
/*
* Standard video mode definitions (taken from XFree86)
@@ -590,6 +591,7 @@ done:
"", (margins) ? " with margins" : "", (interlace) ?
" interlaced" : "");
+ memset(&cvt_mode, 0, sizeof(cvt_mode));
cvt_mode.xres = xres;
cvt_mode.yres = yres;
cvt_mode.refresh = (refresh) ? refresh : 60;
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 3ee314beacc1..fafe7db20d6d 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -573,8 +573,8 @@ static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal,
dma_desc->fdadr = fbi->dma_buff_phys + dma_desc_off;
fbi->fdadr[dma] = fbi->dma_buff_phys + dma_desc_off;
} else {
- pal_desc = &fbi->dma_buff->pal_desc[dma];
- pal_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[pal]);
+ pal_desc = &fbi->dma_buff->pal_desc[pal];
+ pal_desc_off = offsetof(struct pxafb_dma_buff, pal_desc[pal]);
pal_desc->fsadr = fbi->dma_buff_phys + pal * PALETTE_SIZE;
pal_desc->fidr = 0;
@@ -1246,7 +1246,7 @@ static int pxafb_resume(struct platform_device *dev)
* cache. Once this area is remapped, all virtual memory
* access to the video memory should occur at the new region.
*/
-static int __init pxafb_map_video_memory(struct pxafb_info *fbi)
+static int __devinit pxafb_map_video_memory(struct pxafb_info *fbi)
{
/*
* We reserve one page for the palette, plus the size
@@ -1276,6 +1276,8 @@ static int __init pxafb_map_video_memory(struct pxafb_info *fbi)
fbi->dma_buff_phys = fbi->map_dma;
fbi->palette_cpu = (u16 *) fbi->dma_buff->palette;
+ pr_debug("pxafb: palette_mem_size = 0x%08lx\n", fbi->palette_size*sizeof(u16));
+
#ifdef CONFIG_FB_PXA_SMARTPANEL
fbi->smart_cmds = (uint16_t *) fbi->dma_buff->cmd_buff;
fbi->n_smart_cmds = 0;
@@ -1346,12 +1348,11 @@ decode_mode:
pxafb_decode_mode_info(fbi, inf->modes, inf->num_modes);
}
-static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
+static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev)
{
struct pxafb_info *fbi;
void *addr;
struct pxafb_mach_info *inf = dev->platform_data;
- struct pxafb_mode_info *mode = inf->modes;
/* Alloc the pxafb_info and pseudo_palette in one step */
fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL);
@@ -1409,7 +1410,7 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
}
#ifdef CONFIG_FB_PXA_PARAMETERS
-static int __init parse_opt_mode(struct device *dev, const char *this_opt)
+static int __devinit parse_opt_mode(struct device *dev, const char *this_opt)
{
struct pxafb_mach_info *inf = dev->platform_data;
@@ -1468,7 +1469,7 @@ done:
return 0;
}
-static int __init parse_opt(struct device *dev, char *this_opt)
+static int __devinit parse_opt(struct device *dev, char *this_opt)
{
struct pxafb_mach_info *inf = dev->platform_data;
struct pxafb_mode_info *mode = &inf->modes[0];
@@ -1566,7 +1567,7 @@ static int __init parse_opt(struct device *dev, char *this_opt)
return 0;
}
-static int __init pxafb_parse_options(struct device *dev, char *options)
+static int __devinit pxafb_parse_options(struct device *dev, char *options)
{
char *this_opt;
int ret;
@@ -1587,8 +1588,8 @@ static int __init pxafb_parse_options(struct device *dev, char *options)
static char g_options[256] __devinitdata = "";
-#ifndef CONFIG_MODULES
-static int __devinit pxafb_setup_options(void)
+#ifndef MODULE
+static int __init pxafb_setup_options(void)
{
char *options = NULL;
@@ -1612,7 +1613,7 @@ MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");
#define pxafb_setup_options() (0)
#endif
-static int __init pxafb_probe(struct platform_device *dev)
+static int __devinit pxafb_probe(struct platform_device *dev)
{
struct pxafb_info *fbi;
struct pxafb_mach_info *inf;
@@ -1684,14 +1685,14 @@ static int __init pxafb_probe(struct platform_device *dev)
if (r == NULL) {
dev_err(&dev->dev, "no I/O memory resource defined\n");
ret = -ENODEV;
- goto failed;
+ goto failed_fbi;
}
r = request_mem_region(r->start, r->end - r->start + 1, dev->name);
if (r == NULL) {
dev_err(&dev->dev, "failed to request I/O memory\n");
ret = -EBUSY;
- goto failed;
+ goto failed_fbi;
}
fbi->mmio_base = ioremap(r->start, r->end - r->start + 1);
@@ -1734,8 +1735,17 @@ static int __init pxafb_probe(struct platform_device *dev)
* This makes sure that our colour bitfield
* descriptors are correctly initialised.
*/
- pxafb_check_var(&fbi->fb.var, &fbi->fb);
- pxafb_set_par(&fbi->fb);
+ ret = pxafb_check_var(&fbi->fb.var, &fbi->fb);
+ if (ret) {
+ dev_err(&dev->dev, "failed to get suitable mode\n");
+ goto failed_free_irq;
+ }
+
+ ret = pxafb_set_par(&fbi->fb);
+ if (ret) {
+ dev_err(&dev->dev, "Failed to set parameters\n");
+ goto failed_free_irq;
+ }
platform_set_drvdata(dev, fbi);
@@ -1743,7 +1753,7 @@ static int __init pxafb_probe(struct platform_device *dev)
if (ret < 0) {
dev_err(&dev->dev,
"Failed to register framebuffer device: %d\n", ret);
- goto failed_free_irq;
+ goto failed_free_cmap;
}
#ifdef CONFIG_CPU_FREQ
@@ -1762,18 +1772,23 @@ static int __init pxafb_probe(struct platform_device *dev)
return 0;
+failed_free_cmap:
+ if (fbi->fb.cmap.len)
+ fb_dealloc_cmap(&fbi->fb.cmap);
failed_free_irq:
free_irq(irq, fbi);
-failed_free_res:
- release_mem_region(r->start, r->end - r->start + 1);
-failed_free_io:
- iounmap(fbi->mmio_base);
failed_free_mem:
dma_free_writecombine(&dev->dev, fbi->map_size,
fbi->map_cpu, fbi->map_dma);
-failed:
+failed_free_io:
+ iounmap(fbi->mmio_base);
+failed_free_res:
+ release_mem_region(r->start, r->end - r->start + 1);
+failed_fbi:
+ clk_put(fbi->clk);
platform_set_drvdata(dev, NULL);
kfree(fbi);
+failed:
return ret;
}
@@ -1786,7 +1801,7 @@ static struct platform_driver pxafb_driver = {
},
};
-static int __devinit pxafb_init(void)
+static int __init pxafb_init(void)
{
if (pxafb_setup_options())
return -EINVAL;
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index 13b38cbbe4cf..f0598961c6b0 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -1,75 +1,15 @@
-/*
- * linux/drivers/video/s3c2410fb.c
- * Copyright (c) Arnaud Patard, Ben Dooks
+/* linux/drivers/video/s3c2410fb.c
+ * Copyright (c) 2004,2005 Arnaud Patard
+ * Copyright (c) 2004-2008 Ben Dooks
+ *
+ * S3C2410 LCD Framebuffer Driver
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*
- * S3C2410 LCD Controller Frame Buffer Driver
- * based on skeletonfb.c, sa1100fb.c and others
- *
- * ChangeLog
- * 2005-04-07: Arnaud Patard <arnaud.patard@rtp-net.org>
- * - u32 state -> pm_message_t state
- * - S3C2410_{VA,SZ}_LCD -> S3C24XX
- *
- * 2005-03-15: Arnaud Patard <arnaud.patard@rtp-net.org>
- * - Removed the ioctl
- * - use readl/writel instead of __raw_writel/__raw_readl
- *
- * 2004-12-04: Arnaud Patard <arnaud.patard@rtp-net.org>
- * - Added the possibility to set on or off the
- * debugging messages
- * - Replaced 0 and 1 by on or off when reading the
- * /sys files
- *
- * 2005-03-23: Ben Dooks <ben-linux@fluff.org>
- * - added non 16bpp modes
- * - updated platform information for range of x/y/bpp
- * - add code to ensure palette is written correctly
- * - add pixel clock divisor control
- *
- * 2004-11-11: Arnaud Patard <arnaud.patard@rtp-net.org>
- * - Removed the use of currcon as it no more exists
- * - Added LCD power sysfs interface
- *
- * 2004-11-03: Ben Dooks <ben-linux@fluff.org>
- * - minor cleanups
- * - add suspend/resume support
- * - s3c2410fb_setcolreg() not valid in >8bpp modes
- * - removed last CONFIG_FB_S3C2410_FIXED
- * - ensure lcd controller stopped before cleanup
- * - added sysfs interface for backlight power
- * - added mask for gpio configuration
- * - ensured IRQs disabled during GPIO configuration
- * - disable TPAL before enabling video
- *
- * 2004-09-20: Arnaud Patard <arnaud.patard@rtp-net.org>
- * - Suppress command line options
- *
- * 2004-09-15: Arnaud Patard <arnaud.patard@rtp-net.org>
- * - code cleanup
- *
- * 2004-09-07: Arnaud Patard <arnaud.patard@rtp-net.org>
- * - Renamed from h1940fb.c to s3c2410fb.c
- * - Add support for different devices
- * - Backlight support
- *
- * 2004-09-05: Herbert Pötzl <herbert@13thfloor.at>
- * - added clock (de-)allocation code
- * - added fixem fbmem option
- *
- * 2004-07-27: Arnaud Patard <arnaud.patard@rtp-net.org>
- * - code cleanup
- * - added a forgotten return in h1940fb_init
- *
- * 2004-07-19: Herbert Pötzl <herbert@13thfloor.at>
- * - code cleanup and extended debugging
- *
- * 2004-07-15: Arnaud Patard <arnaud.patard@rtp-net.org>
- * - First version
- */
+ * Driver based on skeletonfb.c, sa1100fb.c and others.
+*/
#include <linux/module.h>
#include <linux/kernel.h>
@@ -580,6 +520,27 @@ static int s3c2410fb_setcolreg(unsigned regno,
return 0;
}
+/* s3c2410fb_lcd_enable
+ *
+ * shutdown the lcd controller
+ */
+static void s3c2410fb_lcd_enable(struct s3c2410fb_info *fbi, int enable)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ if (enable)
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID;
+ else
+ fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;
+
+ writel(fbi->regs.lcdcon1, fbi->io + S3C2410_LCDCON1);
+
+ local_irq_restore(flags);
+}
+
+
/*
* s3c2410fb_blank
* @blank_mode: the blank mode we want.
@@ -589,9 +550,6 @@ static int s3c2410fb_setcolreg(unsigned regno,
* blanking succeeded, != 0 if un-/blanking failed due to e.g. a
* video mode which doesn't support it. Implements VESA suspend
* and powerdown modes on hardware that supports disabling hsync/vsync:
- * blank_mode == 2: suspend vsync
- * blank_mode == 3: suspend hsync
- * blank_mode == 4: powerdown
*
* Returns negative errno on error, or zero on success.
*
@@ -605,6 +563,12 @@ static int s3c2410fb_blank(int blank_mode, struct fb_info *info)
tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL;
+ if (blank_mode == FB_BLANK_POWERDOWN) {
+ s3c2410fb_lcd_enable(fbi, 0);
+ } else {
+ s3c2410fb_lcd_enable(fbi, 1);
+ }
+
if (blank_mode == FB_BLANK_UNBLANK)
writel(0x0, tpal_reg);
else {
@@ -948,7 +912,10 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev,
}
/* create device files */
- device_create_file(&pdev->dev, &dev_attr_debug);
+ ret = device_create_file(&pdev->dev, &dev_attr_debug);
+ if (ret) {
+ printk(KERN_ERR "failed to add debug attribute\n");
+ }
printk(KERN_INFO "fb%d: %s frame buffer device\n",
fbinfo->node, fbinfo->fix.id);
@@ -983,21 +950,6 @@ static int __init s3c2412fb_probe(struct platform_device *pdev)
return s3c24xxfb_probe(pdev, DRV_S3C2412);
}
-/* s3c2410fb_stop_lcd
- *
- * shutdown the lcd controller
- */
-static void s3c2410fb_stop_lcd(struct s3c2410fb_info *fbi)
-{
- unsigned long flags;
-
- local_irq_save(flags);
-
- fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;
- writel(fbi->regs.lcdcon1, fbi->io + S3C2410_LCDCON1);
-
- local_irq_restore(flags);
-}
/*
* Cleanup
@@ -1010,7 +962,7 @@ static int s3c2410fb_remove(struct platform_device *pdev)
unregister_framebuffer(fbinfo);
- s3c2410fb_stop_lcd(info);
+ s3c2410fb_lcd_enable(info, 0);
msleep(1);
s3c2410fb_unmap_video_memory(fbinfo);
@@ -1043,7 +995,7 @@ static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state)
struct fb_info *fbinfo = platform_get_drvdata(dev);
struct s3c2410fb_info *info = fbinfo->par;
- s3c2410fb_stop_lcd(info);
+ s3c2410fb_lcd_enable(info, 0);
/* sleep before disabling the clock, we need to ensure
* the LCD DMA engine is not going to get back on the bus
@@ -1118,3 +1070,5 @@ MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, "
"Ben Dooks <ben-linux@fluff.org>");
MODULE_DESCRIPTION("Framebuffer driver for the s3c2410");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c2410-lcd");
+MODULE_ALIAS("platform:s3c2412-lcd");
diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h
index dbb73b95e2ef..9a6ba3e9d1b8 100644
--- a/drivers/video/s3c2410fb.h
+++ b/drivers/video/s3c2410fb.h
@@ -1,26 +1,14 @@
/*
* linux/drivers/video/s3c2410fb.h
- * Copyright (c) Arnaud Patard
+ * Copyright (c) 2004 Arnaud Patard
+ *
+ * S3C2410 LCD Framebuffer Driver
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*
- * S3C2410 LCD Controller Frame Buffer Driver
- * based on skeletonfb.c, sa1100fb.h
- *
- * ChangeLog
- *
- * 2004-12-04: Arnaud Patard <arnaud.patard@rtp-net.org>
- * - Moved dprintk to s3c2410fb.c
- *
- * 2004-09-07: Arnaud Patard <arnaud.patard@rtp-net.org>
- * - Renamed from h1940fb.h to s3c2410fb.h
- * - Changed h1940 to s3c2410
- *
- * 2004-07-15: Arnaud Patard <arnaud.patard@rtp-net.org>
- * - First version
- */
+*/
#ifndef __S3C2410FB_H
#define __S3C2410FB_H
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index 73803624c131..b9343844cd1f 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -5787,7 +5787,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
} else {
struct sis_video_info *countvideo = card_list;
ivideo->cardnumber = 1;
- while((countvideo = countvideo->next) != 0)
+ while((countvideo = countvideo->next) != NULL)
ivideo->cardnumber++;
}
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
index 742b5c656d66..15d4a768b1f6 100644
--- a/drivers/video/sm501fb.c
+++ b/drivers/video/sm501fb.c
@@ -663,14 +663,14 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
sm501fb_sync_regs(fbi);
mdelay(10);
- if (pd->flags & SM501FB_FLAG_PANEL_USE_VBIASEN) {
+ if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) {
control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */
writel(control, ctrl_reg);
sm501fb_sync_regs(fbi);
mdelay(10);
}
- if (pd->flags & SM501FB_FLAG_PANEL_USE_FPEN) {
+ if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) {
control |= SM501_DC_PANEL_CONTROL_FPEN;
writel(control, ctrl_reg);
sm501fb_sync_regs(fbi);
@@ -678,14 +678,14 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
}
} else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) {
/* disable panel power */
- if (pd->flags & SM501FB_FLAG_PANEL_USE_FPEN) {
+ if (!(pd->flags & SM501FB_FLAG_PANEL_NO_FPEN)) {
control &= ~SM501_DC_PANEL_CONTROL_FPEN;
writel(control, ctrl_reg);
sm501fb_sync_regs(fbi);
mdelay(10);
}
- if (pd->flags & SM501FB_FLAG_PANEL_USE_VBIASEN) {
+ if (!(pd->flags & SM501FB_FLAG_PANEL_NO_VBIASEN)) {
control &= ~SM501_DC_PANEL_CONTROL_BIAS;
writel(control, ctrl_reg);
sm501fb_sync_regs(fbi);
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c
index 30469bf906e5..d0674f1e3f10 100644
--- a/drivers/video/w100fb.c
+++ b/drivers/video/w100fb.c
@@ -1003,6 +1003,7 @@ static struct w100_pll_info xtal_14318000[] = {
static struct w100_pll_info xtal_16000000[] = {
/*freq M N_int N_fac tfgoal lock_time */
{ 72, 1, 8, 0, 0xe0, 48}, /* tfgoal guessed */
+ { 80, 1, 9, 0, 0xe0, 13}, /* tfgoal guessed */
{ 95, 1, 10, 7, 0xe0, 38}, /* tfgoal guessed */
{ 96, 1, 11, 0, 0xe0, 36}, /* tfgoal guessed */
{ 0, 0, 0, 0, 0, 0},
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index 13866789b356..7084e7e146c0 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -2,6 +2,9 @@
#include <linux/spinlock.h>
#include <linux/virtio_config.h>
+/* Unique numbering for virtio devices. */
+static unsigned int dev_index;
+
static ssize_t device_show(struct device *_d,
struct device_attribute *attr, char *buf)
{
@@ -121,9 +124,9 @@ static int virtio_dev_probe(struct device *_d)
if (err)
add_status(dev, VIRTIO_CONFIG_S_FAILED);
else {
- add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
/* They should never have set feature bits beyond 32 */
dev->config->set_features(dev, dev->features[0]);
+ add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
}
return err;
}
@@ -166,7 +169,10 @@ int register_virtio_device(struct virtio_device *dev)
int err;
dev->dev.bus = &virtio_bus;
- sprintf(dev->dev.bus_id, "%u", dev->index);
+
+ /* Assign a unique device index and hence name. */
+ dev->index = dev_index++;
+ sprintf(dev->dev.bus_id, "virtio%u", dev->index);
/* We always start by resetting the device, in case a previous
* driver messed it up. This also tests that code path a little. */
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
index 27e9fc9117cd..eae7236310e4 100644
--- a/drivers/virtio/virtio_pci.c
+++ b/drivers/virtio/virtio_pci.c
@@ -78,9 +78,6 @@ static struct device virtio_pci_root = {
.bus_id = "virtio-pci",
};
-/* Unique numbering for devices under the kvm root */
-static unsigned int dev_index;
-
/* Convert a generic virtio device to our structure */
static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev)
{
@@ -325,10 +322,6 @@ static int __devinit virtio_pci_probe(struct pci_dev *pci_dev,
if (vp_dev == NULL)
return -ENOMEM;
- snprintf(vp_dev->vdev.dev.bus_id, BUS_ID_SIZE, "virtio%d", dev_index);
- vp_dev->vdev.index = dev_index;
- dev_index++;
-
vp_dev->vdev.dev.parent = &virtio_pci_root;
vp_dev->vdev.config = &virtio_pci_config_ops;
vp_dev->pci_dev = pci_dev;
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 937a49d6772c..72bf8bc09014 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -227,7 +227,6 @@ static bool vring_enable_cb(struct virtqueue *_vq)
struct vring_virtqueue *vq = to_vvq(_vq);
START_USE(vq);
- BUG_ON(!(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT));
/* We optimistically turn back on interrupts, then check if there was
* more to do. */
@@ -254,13 +253,6 @@ irqreturn_t vring_interrupt(int irq, void *_vq)
if (unlikely(vq->broken))
return IRQ_HANDLED;
- /* Other side may have missed us turning off the interrupt,
- * but we should preserve disable semantic for virtio users. */
- if (unlikely(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) {
- pr_debug("virtqueue interrupt after disable for %p\n", vq);
- return IRQ_HANDLED;
- }
-
pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback);
if (vq->vq.callback)
vq->vq.callback(&vq->vq);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 254d115cafab..ccb78f66c2b6 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -295,6 +295,19 @@ config ALIM7101_WDT
Most people will say N.
+config GEODE_WDT
+ tristate "AMD Geode CS5535/CS5536 Watchdog"
+ depends on MGEODE_LX
+ help
+ This driver enables a watchdog capability built into the
+ CS5535/CS5536 companion chips for the AMD Geode GX and LX
+ processors. This watchdog watches your kernel to make sure
+ it doesn't freeze, and if it does, it reboots your computer after
+ a certain amount of time.
+
+ You can compile this driver directly into the kernel, or use
+ it as a module. The module will be called geodewdt.
+
config SC520_WDT
tristate "AMD Elan SC520 processor Watchdog"
depends on X86
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index f3fb170fe5c6..25b352b664d9 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -59,6 +59,7 @@ obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o
obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
+obj-$(CONFIG_GEODE_WDT) += geodewdt.o
obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
obj-$(CONFIG_IB700_WDT) += ib700wdt.o
diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c
index 1237113dc14a..03b3e3d91e7c 100644
--- a/drivers/watchdog/bfin_wdt.c
+++ b/drivers/watchdog/bfin_wdt.c
@@ -29,7 +29,8 @@
#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
#define stampit() stamp("here i am")
-#define pr_init(fmt, args...) ({ static const __initdata char __fmt[] = fmt; printk(__fmt, ## args); })
+#define pr_devinit(fmt, args...) ({ static const __devinitconst char __fmt[] = fmt; printk(__fmt, ## args); })
+#define pr_init(fmt, args...) ({ static const __initconst char __fmt[] = fmt; printk(__fmt, ## args); })
#define WATCHDOG_NAME "bfin-wdt"
#define PFX WATCHDOG_NAME ": "
@@ -377,20 +378,6 @@ static int bfin_wdt_resume(struct platform_device *pdev)
# define bfin_wdt_resume NULL
#endif
-static struct platform_device bfin_wdt_device = {
- .name = WATCHDOG_NAME,
- .id = -1,
-};
-
-static struct platform_driver bfin_wdt_driver = {
- .driver = {
- .name = WATCHDOG_NAME,
- .owner = THIS_MODULE,
- },
- .suspend = bfin_wdt_suspend,
- .resume = bfin_wdt_resume,
-};
-
static const struct file_operations bfin_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -418,11 +405,67 @@ static struct notifier_block bfin_wdt_notifier = {
};
/**
- * bfin_wdt_init - Initialize module
+ * bfin_wdt_probe - Initialize module
*
- * Registers the device and notifier handler. Actual device
+ * Registers the misc device and notifier handler. Actual device
* initialization is handled by bfin_wdt_open().
*/
+static int __devinit bfin_wdt_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = register_reboot_notifier(&bfin_wdt_notifier);
+ if (ret) {
+ pr_devinit(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret);
+ return ret;
+ }
+
+ ret = misc_register(&bfin_wdt_miscdev);
+ if (ret) {
+ pr_devinit(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ unregister_reboot_notifier(&bfin_wdt_notifier);
+ return ret;
+ }
+
+ pr_devinit(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
+ timeout, nowayout);
+
+ return 0;
+}
+
+/**
+ * bfin_wdt_remove - Initialize module
+ *
+ * Unregisters the misc device and notifier handler. Actual device
+ * deinitialization is handled by bfin_wdt_close().
+ */
+static int __devexit bfin_wdt_remove(struct platform_device *pdev)
+{
+ misc_deregister(&bfin_wdt_miscdev);
+ unregister_reboot_notifier(&bfin_wdt_notifier);
+ return 0;
+}
+
+static struct platform_device *bfin_wdt_device;
+
+static struct platform_driver bfin_wdt_driver = {
+ .probe = bfin_wdt_probe,
+ .remove = __devexit_p(bfin_wdt_remove),
+ .suspend = bfin_wdt_suspend,
+ .resume = bfin_wdt_resume,
+ .driver = {
+ .name = WATCHDOG_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+/**
+ * bfin_wdt_init - Initialize module
+ *
+ * Checks the module params and registers the platform device & driver.
+ * Real work is in the platform probe function.
+ */
static int __init bfin_wdt_init(void)
{
int ret;
@@ -436,44 +479,32 @@ static int __init bfin_wdt_init(void)
/* Since this is an on-chip device and needs no board-specific
* resources, we'll handle all the platform device stuff here.
*/
- ret = platform_device_register(&bfin_wdt_device);
- if (ret)
- return ret;
-
- ret = platform_driver_probe(&bfin_wdt_driver, NULL);
- if (ret)
- return ret;
-
- ret = register_reboot_notifier(&bfin_wdt_notifier);
+ ret = platform_driver_register(&bfin_wdt_driver);
if (ret) {
- pr_init(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret);
+ pr_init(KERN_ERR PFX "unable to register driver\n");
return ret;
}
- ret = misc_register(&bfin_wdt_miscdev);
- if (ret) {
- pr_init(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
- unregister_reboot_notifier(&bfin_wdt_notifier);
- return ret;
+ bfin_wdt_device = platform_device_register_simple(WATCHDOG_NAME, -1, NULL, 0);
+ if (IS_ERR(bfin_wdt_device)) {
+ pr_init(KERN_ERR PFX "unable to register device\n");
+ platform_driver_unregister(&bfin_wdt_driver);
+ return PTR_ERR(bfin_wdt_device);
}
- pr_init(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
- timeout, nowayout);
-
return 0;
}
/**
* bfin_wdt_exit - Deinitialize module
*
- * Unregisters the device and notifier handler. Actual device
- * deinitialization is handled by bfin_wdt_close().
+ * Back out the platform device & driver steps. Real work is in the
+ * platform remove function.
*/
static void __exit bfin_wdt_exit(void)
{
- misc_deregister(&bfin_wdt_miscdev);
- unregister_reboot_notifier(&bfin_wdt_notifier);
+ platform_device_unregister(bfin_wdt_device);
+ platform_driver_unregister(&bfin_wdt_driver);
}
module_init(bfin_wdt_init);
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
index d362f5bf658a..c1ba0db48501 100644
--- a/drivers/watchdog/booke_wdt.c
+++ b/drivers/watchdog/booke_wdt.c
@@ -1,12 +1,10 @@
/*
- * drivers/char/watchdog/booke_wdt.c
- *
* Watchdog timer for PowerPC Book-E systems
*
* Author: Matthew McClintock
* Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
- * Copyright 2005 Freescale Semiconductor Inc.
+ * Copyright 2005, 2008 Freescale Semiconductor Inc.
*
* 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
@@ -16,6 +14,7 @@
#include <linux/module.h>
#include <linux/fs.h>
+#include <linux/smp.h>
#include <linux/miscdevice.h>
#include <linux/notifier.h>
#include <linux/watchdog.h>
@@ -38,7 +37,7 @@
#define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */
#endif /* for timing information */
-u32 booke_wdt_enabled = 0;
+u32 booke_wdt_enabled;
u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
#ifdef CONFIG_FSL_BOOKE
@@ -47,33 +46,31 @@ u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
#define WDTP(x) (TCR_WP(x))
#endif
-/*
- * booke_wdt_ping:
- */
-static __inline__ void booke_wdt_ping(void)
+static DEFINE_SPINLOCK(booke_wdt_lock);
+
+static void __booke_wdt_ping(void *data)
{
mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
}
-/*
- * booke_wdt_enable:
- */
-static __inline__ void booke_wdt_enable(void)
+static void booke_wdt_ping(void)
+{
+ on_each_cpu(__booke_wdt_ping, NULL, 0, 0);
+}
+
+static void __booke_wdt_enable(void *data)
{
u32 val;
/* clear status before enabling watchdog */
- booke_wdt_ping();
+ __booke_wdt_ping(NULL);
val = mfspr(SPRN_TCR);
val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period));
mtspr(SPRN_TCR, val);
}
-/*
- * booke_wdt_write:
- */
-static ssize_t booke_wdt_write (struct file *file, const char __user *buf,
+static ssize_t booke_wdt_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
booke_wdt_ping();
@@ -81,15 +78,11 @@ static ssize_t booke_wdt_write (struct file *file, const char __user *buf,
}
static struct watchdog_info ident = {
- .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
- .firmware_version = 0,
- .identity = "PowerPC Book-E Watchdog",
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+ .identity = "PowerPC Book-E Watchdog",
};
-/*
- * booke_wdt_ioctl:
- */
-static int booke_wdt_ioctl (struct inode *inode, struct file *file,
+static int booke_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
u32 tmp = 0;
@@ -97,7 +90,7 @@ static int booke_wdt_ioctl (struct inode *inode, struct file *file,
switch (cmd) {
case WDIOC_GETSUPPORT:
- if (copy_to_user ((struct watchdog_info __user *) arg, &ident,
+ if (copy_to_user((struct watchdog_info __user *)arg, &ident,
sizeof(struct watchdog_info)))
return -EFAULT;
case WDIOC_GETSTATUS:
@@ -132,33 +125,33 @@ static int booke_wdt_ioctl (struct inode *inode, struct file *file,
return 0;
}
-/*
- * booke_wdt_open:
- */
-static int booke_wdt_open (struct inode *inode, struct file *file)
+
+static int booke_wdt_open(struct inode *inode, struct file *file)
{
+ spin_lock(&booke_wdt_lock);
if (booke_wdt_enabled == 0) {
booke_wdt_enabled = 1;
- booke_wdt_enable();
- printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
- booke_wdt_period);
+ on_each_cpu(__booke_wdt_enable, NULL, 0, 0);
+ printk(KERN_INFO "PowerPC Book-E Watchdog Timer Enabled "
+ "(wdt_period=%d)\n", booke_wdt_period);
}
+ spin_unlock(&booke_wdt_lock);
return nonseekable_open(inode, file);
}
static const struct file_operations booke_wdt_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = booke_wdt_write,
- .ioctl = booke_wdt_ioctl,
- .open = booke_wdt_open,
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = booke_wdt_write,
+ .ioctl = booke_wdt_ioctl,
+ .open = booke_wdt_open,
};
static struct miscdevice booke_wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &booke_wdt_fops,
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &booke_wdt_fops,
};
static void __exit booke_wdt_exit(void)
@@ -166,28 +159,27 @@ static void __exit booke_wdt_exit(void)
misc_deregister(&booke_wdt_miscdev);
}
-/*
- * booke_wdt_init:
- */
static int __init booke_wdt_init(void)
{
int ret = 0;
- printk (KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n");
+ printk(KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n");
ident.firmware_version = cur_cpu_spec->pvr_value;
ret = misc_register(&booke_wdt_miscdev);
if (ret) {
- printk (KERN_CRIT "Cannot register miscdev on minor=%d (err=%d)\n",
+ printk(KERN_CRIT "Cannot register miscdev on minor=%d: %d\n",
WATCHDOG_MINOR, ret);
return ret;
}
+ spin_lock(&booke_wdt_lock);
if (booke_wdt_enabled == 1) {
- printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
- booke_wdt_period);
- booke_wdt_enable();
+ printk(KERN_INFO "PowerPC Book-E Watchdog Timer Enabled "
+ "(wdt_period=%d)\n", booke_wdt_period);
+ on_each_cpu(__booke_wdt_enable, NULL, 0, 0);
}
+ spin_unlock(&booke_wdt_lock);
return ret;
}
diff --git a/drivers/watchdog/geodewdt.c b/drivers/watchdog/geodewdt.c
new file mode 100644
index 000000000000..30d09cbbad94
--- /dev/null
+++ b/drivers/watchdog/geodewdt.c
@@ -0,0 +1,308 @@
+/* Watchdog timer for the Geode GX/LX with the CS5535/CS5536 companion chip
+ *
+ * Copyright (C) 2006-2007, Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+
+#include <asm/uaccess.h>
+#include <asm/geode.h>
+
+#define GEODEWDT_HZ 500
+#define GEODEWDT_SCALE 6
+#define GEODEWDT_MAX_SECONDS 131
+
+#define WDT_FLAGS_OPEN 1
+#define WDT_FLAGS_ORPHAN 2
+
+#define DRV_NAME "geodewdt"
+#define WATCHDOG_NAME "Geode GX/LX WDT"
+#define WATCHDOG_TIMEOUT 60
+
+static int timeout = WATCHDOG_TIMEOUT;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=131, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static struct platform_device *geodewdt_platform_device;
+static unsigned long wdt_flags;
+static int wdt_timer;
+static int safe_close;
+
+static void geodewdt_ping(void)
+{
+ /* Stop the counter */
+ geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0);
+
+ /* Reset the counter */
+ geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0);
+
+ /* Enable the counter */
+ geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN);
+}
+
+static void geodewdt_disable(void)
+{
+ geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0);
+ geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0);
+}
+
+static int geodewdt_set_heartbeat(int val)
+{
+ if (val < 1 || val > GEODEWDT_MAX_SECONDS)
+ return -EINVAL;
+
+ geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0);
+ geode_mfgpt_write(wdt_timer, MFGPT_REG_CMP2, val * GEODEWDT_HZ);
+ geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0);
+ geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN);
+
+ timeout = val;
+ return 0;
+}
+
+static int
+geodewdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(WDT_FLAGS_OPEN, &wdt_flags))
+ return -EBUSY;
+
+ if (!test_and_clear_bit(WDT_FLAGS_ORPHAN, &wdt_flags))
+ __module_get(THIS_MODULE);
+
+ geodewdt_ping();
+ return nonseekable_open(inode, file);
+}
+
+static int
+geodewdt_release(struct inode *inode, struct file *file)
+{
+ if (safe_close) {
+ geodewdt_disable();
+ module_put(THIS_MODULE);
+ }
+ else {
+ printk(KERN_CRIT "Unexpected close - watchdog is not stopping.\n");
+ geodewdt_ping();
+
+ set_bit(WDT_FLAGS_ORPHAN, &wdt_flags);
+ }
+
+ clear_bit(WDT_FLAGS_OPEN, &wdt_flags);
+ safe_close = 0;
+ return 0;
+}
+
+static ssize_t
+geodewdt_write(struct file *file, const char __user *data, size_t len,
+ loff_t *ppos)
+{
+ if(len) {
+ if (!nowayout) {
+ size_t i;
+ safe_close = 0;
+
+ for (i = 0; i != len; i++) {
+ char c;
+
+ if (get_user(c, data + i))
+ return -EFAULT;
+
+ if (c == 'V')
+ safe_close = 1;
+ }
+ }
+
+ geodewdt_ping();
+ }
+ return len;
+}
+
+static int
+geodewdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ int interval;
+
+ static struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING
+ | WDIOF_MAGICCLOSE,
+ .firmware_version = 1,
+ .identity = WATCHDOG_NAME,
+ };
+
+ switch(cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, p);
+
+ case WDIOC_KEEPALIVE:
+ geodewdt_ping();
+ return 0;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(interval, p))
+ return -EFAULT;
+
+ if (geodewdt_set_heartbeat(interval))
+ return -EINVAL;
+
+/* Fall through */
+
+ case WDIOC_GETTIMEOUT:
+ return put_user(timeout, p);
+
+ case WDIOC_SETOPTIONS:
+ {
+ int options, ret = -EINVAL;
+
+ if (get_user(options, p))
+ return -EFAULT;
+
+ if (options & WDIOS_DISABLECARD) {
+ geodewdt_disable();
+ ret = 0;
+ }
+
+ if (options & WDIOS_ENABLECARD) {
+ geodewdt_ping();
+ ret = 0;
+ }
+
+ return ret;
+ }
+ default:
+ return -ENOTTY;
+ }
+
+ return 0;
+}
+
+static const struct file_operations geodewdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = geodewdt_write,
+ .ioctl = geodewdt_ioctl,
+ .open = geodewdt_open,
+ .release = geodewdt_release,
+};
+
+static struct miscdevice geodewdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &geodewdt_fops
+};
+
+static int __devinit
+geodewdt_probe(struct platform_device *dev)
+{
+ int ret, timer;
+
+ timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING);
+
+ if (timer == -1) {
+ printk(KERN_ERR "geodewdt: No timers were available\n");
+ return -ENODEV;
+ }
+
+ wdt_timer = timer;
+
+ /* Set up the timer */
+
+ geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP,
+ GEODEWDT_SCALE | (3 << 8));
+
+ /* Set up comparator 2 to reset when the event fires */
+ geode_mfgpt_toggle_event(wdt_timer, MFGPT_CMP2, MFGPT_EVENT_RESET, 1);
+
+ /* Set up the initial timeout */
+
+ geode_mfgpt_write(wdt_timer, MFGPT_REG_CMP2,
+ timeout * GEODEWDT_HZ);
+
+ ret = misc_register(&geodewdt_miscdev);
+
+ return ret;
+}
+
+static int __devexit
+geodewdt_remove(struct platform_device *dev)
+{
+ misc_deregister(&geodewdt_miscdev);
+ return 0;
+}
+
+static void
+geodewdt_shutdown(struct platform_device *dev)
+{
+ geodewdt_disable();
+}
+
+static struct platform_driver geodewdt_driver = {
+ .probe = geodewdt_probe,
+ .remove = __devexit_p(geodewdt_remove),
+ .shutdown = geodewdt_shutdown,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ },
+};
+
+static int __init
+geodewdt_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&geodewdt_driver);
+ if (ret)
+ return ret;
+
+ geodewdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
+ if (IS_ERR(geodewdt_platform_device)) {
+ ret = PTR_ERR(geodewdt_platform_device);
+ goto err;
+ }
+
+ return 0;
+err:
+ platform_driver_unregister(&geodewdt_driver);
+ return ret;
+}
+
+static void __exit
+geodewdt_exit(void)
+{
+ platform_device_unregister(geodewdt_platform_device);
+ platform_driver_unregister(&geodewdt_driver);
+}
+
+module_init(geodewdt_init);
+module_exit(geodewdt_exit);
+
+MODULE_AUTHOR("Advanced Micro Devices, Inc");
+MODULE_DESCRIPTION("Geode GX/LX Watchdog Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 6483d1066b95..eaa3f2a79ff5 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -140,49 +140,53 @@ static struct pci_device_id hpwdt_devices[] = {
};
MODULE_DEVICE_TABLE(pci, hpwdt_devices);
+extern asmlinkage void asminline_call(struct cmn_registers *pi86Regs, unsigned long *pRomEntry);
+
#ifndef CONFIG_X86_64
/* --32 Bit Bios------------------------------------------------------------ */
#define HPWDT_ARCH 32
-static void asminline_call(struct cmn_registers *pi86Regs,
- unsigned long *pRomEntry)
-{
- asm("pushl %ebp \n\t"
- "movl %esp, %ebp \n\t"
- "pusha \n\t"
- "pushf \n\t"
- "push %es \n\t"
- "push %ds \n\t"
- "pop %es \n\t"
- "movl 8(%ebp),%eax \n\t"
- "movl 4(%eax),%ebx \n\t"
- "movl 8(%eax),%ecx \n\t"
- "movl 12(%eax),%edx \n\t"
- "movl 16(%eax),%esi \n\t"
- "movl 20(%eax),%edi \n\t"
- "movl (%eax),%eax \n\t"
- "push %cs \n\t"
- "call *12(%ebp) \n\t"
- "pushf \n\t"
- "pushl %eax \n\t"
- "movl 8(%ebp),%eax \n\t"
- "movl %ebx,4(%eax) \n\t"
- "movl %ecx,8(%eax) \n\t"
- "movl %edx,12(%eax) \n\t"
- "movl %esi,16(%eax) \n\t"
- "movl %edi,20(%eax) \n\t"
- "movw %ds,24(%eax) \n\t"
- "movw %es,26(%eax) \n\t"
- "popl %ebx \n\t"
- "movl %ebx,(%eax) \n\t"
- "popl %ebx \n\t"
- "movl %ebx,28(%eax) \n\t"
- "pop %es \n\t"
- "popf \n\t"
- "popa \n\t"
- "leave \n\t" "ret");
-}
+asm(".text \n\t"
+ ".align 4 \n"
+ "asminline_call: \n\t"
+ "pushl %ebp \n\t"
+ "movl %esp, %ebp \n\t"
+ "pusha \n\t"
+ "pushf \n\t"
+ "push %es \n\t"
+ "push %ds \n\t"
+ "pop %es \n\t"
+ "movl 8(%ebp),%eax \n\t"
+ "movl 4(%eax),%ebx \n\t"
+ "movl 8(%eax),%ecx \n\t"
+ "movl 12(%eax),%edx \n\t"
+ "movl 16(%eax),%esi \n\t"
+ "movl 20(%eax),%edi \n\t"
+ "movl (%eax),%eax \n\t"
+ "push %cs \n\t"
+ "call *12(%ebp) \n\t"
+ "pushf \n\t"
+ "pushl %eax \n\t"
+ "movl 8(%ebp),%eax \n\t"
+ "movl %ebx,4(%eax) \n\t"
+ "movl %ecx,8(%eax) \n\t"
+ "movl %edx,12(%eax) \n\t"
+ "movl %esi,16(%eax) \n\t"
+ "movl %edi,20(%eax) \n\t"
+ "movw %ds,24(%eax) \n\t"
+ "movw %es,26(%eax) \n\t"
+ "popl %ebx \n\t"
+ "movl %ebx,(%eax) \n\t"
+ "popl %ebx \n\t"
+ "movl %ebx,28(%eax) \n\t"
+ "pop %es \n\t"
+ "popf \n\t"
+ "popa \n\t"
+ "leave \n\t"
+ "ret \n\t"
+ ".previous");
+
/*
* cru_detect
@@ -333,43 +337,44 @@ static int __devinit detect_cru_service(void)
#define HPWDT_ARCH 64
-static void asminline_call(struct cmn_registers *pi86Regs,
- unsigned long *pRomEntry)
-{
- asm("pushq %rbp \n\t"
- "movq %rsp, %rbp \n\t"
- "pushq %rax \n\t"
- "pushq %rbx \n\t"
- "pushq %rdx \n\t"
- "pushq %r12 \n\t"
- "pushq %r9 \n\t"
- "movq %rsi, %r12 \n\t"
- "movq %rdi, %r9 \n\t"
- "movl 4(%r9),%ebx \n\t"
- "movl 8(%r9),%ecx \n\t"
- "movl 12(%r9),%edx \n\t"
- "movl 16(%r9),%esi \n\t"
- "movl 20(%r9),%edi \n\t"
- "movl (%r9),%eax \n\t"
- "call *%r12 \n\t"
- "pushfq \n\t"
- "popq %r12 \n\t"
- "popfq \n\t"
- "movl %eax, (%r9) \n\t"
- "movl %ebx, 4(%r9) \n\t"
- "movl %ecx, 8(%r9) \n\t"
- "movl %edx, 12(%r9) \n\t"
- "movl %esi, 16(%r9) \n\t"
- "movl %edi, 20(%r9) \n\t"
- "movq %r12, %rax \n\t"
- "movl %eax, 28(%r9) \n\t"
- "popq %r9 \n\t"
- "popq %r12 \n\t"
- "popq %rdx \n\t"
- "popq %rbx \n\t"
- "popq %rax \n\t"
- "leave \n\t" "ret");
-}
+asm(".text \n\t"
+ ".align 4 \n"
+ "asminline_call: \n\t"
+ "pushq %rbp \n\t"
+ "movq %rsp, %rbp \n\t"
+ "pushq %rax \n\t"
+ "pushq %rbx \n\t"
+ "pushq %rdx \n\t"
+ "pushq %r12 \n\t"
+ "pushq %r9 \n\t"
+ "movq %rsi, %r12 \n\t"
+ "movq %rdi, %r9 \n\t"
+ "movl 4(%r9),%ebx \n\t"
+ "movl 8(%r9),%ecx \n\t"
+ "movl 12(%r9),%edx \n\t"
+ "movl 16(%r9),%esi \n\t"
+ "movl 20(%r9),%edi \n\t"
+ "movl (%r9),%eax \n\t"
+ "call *%r12 \n\t"
+ "pushfq \n\t"
+ "popq %r12 \n\t"
+ "popfq \n\t"
+ "movl %eax, (%r9) \n\t"
+ "movl %ebx, 4(%r9) \n\t"
+ "movl %ecx, 8(%r9) \n\t"
+ "movl %edx, 12(%r9) \n\t"
+ "movl %esi, 16(%r9) \n\t"
+ "movl %edi, 20(%r9) \n\t"
+ "movq %r12, %rax \n\t"
+ "movl %eax, 28(%r9) \n\t"
+ "popq %r9 \n\t"
+ "popq %r12 \n\t"
+ "popq %rdx \n\t"
+ "popq %rbx \n\t"
+ "popq %rax \n\t"
+ "leave \n\t"
+ "ret \n\t"
+ ".previous");
/*
* dmi_find_cru
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index a0e6809e369f..95ba985bd341 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -41,9 +41,10 @@
* 82801HH (ICH8DH) : document number 313056-003, 313057-009,
* 82801HO (ICH8DO) : document number 313056-003, 313057-009,
* 82801HEM (ICH8M-E) : document number 313056-003, 313057-009,
- * 82801IB (ICH9) : document number 316972-001, 316973-001,
- * 82801IR (ICH9R) : document number 316972-001, 316973-001,
- * 82801IH (ICH9DH) : document number 316972-001, 316973-001,
+ * 82801IB (ICH9) : document number 316972-001, 316973-006,
+ * 82801IR (ICH9R) : document number 316972-001, 316973-006,
+ * 82801IH (ICH9DH) : document number 316972-001, 316973-006,
+ * 82801IO (ICH9DO) : document number 316972-001, 316973-006,
* 6300ESB (6300ESB) : document number 300641-003, 300884-010,
* 631xESB (631xESB) : document number 313082-001, 313075-005,
* 632xESB (632xESB) : document number 313082-001, 313075-005
@@ -55,8 +56,8 @@
/* Module and version information */
#define DRV_NAME "iTCO_wdt"
-#define DRV_VERSION "1.02"
-#define DRV_RELDATE "26-Jul-2007"
+#define DRV_VERSION "1.03"
+#define DRV_RELDATE "30-Apr-2008"
#define PFX DRV_NAME ": "
/* Includes */
@@ -104,6 +105,7 @@ enum iTCO_chipsets {
TCO_ICH9, /* ICH9 */
TCO_ICH9R, /* ICH9R */
TCO_ICH9DH, /* ICH9DH */
+ TCO_ICH9DO, /* ICH9DO */
TCO_631XESB, /* 631xESB/632xESB */
};
@@ -136,6 +138,7 @@ static struct {
{"ICH9", 2},
{"ICH9R", 2},
{"ICH9DH", 2},
+ {"ICH9DO", 2},
{"631xESB/632xESB", 2},
{NULL,0}
};
@@ -181,6 +184,7 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = {
{ ITCO_PCI_DEVICE(0x2918, TCO_ICH9 )},
{ ITCO_PCI_DEVICE(0x2916, TCO_ICH9R )},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2, TCO_ICH9DH )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_4, TCO_ICH9DO )},
{ ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0, TCO_631XESB)},
{ ITCO_PCI_DEVICE(0x2671, TCO_631XESB)},
{ ITCO_PCI_DEVICE(0x2672, TCO_631XESB)},
diff --git a/drivers/watchdog/w83697hf_wdt.c b/drivers/watchdog/w83697hf_wdt.c
index c622a0e6c9ae..528b882420b6 100644
--- a/drivers/watchdog/w83697hf_wdt.c
+++ b/drivers/watchdog/w83697hf_wdt.c
@@ -44,6 +44,7 @@
#define WATCHDOG_NAME "w83697hf/hg WDT"
#define PFX WATCHDOG_NAME ": "
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
+#define WATCHDOG_EARLY_DISABLE 1 /* Disable until userland kicks in */
static unsigned long wdt_is_open;
static char expect_close;
@@ -56,12 +57,16 @@ MODULE_PARM_DESC(wdt_io, "w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)
static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
module_param(timeout, int, 0);
-MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255 (default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+static int early_disable = WATCHDOG_EARLY_DISABLE;
+module_param(early_disable, int, 0);
+MODULE_PARM_DESC(early_disable, "Watchdog gets disabled at boot time (default=" __MODULE_STRING(WATCHDOG_EARLY_DISABLE) ")");
+
/*
* Kernel methods.
*/
@@ -140,7 +145,7 @@ w83697hf_init(void)
w83697hf_deselect_wdt();
}
-static int
+static void
wdt_ping(void)
{
spin_lock(&io_lock);
@@ -150,10 +155,9 @@ wdt_ping(void)
w83697hf_deselect_wdt();
spin_unlock(&io_lock);
- return 0;
}
-static int
+static void
wdt_enable(void)
{
spin_lock(&io_lock);
@@ -164,10 +168,9 @@ wdt_enable(void)
w83697hf_deselect_wdt();
spin_unlock(&io_lock);
- return 0;
}
-static int
+static void
wdt_disable(void)
{
spin_lock(&io_lock);
@@ -178,7 +181,22 @@ wdt_disable(void)
w83697hf_deselect_wdt();
spin_unlock(&io_lock);
- return 0;
+}
+
+static unsigned char
+wdt_running(void)
+{
+ unsigned char t;
+
+ spin_lock(&io_lock);
+ w83697hf_select_wdt();
+
+ t = w83697hf_get_reg(0xF4); /* Read timer */
+
+ w83697hf_deselect_wdt();
+ spin_unlock(&io_lock);
+
+ return t;
}
static int
@@ -397,7 +415,11 @@ wdt_init(void)
}
w83697hf_init();
- wdt_disable(); /* Disable watchdog until first use */
+ if (early_disable) {
+ if (wdt_running())
+ printk (KERN_WARNING PFX "Stopping previously enabled watchdog until userland kicks in\n");
+ wdt_disable();
+ }
if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT);
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 4f0f22b020ea..76e5b7386af9 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -529,7 +529,7 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
#ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */
/* Clear master flag /before/ clearing selector flag. */
- rmb();
+ wmb();
#endif
pending_words = xchg(&vcpu_info->evtchn_pending_sel, 0);
while (pending_words != 0) {