aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acorn/char/Makefile1
-rw-r--r--drivers/acorn/char/i2c.c368
-rw-r--r--drivers/acorn/char/pcf8583.c284
-rw-r--r--drivers/acorn/char/pcf8583.h41
-rw-r--r--drivers/acpi/Kconfig1
-rw-r--r--drivers/ata/Kconfig9
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/ahci.c70
-rw-r--r--drivers/ata/ata_generic.c10
-rw-r--r--drivers/ata/ata_piix.c17
-rw-r--r--drivers/ata/libata-acpi.c88
-rw-r--r--drivers/ata/libata-core.c302
-rw-r--r--drivers/ata/libata-eh.c249
-rw-r--r--drivers/ata/libata-scsi.c46
-rw-r--r--drivers/ata/libata-sff.c8
-rw-r--r--drivers/ata/libata.h13
-rw-r--r--drivers/ata/pata_ali.c8
-rw-r--r--drivers/ata/pata_amd.c12
-rw-r--r--drivers/ata/pata_atiixp.c4
-rw-r--r--drivers/ata/pata_cmd64x.c8
-rw-r--r--drivers/ata/pata_cs5520.c35
-rw-r--r--drivers/ata/pata_cs5530.c8
-rw-r--r--drivers/ata/pata_cs5535.c4
-rw-r--r--drivers/ata/pata_cypress.c4
-rw-r--r--drivers/ata/pata_efar.c4
-rw-r--r--drivers/ata/pata_hpt366.c9
-rw-r--r--drivers/ata/pata_hpt37x.c2
-rw-r--r--drivers/ata/pata_hpt3x3.c6
-rw-r--r--drivers/ata/pata_isapnp.c3
-rw-r--r--drivers/ata/pata_it8213.c4
-rw-r--r--drivers/ata/pata_it821x.c10
-rw-r--r--drivers/ata/pata_ixp4xx_cf.c7
-rw-r--r--drivers/ata/pata_jmicron.c57
-rw-r--r--drivers/ata/pata_legacy.c22
-rw-r--r--drivers/ata/pata_marvell.c4
-rw-r--r--drivers/ata/pata_mpc52xx.c4
-rw-r--r--drivers/ata/pata_mpiix.c4
-rw-r--r--drivers/ata/pata_netcell.c4
-rw-r--r--drivers/ata/pata_ns87410.c4
-rw-r--r--drivers/ata/pata_oldpiix.c9
-rw-r--r--drivers/ata/pata_opti.c6
-rw-r--r--drivers/ata/pata_optidma.c6
-rw-r--r--drivers/ata/pata_pcmcia.c10
-rw-r--r--drivers/ata/pata_pdc2027x.c2
-rw-r--r--drivers/ata/pata_pdc202xx_old.c26
-rw-r--r--drivers/ata/pata_platform.c2
-rw-r--r--drivers/ata/pata_qdi.c14
-rw-r--r--drivers/ata/pata_radisys.c4
-rw-r--r--drivers/ata/pata_rz1000.c7
-rw-r--r--drivers/ata/pata_sc1200.c7
-rw-r--r--drivers/ata/pata_scc.c1230
-rw-r--r--drivers/ata/pata_serverworks.c8
-rw-r--r--drivers/ata/pata_sil680.c22
-rw-r--r--drivers/ata/pata_sis.c13
-rw-r--r--drivers/ata/pata_sl82c105.c42
-rw-r--r--drivers/ata/pata_triflex.c4
-rw-r--r--drivers/ata/pata_via.c8
-rw-r--r--drivers/ata/pata_winbond.c2
-rw-r--r--drivers/ata/pdc_adma.c4
-rw-r--r--drivers/ata/sata_inic162x.c7
-rw-r--r--drivers/ata/sata_mv.c39
-rw-r--r--drivers/ata/sata_nv.c248
-rw-r--r--drivers/ata/sata_promise.c32
-rw-r--r--drivers/ata/sata_qstor.c4
-rw-r--r--drivers/ata/sata_sil.c14
-rw-r--r--drivers/ata/sata_sil24.c7
-rw-r--r--drivers/ata/sata_sis.c5
-rw-r--r--drivers/ata/sata_svw.c2
-rw-r--r--drivers/ata/sata_sx4.c16
-rw-r--r--drivers/ata/sata_uli.c2
-rw-r--r--drivers/ata/sata_via.c30
-rw-r--r--drivers/ata/sata_vsc.c125
-rw-r--r--drivers/ata/sis.h5
-rw-r--r--drivers/base/class.c42
-rw-r--r--drivers/base/core.c38
-rw-r--r--drivers/block/Kconfig16
-rw-r--r--drivers/block/aoe/aoecmd.c12
-rw-r--r--drivers/block/aoe/aoenet.c5
-rw-r--r--drivers/block/cciss.c49
-rw-r--r--drivers/block/umem.c5
-rw-r--r--drivers/bluetooth/bcm203x.c2
-rw-r--r--drivers/bluetooth/bfusb.c1
-rw-r--r--drivers/bluetooth/bt3c_cs.c1
-rw-r--r--drivers/cdrom/viocd.c27
-rw-r--r--drivers/char/Kconfig15
-rw-r--r--drivers/char/agp/Makefile3
-rw-r--r--drivers/char/agp/agp.h8
-rw-r--r--drivers/char/agp/ali-agp.c6
-rw-r--r--drivers/char/agp/amd-k7-agp.c6
-rw-r--r--drivers/char/agp/amd64-agp.c4
-rw-r--r--drivers/char/agp/ati-agp.c4
-rw-r--r--drivers/char/agp/efficeon-agp.c6
-rw-r--r--drivers/char/agp/generic.c2
-rw-r--r--drivers/char/agp/hp-agp.c2
-rw-r--r--drivers/char/agp/i460-agp.c4
-rw-r--r--drivers/char/agp/intel-agp.c38
-rw-r--r--drivers/char/agp/nvidia-agp.c6
-rw-r--r--drivers/char/agp/parisc-agp.c4
-rw-r--r--drivers/char/agp/sgi-agp.c2
-rw-r--r--drivers/char/agp/sis-agp.c2
-rw-r--r--drivers/char/agp/sworks-agp.c6
-rw-r--r--drivers/char/agp/uninorth-agp.c8
-rw-r--r--drivers/char/agp/via-agp.c6
-rw-r--r--drivers/char/cyclades.c1
-rw-r--r--drivers/char/ds1286.c9
-rw-r--r--drivers/char/epca.c17
-rw-r--r--drivers/char/hvc_console.c16
-rw-r--r--drivers/char/ip2/i2lib.c4
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c5
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c3
-rw-r--r--drivers/char/tty_io.c14
-rw-r--r--drivers/clocksource/acpi_pm.c5
-rw-r--r--drivers/clocksource/cyclone.c2
-rw-r--r--drivers/connector/connector.c22
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c5
-rw-r--r--drivers/crypto/geode-aes.c3
-rw-r--r--drivers/hid/hid-core.c7
-rw-r--r--drivers/hid/hid-debug.c1
-rw-r--r--drivers/hid/hid-input.c37
-rw-r--r--drivers/i2c/busses/Kconfig10
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-acorn.c97
-rw-r--r--drivers/ide/Kconfig10
-rw-r--r--drivers/ide/cris/ide-cris.c2
-rw-r--r--drivers/ide/ide-disk.c2
-rw-r--r--drivers/ide/ide-iops.c2
-rw-r--r--drivers/ide/ide-lib.c18
-rw-r--r--drivers/ide/ide-probe.c2
-rw-r--r--drivers/ide/ide.c39
-rw-r--r--drivers/ide/legacy/ali14xx.c11
-rw-r--r--drivers/ide/legacy/dtc2278.c14
-rw-r--r--drivers/ide/legacy/ht6560b.c10
-rw-r--r--drivers/ide/legacy/ide-cs.c7
-rw-r--r--drivers/ide/legacy/qd65xx.c14
-rw-r--r--drivers/ide/legacy/umc8672.c15
-rw-r--r--drivers/ide/mips/au1xxx-ide.c2
-rw-r--r--drivers/ide/pci/alim15x3.c35
-rw-r--r--drivers/ide/pci/cmd640.c1
-rw-r--r--drivers/ide/pci/cmd64x.c108
-rw-r--r--drivers/ide/pci/delkin_cb.c2
-rw-r--r--drivers/ide/pci/generic.c2
-rw-r--r--drivers/ide/pci/opti621.c3
-rw-r--r--drivers/ide/pci/piix.c49
-rw-r--r--drivers/ide/pci/rz1000.c2
-rw-r--r--drivers/ide/pci/siimage.c5
-rw-r--r--drivers/ide/pci/slc90e66.c38
-rw-r--r--drivers/ide/ppc/pmac.c33
-rw-r--r--drivers/ide/ppc/scc_pata.c27
-rw-r--r--drivers/infiniband/core/cm.c10
-rw-r--r--drivers/infiniband/core/cma.c8
-rw-r--r--drivers/infiniband/core/ucma.c2
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c4
-rw-r--r--drivers/infiniband/core/verbs.c2
-rw-r--r--drivers/infiniband/hw/cxgb3/Makefile1
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.c32
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.h5
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_resource.c14
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c25
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_ev.c12
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c42
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.h34
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c31
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes.h6
-rw-r--r--drivers/infiniband/hw/ehca/ehca_cq.c16
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c59
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c4
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mr.c10
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c10
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h1
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c46
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c13
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c13
-rw-r--r--drivers/input/keyboard/Kconfig10
-rw-r--r--drivers/input/keyboard/gpio_keys.c4
-rw-r--r--drivers/input/serio/i8042.c10
-rw-r--r--drivers/isdn/capi/Kconfig16
-rw-r--r--drivers/isdn/capi/capidrv.c28
-rw-r--r--drivers/isdn/capi/capiutil.c254
-rw-r--r--drivers/isdn/capi/kcapi.c77
-rw-r--r--drivers/isdn/gigaset/Makefile9
-rw-r--r--drivers/isdn/gigaset/asyncdata.c5
-rw-r--r--drivers/kvm/kvm.h13
-rw-r--r--drivers/kvm/kvm_main.c776
-rw-r--r--drivers/kvm/kvm_svm.h3
-rw-r--r--drivers/kvm/mmu.c36
-rw-r--r--drivers/kvm/paging_tmpl.h18
-rw-r--r--drivers/kvm/svm.c42
-rw-r--r--drivers/kvm/vmx.c33
-rw-r--r--drivers/leds/Kconfig12
-rw-r--r--drivers/leds/Makefile2
-rw-r--r--drivers/leds/leds-cobalt.c43
-rw-r--r--drivers/leds/leds-h1940.c163
-rw-r--r--drivers/md/md.c140
-rw-r--r--drivers/md/raid10.c38
-rw-r--r--drivers/md/raid5.c161
-rw-r--r--drivers/md/raid6mmx.c16
-rw-r--r--drivers/md/raid6sse1.c17
-rw-r--r--drivers/md/raid6sse2.c22
-rw-r--r--drivers/md/raid6x86.h218
-rw-r--r--drivers/media/Kconfig1
-rw-r--r--drivers/media/common/Kconfig4
-rw-r--r--drivers/media/common/ir-functions.c110
-rw-r--r--drivers/media/common/ir-keymaps.c171
-rw-r--r--drivers/media/common/saa7146_fops.c2
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c90
-rw-r--r--drivers/media/dvb/bt8xx/bt878.c1
-rw-r--r--drivers/media/dvb/bt8xx/dst.c2
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.c3
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c5
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c71
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c17
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig28
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile9
-rw-r--r--drivers/media/dvb/dvb-usb/au6610.c255
-rw-r--r--drivers/media/dvb/dvb-usb/au6610.h19
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c4
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h5
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c2
-rw-r--r--drivers/media/dvb/dvb-usb/gl861.c231
-rw-r--r--drivers/media/dvb/dvb-usb/gl861.h15
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.c541
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.h35
-rw-r--r--drivers/media/dvb/frontends/Kconfig7
-rw-r--r--drivers/media/dvb/frontends/Makefile1
-rw-r--r--drivers/media/dvb/frontends/cx24110.c4
-rw-r--r--drivers/media/dvb/frontends/cx24123.c6
-rw-r--r--drivers/media/dvb/frontends/dib3000mc.c2
-rw-r--r--drivers/media/dvb/frontends/qt1010.c485
-rw-r--r--drivers/media/dvb/frontends/qt1010.h53
-rw-r--r--drivers/media/dvb/frontends/qt1010_priv.h105
-rw-r--r--drivers/media/dvb/frontends/stv0297.c19
-rw-r--r--drivers/media/dvb/frontends/stv0299.c2
-rw-r--r--drivers/media/dvb/frontends/tda10021.c2
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c2
-rw-r--r--drivers/media/dvb/frontends/zl10353.c103
-rw-r--r--drivers/media/dvb/frontends/zl10353.h3
-rw-r--r--drivers/media/dvb/frontends/zl10353_priv.h36
-rw-r--r--drivers/media/dvb/ttpci/av7110.c57
-rw-r--r--drivers/media/dvb/ttpci/av7110.h2
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.c42
-rw-r--r--drivers/media/dvb/ttpci/av7110_ca.c22
-rw-r--r--drivers/media/dvb/ttpci/av7110_ir.c18
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c30
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c3
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c55
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusb_dec.c4
-rw-r--r--drivers/media/radio/radio-aztech.c278
-rw-r--r--drivers/media/radio/radio-gemtek-pci.c18
-rw-r--r--drivers/media/radio/radio-maxiradio.c354
-rw-r--r--drivers/media/video/Kconfig2
-rw-r--r--drivers/media/video/Makefile1
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c23
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c893
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c157
-rw-r--r--drivers/media/video/bt8xx/bttv-risc.c171
-rw-r--r--drivers/media/video/bt8xx/bttv-vbi.c368
-rw-r--r--drivers/media/video/bt8xx/bttv.h27
-rw-r--r--drivers/media/video/bt8xx/bttvp.h90
-rw-r--r--drivers/media/video/cafe_ccic.c6
-rw-r--r--drivers/media/video/cpia.c11
-rw-r--r--drivers/media/video/cx2341x.c17
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c28
-rw-r--r--drivers/media/video/cx25840/cx25840-firmware.c2
-rw-r--r--drivers/media/video/cx88/Makefile5
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c581
-rw-r--r--drivers/media/video/cx88/cx88-cards.c6
-rw-r--r--drivers/media/video/cx88/cx88-core.c102
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c10
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c2
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c49
-rw-r--r--drivers/media/video/cx88/cx88-vbi.c11
-rw-r--r--drivers/media/video/cx88/cx88-video.c1166
-rw-r--r--drivers/media/video/cx88/cx88.h55
-rw-r--r--drivers/media/video/et61x251/et61x251.h5
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c129
-rw-r--r--drivers/media/video/et61x251/et61x251_sensor.h4
-rw-r--r--drivers/media/video/et61x251/et61x251_tas5130d1b.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-audio.c46
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-context.c3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ctrl.c45
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c27
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debugifc.c4
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-eeprom.c5
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-encoder.c269
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h62
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h36
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c510
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.h44
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c16
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c69
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c41
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.h3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-io.c3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ioread.c3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-std.c28
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-sysfs.c52
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-tuner.c3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c339
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-video-v4l.c29
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-wm8775.c28
-rw-r--r--drivers/media/video/pwc/Makefile8
-rw-r--r--drivers/media/video/pwc/pwc-if.c8
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c2
-rw-r--r--drivers/media/video/pwc/pwc.h9
-rw-r--r--drivers/media/video/saa5246a.c10
-rw-r--r--drivers/media/video/saa5246a.h9
-rw-r--r--drivers/media/video/saa5249.c41
-rw-r--r--drivers/media/video/saa7115.c59
-rw-r--r--drivers/media/video/saa7127.c20
-rw-r--r--drivers/media/video/saa7134/Makefile4
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c140
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c12
-rw-r--r--drivers/media/video/saa7134/saa7134-i2c.c24
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c93
-rw-r--r--drivers/media/video/saa7134/saa7134.h30
-rw-r--r--drivers/media/video/sn9c102/Kconfig4
-rw-r--r--drivers/media/video/sn9c102/Makefile2
-rw-r--r--drivers/media/video/sn9c102/sn9c102.h57
-rw-r--r--drivers/media/video/sn9c102/sn9c102_config.h86
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c719
-rw-r--r--drivers/media/video/sn9c102/sn9c102_devtable.h142
-rw-r--r--drivers/media/video/sn9c102/sn9c102_hv7131d.c7
-rw-r--r--drivers/media/video/sn9c102/sn9c102_mi0343.c7
-rw-r--r--drivers/media/video/sn9c102/sn9c102_ov7630.c336
-rw-r--r--drivers/media/video/sn9c102/sn9c102_ov7660.c592
-rw-r--r--drivers/media/video/sn9c102/sn9c102_pas106b.c7
-rw-r--r--drivers/media/video/sn9c102/sn9c102_pas202bca.c238
-rw-r--r--drivers/media/video/sn9c102/sn9c102_pas202bcb.c97
-rw-r--r--drivers/media/video/sn9c102/sn9c102_sensor.h168
-rw-r--r--drivers/media/video/sn9c102/sn9c102_tas5110c1b.c8
-rw-r--r--drivers/media/video/sn9c102/sn9c102_tas5130d1b.c8
-rw-r--r--drivers/media/video/tvmixer.c3
-rw-r--r--drivers/media/video/tvp5150.c20
-rw-r--r--drivers/media/video/upd64031a.c22
-rw-r--r--drivers/media/video/upd64083.c22
-rw-r--r--drivers/media/video/usbvision/Kconfig2
-rw-r--r--drivers/media/video/usbvision/usbvision-core.c70
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c174
-rw-r--r--drivers/media/video/usbvision/usbvision.h11
-rw-r--r--drivers/media/video/v4l1-compat.c2
-rw-r--r--drivers/media/video/v4l2-common.c628
-rw-r--r--drivers/media/video/video-buf.c3
-rw-r--r--drivers/media/video/videodev.c56
-rw-r--r--drivers/media/video/vivi.c102
-rw-r--r--drivers/media/video/zc0301/zc0301.h4
-rw-r--r--drivers/media/video/zc0301/zc0301_core.c55
-rw-r--r--drivers/media/video/zc0301/zc0301_pas202bcb.c4
-rw-r--r--drivers/media/video/zc0301/zc0301_pb0330.c4
-rw-r--r--drivers/media/video/zc0301/zc0301_sensor.h12
-rw-r--r--drivers/mfd/sm501.c2
-rw-r--r--drivers/mmc/mmc.c83
-rw-r--r--drivers/mmc/sdhci.c39
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c2
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0020.c2
-rw-r--r--drivers/mtd/maps/dilnetpc.c4
-rw-r--r--drivers/mtd/maps/esb2rom.c11
-rw-r--r--drivers/mtd/mtdconcat.c1
-rw-r--r--drivers/mtd/mtdpart.c7
-rw-r--r--drivers/mtd/nand/diskonchip.c2
-rw-r--r--drivers/mtd/nand/nand_base.c1
-rw-r--r--drivers/mtd/nand/s3c2410.c2
-rw-r--r--drivers/mtd/onenand/onenand_base.c77
-rw-r--r--drivers/net/3c59x.c36
-rw-r--r--drivers/net/8139cp.c3
-rw-r--r--drivers/net/Kconfig8
-rw-r--r--drivers/net/acenic.c5
-rw-r--r--drivers/net/amd8111e.c3
-rw-r--r--drivers/net/atl1/atl1_main.c5
-rw-r--r--drivers/net/bnx2.c4
-rw-r--r--drivers/net/bonding/bond_main.c100
-rw-r--r--drivers/net/chelsio/cxgb2.c3
-rw-r--r--drivers/net/chelsio/sge.c1
-rw-r--r--drivers/net/cxgb3/adapter.h11
-rw-r--r--drivers/net/cxgb3/cxgb3_ioctl.h33
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c69
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.c6
-rw-r--r--drivers/net/cxgb3/sge.c390
-rw-r--r--drivers/net/cxgb3/t3_hw.c6
-rw-r--r--drivers/net/cxgb3/version.h4
-rw-r--r--drivers/net/de600.c6
-rw-r--r--drivers/net/e1000/e1000_main.c25
-rw-r--r--drivers/net/ehea/ehea_main.c3
-rw-r--r--drivers/net/forcedeth.c20
-rw-r--r--drivers/net/gianfar.c3
-rw-r--r--drivers/net/ixgb/ixgb_main.c5
-rw-r--r--drivers/net/lasi_82596.c34
-rw-r--r--drivers/net/mv643xx_eth.c69
-rw-r--r--drivers/net/mv643xx_eth.h15
-rw-r--r--drivers/net/myri10ge/myri10ge.c91
-rw-r--r--drivers/net/natsemi.c26
-rw-r--r--drivers/net/netxen/netxen_nic.h4
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c144
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c19
-rw-r--r--drivers/net/netxen/netxen_nic_init.c28
-rw-r--r--drivers/net/netxen/netxen_nic_main.c19
-rw-r--r--drivers/net/netxen/netxen_nic_phan_reg.h3
-rw-r--r--drivers/net/ni52.c2
-rw-r--r--drivers/net/ns83820.c3
-rw-r--r--drivers/net/pcnet32.c4
-rw-r--r--drivers/net/pppoe.c53
-rwxr-xr-xdrivers/net/qla3xxx.c492
-rwxr-xr-xdrivers/net/qla3xxx.h11
-rw-r--r--drivers/net/r8169.c17
-rw-r--r--drivers/net/s2io-regs.h1
-rw-r--r--drivers/net/s2io.c302
-rw-r--r--drivers/net/s2io.h10
-rw-r--r--drivers/net/sgiseeq.c11
-rw-r--r--drivers/net/sis900.c10
-rw-r--r--drivers/net/skfp/cfm.c2
-rw-r--r--drivers/net/skge.c47
-rw-r--r--drivers/net/skge.h3
-rw-r--r--drivers/net/sky2.c27
-rw-r--r--drivers/net/spider_net.c554
-rw-r--r--drivers/net/spider_net.h34
-rw-r--r--drivers/net/starfire.c5
-rw-r--r--drivers/net/sun3_82586.c2
-rw-r--r--drivers/net/sungem_phy.c389
-rw-r--r--drivers/net/sungem_phy.h10
-rw-r--r--drivers/net/tc35815.c23
-rw-r--r--drivers/net/tg3.c23
-rw-r--r--drivers/net/tg3.h2
-rw-r--r--drivers/net/tokenring/ibmtr.c25
-rw-r--r--drivers/net/tulip/de2104x.c8
-rw-r--r--drivers/net/tulip/dmfe.c204
-rw-r--r--drivers/net/tulip/tulip_core.c2
-rw-r--r--drivers/net/typhoon.c3
-rw-r--r--drivers/net/ucc_geth.c21
-rw-r--r--drivers/net/via-rhine.c32
-rw-r--r--drivers/net/wan/cosa.c1
-rw-r--r--drivers/net/wan/hdlc.c33
-rw-r--r--drivers/net/wan/hdlc_cisco.c3
-rw-r--r--drivers/net/wan/hdlc_fr.c3
-rw-r--r--drivers/net/wan/hdlc_ppp.c2
-rw-r--r--drivers/net/wan/hdlc_raw.c3
-rw-r--r--drivers/net/wan/hdlc_x25.c2
-rw-r--r--drivers/net/wan/z85230.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c11
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.c10
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_wx.c10
-rw-r--r--drivers/net/wireless/wl3501_cs.c1
-rw-r--r--drivers/parisc/hppb.c14
-rw-r--r--drivers/parisc/iosapic_private.h2
-rw-r--r--drivers/parisc/lba_pci.c90
-rw-r--r--drivers/parisc/led.c14
-rw-r--r--drivers/parisc/power.c201
-rw-r--r--drivers/parisc/sba_iommu.c4
-rw-r--r--drivers/pci/msi.c146
-rw-r--r--drivers/pci/pci.c34
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--drivers/pci/probe.c45
-rw-r--r--drivers/pci/quirks.c87
-rw-r--r--drivers/pcmcia/hd64465_ss.c2
-rw-r--r--drivers/pcmcia/m32r_cfc.c2
-rw-r--r--drivers/pcmcia/m8xx_pcmcia.c2
-rw-r--r--drivers/pcmcia/omap_cf.c2
-rw-r--r--drivers/pcmcia/rsrc_mgr.c2
-rw-r--r--drivers/pcmcia/vrc4171_card.c2
-rw-r--r--drivers/rtc/Kconfig8
-rw-r--r--drivers/rtc/class.c14
-rw-r--r--drivers/rtc/interface.c3
-rw-r--r--drivers/rtc/rtc-pcf8583.c29
-rw-r--r--drivers/s390/block/dasd_eer.c1
-rw-r--r--drivers/s390/char/sclp_quiesce.c1
-rw-r--r--drivers/s390/char/tape_std.c5
-rw-r--r--drivers/s390/cio/cio.c3
-rw-r--r--drivers/s390/cio/device_fsm.c117
-rw-r--r--drivers/s390/net/qeth_main.c25
-rw-r--r--drivers/sbus/char/Kconfig7
-rw-r--r--drivers/sbus/char/Makefile1
-rw-r--r--drivers/sbus/char/aurora.c2364
-rw-r--r--drivers/sbus/char/aurora.h276
-rw-r--r--drivers/sbus/char/bbc_i2c.c17
-rw-r--r--drivers/sbus/char/cd180.h240
-rw-r--r--drivers/sbus/char/uctrl.c8
-rw-r--r--drivers/scsi/arm/cumana_2.c4
-rw-r--r--drivers/scsi/arm/eesox.c4
-rw-r--r--drivers/scsi/arm/fas216.c9
-rw-r--r--drivers/scsi/arm/powertec.c5
-rw-r--r--drivers/scsi/arm/scsi.h2
-rw-r--r--drivers/serial/dz.c7
-rw-r--r--drivers/serial/mcfserial.c44
-rw-r--r--drivers/serial/mux.c167
-rw-r--r--drivers/serial/serial_txx9.c276
-rw-r--r--drivers/serial/sn_console.c52
-rw-r--r--drivers/usb/core/Makefile2
-rw-r--r--drivers/usb/core/driver.c69
-rw-r--r--drivers/usb/core/hub.c3
-rw-r--r--drivers/usb/core/message.c6
-rw-r--r--drivers/usb/core/quirks.c77
-rw-r--r--drivers/usb/core/sysfs.c111
-rw-r--r--drivers/usb/core/usb.c12
-rw-r--r--drivers/usb/core/usb.h9
-rw-r--r--drivers/usb/gadget/inode.c5
-rw-r--r--drivers/usb/host/uhci-debug.c57
-rw-r--r--drivers/usb/host/uhci-hcd.c58
-rw-r--r--drivers/usb/host/uhci-hcd.h82
-rw-r--r--drivers/usb/host/uhci-q.c219
-rw-r--r--drivers/usb/input/hid-core.c56
-rw-r--r--drivers/usb/input/usbkbd.c4
-rw-r--r--drivers/usb/input/usbmouse.c4
-rw-r--r--drivers/usb/input/wacom_wac.c103
-rw-r--r--drivers/usb/input/wacom_wac.h1
-rw-r--r--drivers/usb/misc/Kconfig14
-rw-r--r--drivers/usb/misc/Makefile1
-rw-r--r--drivers/usb/misc/iowarrior.c925
-rw-r--r--drivers/usb/mon/mon_bin.c2
-rw-r--r--drivers/usb/mon/mon_text.c2
-rw-r--r--drivers/usb/mon/usb_mon.h4
-rw-r--r--drivers/usb/net/Kconfig9
-rw-r--r--drivers/usb/net/Makefile1
-rw-r--r--drivers/usb/net/asix.c14
-rw-r--r--drivers/usb/net/dm9601.c606
-rw-r--r--drivers/usb/serial/ftdi_sio.c1
-rw-r--r--drivers/usb/serial/ftdi_sio.h6
-rw-r--r--drivers/usb/serial/option.c117
-rw-r--r--drivers/usb/storage/usb.c4
-rw-r--r--drivers/video/Kconfig19
-rw-r--r--drivers/video/aty/aty128fb.c12
-rw-r--r--drivers/video/aty/atyfb.h3
-rw-r--r--drivers/video/aty/atyfb_base.c13
-rw-r--r--drivers/video/aty/mach64_ct.c3
-rw-r--r--drivers/video/aty/radeon_base.c13
-rw-r--r--drivers/video/nvidia/nv_backlight.c9
-rw-r--r--drivers/video/nvidia/nvidia.c12
-rw-r--r--drivers/video/riva/fbdev.c12
-rw-r--r--drivers/video/s3fb.c6
-rw-r--r--drivers/video/sm501fb.c16
530 files changed, 19105 insertions, 12159 deletions
diff --git a/drivers/acorn/char/Makefile b/drivers/acorn/char/Makefile
index 2fa9a8bf48a..d006c9f168d 100644
--- a/drivers/acorn/char/Makefile
+++ b/drivers/acorn/char/Makefile
@@ -2,5 +2,4 @@
# Makefile for the acorn character device drivers.
#
-obj-$(CONFIG_ARCH_ACORN) += i2c.o pcf8583.o
obj-$(CONFIG_L7200_KEYB) += defkeymap-l7200.o keyb_l7200.o
diff --git a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c
deleted file mode 100644
index d276fd14d63..00000000000
--- a/drivers/acorn/char/i2c.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * linux/drivers/acorn/char/i2c.c
- *
- * Copyright (C) 2000 Russell King
- *
- * 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.
- *
- * ARM IOC/IOMD i2c driver.
- *
- * On Acorn machines, the following i2c devices are on the bus:
- * - PCF8583 real time clock & static RAM
- */
-#include <linux/capability.h>
-#include <linux/init.h>
-#include <linux/time.h>
-#include <linux/miscdevice.h>
-#include <linux/rtc.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <linux/fs.h>
-
-#include <asm/hardware.h>
-#include <asm/io.h>
-#include <asm/hardware/ioc.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#include "pcf8583.h"
-
-extern int (*set_rtc)(void);
-
-static struct i2c_client *rtc_client;
-static const unsigned char days_in_mon[] =
- { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-
-#define CMOS_CHECKSUM (63)
-
-/*
- * Acorn machines store the year in the static RAM at
- * location 128.
- */
-#define CMOS_YEAR (64 + 128)
-
-static inline int rtc_command(int cmd, void *data)
-{
- int ret = -EIO;
-
- if (rtc_client)
- ret = rtc_client->driver->command(rtc_client, cmd, data);
-
- return ret;
-}
-
-/*
- * Update the century + year bytes in the CMOS RAM, ensuring
- * that the check byte is correctly adjusted for the change.
- */
-static int rtc_update_year(unsigned int new_year)
-{
- unsigned char yr[2], chk;
- struct mem cmos_year = { CMOS_YEAR, sizeof(yr), yr };
- struct mem cmos_check = { CMOS_CHECKSUM, 1, &chk };
- int ret;
-
- ret = rtc_command(MEM_READ, &cmos_check);
- if (ret)
- goto out;
- ret = rtc_command(MEM_READ, &cmos_year);
- if (ret)
- goto out;
-
- chk -= yr[1] + yr[0];
-
- yr[1] = new_year / 100;
- yr[0] = new_year % 100;
-
- chk += yr[1] + yr[0];
-
- ret = rtc_command(MEM_WRITE, &cmos_year);
- if (ret == 0)
- ret = rtc_command(MEM_WRITE, &cmos_check);
- out:
- return ret;
-}
-
-/*
- * Read the current RTC time and date, and update xtime.
- */
-static void get_rtc_time(struct rtc_tm *rtctm, unsigned int *year)
-{
- unsigned char ctrl, yr[2];
- struct mem rtcmem = { CMOS_YEAR, sizeof(yr), yr };
- int real_year, year_offset;
-
- /*
- * Ensure that the RTC is running.
- */
- rtc_command(RTC_GETCTRL, &ctrl);
- if (ctrl & 0xc0) {
- unsigned char new_ctrl = ctrl & ~0xc0;
-
- printk(KERN_WARNING "RTC: resetting control %02x -> %02x\n",
- ctrl, new_ctrl);
-
- rtc_command(RTC_SETCTRL, &new_ctrl);
- }
-
- if (rtc_command(RTC_GETDATETIME, rtctm) ||
- rtc_command(MEM_READ, &rtcmem))
- return;
-
- real_year = yr[0];
-
- /*
- * The RTC year holds the LSB two bits of the current
- * year, which should reflect the LSB two bits of the
- * CMOS copy of the year. Any difference indicates
- * that we have to correct the CMOS version.
- */
- year_offset = rtctm->year_off - (real_year & 3);
- if (year_offset < 0)
- /*
- * RTC year wrapped. Adjust it appropriately.
- */
- year_offset += 4;
-
- *year = real_year + year_offset + yr[1] * 100;
-}
-
-static int set_rtc_time(struct rtc_tm *rtctm, unsigned int year)
-{
- unsigned char leap;
- int ret;
-
- leap = (!(year % 4) && (year % 100)) || !(year % 400);
-
- if (rtctm->mon > 12 || rtctm->mon == 0 || rtctm->mday == 0)
- return -EINVAL;
-
- if (rtctm->mday > (days_in_mon[rtctm->mon] + (rtctm->mon == 2 && leap)))
- return -EINVAL;
-
- if (rtctm->hours >= 24 || rtctm->mins >= 60 || rtctm->secs >= 60)
- return -EINVAL;
-
- /*
- * The RTC's own 2-bit year must reflect the least
- * significant two bits of the CMOS year.
- */
- rtctm->year_off = (year % 100) & 3;
-
- ret = rtc_command(RTC_SETDATETIME, rtctm);
- if (ret == 0)
- ret = rtc_update_year(year);
-
- return ret;
-}
-
-/*
- * Set the RTC time only. Note that
- * we do not touch the date.
- */
-static int k_set_rtc_time(void)
-{
- struct rtc_tm new_rtctm, old_rtctm;
- unsigned long nowtime = xtime.tv_sec;
-
- if (rtc_command(RTC_GETDATETIME, &old_rtctm))
- return 0;
-
- new_rtctm.cs = xtime.tv_nsec / 10000000;
- new_rtctm.secs = nowtime % 60; nowtime /= 60;
- new_rtctm.mins = nowtime % 60; nowtime /= 60;
- new_rtctm.hours = nowtime % 24;
-
- /*
- * avoid writing when we're going to change the day
- * of the month. We will retry in the next minute.
- * This basically means that if the RTC must not drift
- * by more than 1 minute in 11 minutes.
- *
- * [ rtc: 1/1/2000 23:58:00, real 2/1/2000 00:01:00,
- * rtc gets set to 1/1/2000 00:01:00 ]
- */
- if ((old_rtctm.hours == 23 && old_rtctm.mins == 59) ||
- (new_rtctm.hours == 23 && new_rtctm.mins == 59))
- return 1;
-
- return rtc_command(RTC_SETTIME, &new_rtctm);
-}
-
-static int rtc_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- unsigned int year;
- struct rtc_time rtctm;
- struct rtc_tm rtc_raw;
-
- switch (cmd) {
- case RTC_ALM_READ:
- case RTC_ALM_SET:
- break;
-
- case RTC_RD_TIME:
- memset(&rtctm, 0, sizeof(struct rtc_time));
- get_rtc_time(&rtc_raw, &year);
- rtctm.tm_sec = rtc_raw.secs;
- rtctm.tm_min = rtc_raw.mins;
- rtctm.tm_hour = rtc_raw.hours;
- rtctm.tm_mday = rtc_raw.mday;
- rtctm.tm_mon = rtc_raw.mon - 1; /* month starts at 0 */
- rtctm.tm_year = year - 1900; /* starts at 1900 */
- return copy_to_user((void *)arg, &rtctm, sizeof(rtctm))
- ? -EFAULT : 0;
-
- case RTC_SET_TIME:
- if (!capable(CAP_SYS_TIME))
- return -EACCES;
-
- if (copy_from_user(&rtctm, (void *)arg, sizeof(rtctm)))
- return -EFAULT;
- rtc_raw.secs = rtctm.tm_sec;
- rtc_raw.mins = rtctm.tm_min;
- rtc_raw.hours = rtctm.tm_hour;
- rtc_raw.mday = rtctm.tm_mday;
- rtc_raw.mon = rtctm.tm_mon + 1;
- year = rtctm.tm_year + 1900;
- return set_rtc_time(&rtc_raw, year);
- break;
-
- case RTC_EPOCH_READ:
- return put_user(1900, (unsigned long *)arg);
-
- }
- return -EINVAL;
-}
-
-static const struct file_operations rtc_fops = {
- .ioctl = rtc_ioctl,
-};
-
-static struct miscdevice rtc_dev = {
- .minor = RTC_MINOR,
- .name = "rtc",
- .fops = &rtc_fops,
-};
-
-/* IOC / IOMD i2c driver */
-
-#define FORCE_ONES 0xdc
-#define SCL 0x02
-#define SDA 0x01
-
-/*
- * We must preserve all non-i2c output bits in IOC_CONTROL.
- * Note also that we need to preserve the value of SCL and
- * SDA outputs as well (which may be different from the
- * values read back from IOC_CONTROL).
- */
-static u_int force_ones;
-
-static void ioc_setscl(void *data, int state)
-{
- u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
- u_int ones = force_ones;
-
- if (state)
- ones |= SCL;
- else
- ones &= ~SCL;
-
- force_ones = ones;
-
- ioc_writeb(ioc_control | ones, IOC_CONTROL);
-}
-
-static void ioc_setsda(void *data, int state)
-{
- u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
- u_int ones = force_ones;
-
- if (state)
- ones |= SDA;
- else
- ones &= ~SDA;
-
- force_ones = ones;
-
- ioc_writeb(ioc_control | ones, IOC_CONTROL);
-}
-
-static int ioc_getscl(void *data)
-{
- return (ioc_readb(IOC_CONTROL) & SCL) != 0;
-}
-
-static int ioc_getsda(void *data)
-{
- return (ioc_readb(IOC_CONTROL) & SDA) != 0;
-}
-
-static struct i2c_algo_bit_data ioc_data = {
- .setsda = ioc_setsda,
- .setscl = ioc_setscl,
- .getsda = ioc_getsda,
- .getscl = ioc_getscl,
- .udelay = 80,
- .timeout = 100
-};
-
-static int ioc_client_reg(struct i2c_client *client)
-{
- if (client->driver->id == I2C_DRIVERID_PCF8583 &&
- client->addr == 0x50) {
- struct rtc_tm rtctm;
- unsigned int year;
- struct timespec tv;
-
- rtc_client = client;
- get_rtc_time(&rtctm, &year);
-
- tv.tv_nsec = rtctm.cs * 10000000;
- tv.tv_sec = mktime(year, rtctm.mon, rtctm.mday,
- rtctm.hours, rtctm.mins, rtctm.secs);
- do_settimeofday(&tv);
- set_rtc = k_set_rtc_time;
- }
-
- return 0;
-}
-
-static int ioc_client_unreg(struct i2c_client *client)
-{
- if (client == rtc_client) {
- set_rtc = NULL;
- rtc_client = NULL;
- }
-
- return 0;
-}
-
-static struct i2c_adapter ioc_ops = {
- .id = I2C_HW_B_IOC,
- .algo_data = &ioc_data,
- .client_register = ioc_client_reg,
- .client_unregister = ioc_client_unreg,
-};
-
-static int __init i2c_ioc_init(void)
-{
- int ret;
-
- force_ones = FORCE_ONES | SCL | SDA;
-
- ret = i2c_bit_add_bus(&ioc_ops);
-
- if (ret >= 0){
- ret = misc_register(&rtc_dev);
- if(ret < 0)
- i2c_del_adapter(&ioc_ops);
- }
-
- return ret;
-}
-
-__initcall(i2c_ioc_init);
diff --git a/drivers/acorn/char/pcf8583.c b/drivers/acorn/char/pcf8583.c
deleted file mode 100644
index 9b49f316ae9..00000000000
--- a/drivers/acorn/char/pcf8583.c
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * linux/drivers/acorn/char/pcf8583.c
- *
- * Copyright (C) 2000 Russell King
- *
- * 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.
- *
- * Driver for PCF8583 RTC & RAM chip
- */
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/mc146818rtc.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/bcd.h>
-
-#include "pcf8583.h"
-
-static struct i2c_driver pcf8583_driver;
-
-static unsigned short ignore[] = { I2C_CLIENT_END };
-static unsigned short normal_addr[] = { 0x50, I2C_CLIENT_END };
-static unsigned short *forces[] = { NULL };
-
-static struct i2c_client_address_data addr_data = {
- .normal_i2c = normal_addr,
- .probe = ignore,
- .ignore = ignore,
- .forces = forces,
-};
-
-#define set_ctrl(x, v) i2c_set_clientdata(x, (void *)(unsigned int)(v))
-#define get_ctrl(x) ((unsigned int)i2c_get_clientdata(x))
-
-static int
-pcf8583_attach(struct i2c_adapter *adap, int addr, int kind)
-{
- struct i2c_client *c;
- unsigned char buf[1], ad[1] = { 0 };
- struct i2c_msg msgs[2] = {
- {
- .addr = addr,
- .flags = 0,
- .len = 1,
- .buf = ad,
- }, {
- .addr = addr,
- .flags = I2C_M_RD,
- .len = 1,
- .buf = buf,
- }
- };
-
- c = kmalloc(sizeof(*c), GFP_KERNEL);
- if (!c)
- return -ENOMEM;
-
- memset(c, 0, sizeof(*c));
- c->addr = addr;
- c->adapter = adap;
- c->driver = &pcf8583_driver;
-
- if (i2c_transfer(c->adapter, msgs, 2) == 2)
- set_ctrl(c, buf[0]);
-
- return i2c_attach_client(c);
-}
-
-static int
-pcf8583_probe(struct i2c_adapter *adap)
-{
- return i2c_probe(adap, &addr_data, pcf8583_attach);
-}
-
-static int
-pcf8583_detach(struct i2c_client *client)
-{
- i2c_detach_client(client);
- kfree(client);
- return 0;
-}
-
-static int
-pcf8583_get_datetime(struct i2c_client *client, struct rtc_tm *dt)
-{
- unsigned char buf[8], addr[1] = { 1 };
- struct i2c_msg msgs[2] = {
- {
- .addr = client->addr,
- .flags = 0,
- .len = 1,
- .buf = addr,
- }, {
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = 6,
- .buf = buf,
- }
- };
- int ret = -EIO;
-
- memset(buf, 0, sizeof(buf));
-
- ret = i2c_transfer(client->adapter, msgs, 2);
- if (ret == 2) {
- dt->year_off = buf[4] >> 6;
- dt->wday = buf[5] >> 5;
-
- buf[4] &= 0x3f;
- buf[5] &= 0x1f;
-
- dt->cs = BCD_TO_BIN(buf[0]);
- dt->secs = BCD_TO_BIN(buf[1]);
- dt->mins = BCD_TO_BIN(buf[2]);
- dt->hours = BCD_TO_BIN(buf[3]);
- dt->mday = BCD_TO_BIN(buf[4]);
- dt->mon = BCD_TO_BIN(buf[5]);
-
- ret = 0;
- }
-
- return ret;
-}
-
-static int
-pcf8583_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo)
-{
- unsigned char buf[8];
- int ret, len = 6;
-
- buf[0] = 0;
- buf[1] = get_ctrl(client) | 0x80;
- buf[2] = BIN_TO_BCD(dt->cs);
- buf[3] = BIN_TO_BCD(dt->secs);
- buf[4] = BIN_TO_BCD(dt->mins);
- buf[5] = BIN_TO_BCD(dt->hours);
-
- if (datetoo) {
- len = 8;
- buf[6] = BIN_TO_BCD(dt->mday) | (dt->year_off << 6);
- buf[7] = BIN_TO_BCD(dt->mon) | (dt->wday << 5);
- }
-
- ret = i2c_master_send(client, (char *)buf, len);
- if (ret == len)
- ret = 0;
-
- buf[1] = get_ctrl(client);
- i2c_master_send(client, (char *)buf, 2);
-
- return ret;
-}
-
-static int
-pcf8583_get_ctrl(struct i2c_client *client, unsigned char *ctrl)
-{
- *ctrl = get_ctrl(client);
- return 0;
-}
-
-static int
-pcf8583_set_ctrl(struct i2c_client *client, unsigned char *ctrl)
-{
- unsigned char buf[2];
-
- buf[0] = 0;
- buf[1] = *ctrl;
- set_ctrl(client, *ctrl);
-
- return i2c_master_send(client, (char *)buf, 2);
-}
-
-static int
-pcf8583_read_mem(struct i2c_client *client, struct mem *mem)
-{
- unsigned char addr[1];
- struct i2c_msg msgs[2] = {
- {
- .addr = client->addr,
- .flags = 0,
- .len = 1,
- .buf = addr,
- }, {
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = mem->nr,
- .buf = mem->data,
- }
- };
-
- if (mem->loc < 8)
- return -EINVAL;
-
- addr[0] = mem->loc;
-
- return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
-}
-
-static int
-pcf8583_write_mem(struct i2c_client *client, struct mem *mem)
-{
- unsigned char addr[1];
- struct i2c_msg msgs[2] = {
- {
- .addr = client->addr,
- .flags = 0,
- .len = 1,
- .buf = addr,
- }, {
- .addr = client->addr,
- .flags = I2C_M_NOSTART,
- .len = mem->nr,
- .buf = mem->data,
- }
- };
-
- if (mem->loc < 8)
- return -EINVAL;
-
- addr[0] = mem->loc;
-
- return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
-}
-
-static int
-pcf8583_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
- switch (cmd) {
- case RTC_GETDATETIME:
- return pcf8583_get_datetime(client, arg);
-
- case RTC_SETTIME:
- return pcf8583_set_datetime(client, arg, 0);
-
- case RTC_SETDATETIME:
- return pcf8583_set_datetime(client, arg, 1);
-
- case RTC_GETCTRL:
- return pcf8583_get_ctrl(client, arg);
-
- case RTC_SETCTRL:
- return pcf8583_set_ctrl(client, arg);
-
- case MEM_READ:
- return pcf8583_read_mem(client, arg);
-
- case MEM_WRITE:
- return pcf8583_write_mem(client, arg);
-
- default:
- return -EINVAL;
- }
-}
-
-static struct i2c_driver pcf8583_driver = {
- .driver = {
- .name = "PCF8583",
- },
- .id = I2C_DRIVERID_PCF8583,
- .attach_adapter = pcf8583_probe,
- .detach_client = pcf8583_detach,
- .command = pcf8583_command
-};
-
-static __init int pcf8583_init(void)
-{
- return i2c_add_driver(&pcf8583_driver);
-}
-
-static __exit void pcf8583_exit(void)
-{
- i2c_del_driver(&pcf8583_driver);
-}
-
-module_init(pcf8583_init);
-module_exit(pcf8583_exit);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("PCF8583 I2C RTC driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/acorn/char/pcf8583.h b/drivers/acorn/char/pcf8583.h
deleted file mode 100644
index 847f7fdb876..00000000000
--- a/drivers/acorn/char/pcf8583.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * linux/drivers/acorn/char/pcf8583.h
- *
- * Copyright (C) 2000 Russell King
- *
- * 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.
- */
-struct rtc_tm {
- unsigned char cs;
- unsigned char secs;
- unsigned char mins;
- unsigned char hours;
- unsigned char mday;
- unsigned char mon;
- unsigned char year_off;
- unsigned char wday;
-};
-
-struct mem {
- unsigned int loc;
- unsigned int nr;
- unsigned char *data;
-};
-
-#define RTC_GETDATETIME 0
-#define RTC_SETTIME 1
-#define RTC_SETDATETIME 2
-#define RTC_GETCTRL 3
-#define RTC_SETCTRL 4
-#define MEM_READ 5
-#define MEM_WRITE 6
-
-#define CTRL_STOP 0x80
-#define CTRL_HOLD 0x40
-#define CTRL_32KHZ 0x00
-#define CTRL_MASK 0x08
-#define CTRL_ALARMEN 0x04
-#define CTRL_ALARM 0x02
-#define CTRL_TIMER 0x01
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index ee3dcd12182..4a3220b218d 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -149,6 +149,7 @@ config ACPI_DOCK
config ACPI_BAY
tristate "Removable Drive Bay (EXPERIMENTAL)"
depends on EXPERIMENTAL
+ depends on ACPI_DOCK
help
This driver adds support for ACPI controlled removable drive
bays such as the IBM ultrabay or the Dell Module Bay.
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 4af0a4bb578..d16b5b0c8b7 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -562,6 +562,15 @@ config PATA_IXP4XX_CF
If unsure, say N.
+config PATA_SCC
+ tristate "Toshiba's Cell Reference Set IDE support"
+ depends on PCI && PPC_IBM_CELL_BLADE
+ help
+ This option enables support for the built-in IDE controller on
+ Toshiba Cell Reference Board.
+
+ If unsure, say N.
+
endif
endmenu
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 74298afbbaa..13d7397e000 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -59,6 +59,7 @@ obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o
obj-$(CONFIG_PATA_SIS) += pata_sis.o
obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o
obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o
+obj-$(CONFIG_PATA_SCC) += pata_scc.o
obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o
# Should be last but one libata driver
obj-$(CONFIG_ATA_GENERIC) += ata_generic.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 6a3543e0624..dc7b5622592 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -46,7 +46,7 @@
#include <linux/libata.h>
#define DRV_NAME "ahci"
-#define DRV_VERSION "2.0"
+#define DRV_VERSION "2.1"
enum {
@@ -198,9 +198,9 @@ struct ahci_port_priv {
void *rx_fis;
dma_addr_t rx_fis_dma;
/* for NCQ spurious interrupt analysis */
- int ncq_saw_spurious_sdb_cnt;
unsigned int ncq_saw_d2h:1;
unsigned int ncq_saw_dmas:1;
+ unsigned int ncq_saw_sdb:1;
};
static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
@@ -219,10 +219,12 @@ static void ahci_thaw(struct ata_port *ap);
static void ahci_error_handler(struct ata_port *ap);
static void ahci_vt8251_error_handler(struct ata_port *ap);
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
+#ifdef CONFIG_PM
static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
static int ahci_port_resume(struct ata_port *ap);
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
static int ahci_pci_device_resume(struct pci_dev *pdev);
+#endif
static struct scsi_host_template ahci_sht = {
.module = THIS_MODULE,
@@ -241,8 +243,10 @@ static struct scsi_host_template ahci_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.suspend = ata_scsi_device_suspend,
.resume = ata_scsi_device_resume,
+#endif
};
static const struct ata_port_operations ahci_ops = {
@@ -271,8 +275,10 @@ static const struct ata_port_operations ahci_ops = {
.error_handler = ahci_error_handler,
.post_internal_cmd = ahci_post_internal_cmd,
+#ifdef CONFIG_PM
.port_suspend = ahci_port_suspend,
.port_resume = ahci_port_resume,
+#endif
.port_start = ahci_port_start,
.port_stop = ahci_port_stop,
@@ -304,8 +310,10 @@ static const struct ata_port_operations ahci_vt8251_ops = {
.error_handler = ahci_vt8251_error_handler,
.post_internal_cmd = ahci_post_internal_cmd,
+#ifdef CONFIG_PM
.port_suspend = ahci_port_suspend,
.port_resume = ahci_port_resume,
+#endif
.port_start = ahci_port_start,
.port_stop = ahci_port_stop,
@@ -381,16 +389,14 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */
{ PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */
{ PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x292c), board_ahci_pi }, /* ICH9M */
{ PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */
{ PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */
{ PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */
- /* JMicron */
- { PCI_VDEVICE(JMICRON, 0x2360), board_ahci_ign_iferr }, /* JMB360 */
- { PCI_VDEVICE(JMICRON, 0x2361), board_ahci_ign_iferr }, /* JMB361 */
- { PCI_VDEVICE(JMICRON, 0x2363), board_ahci_ign_iferr }, /* JMB363 */
- { PCI_VDEVICE(JMICRON, 0x2365), board_ahci_ign_iferr }, /* JMB365 */
- { PCI_VDEVICE(JMICRON, 0x2366), board_ahci_ign_iferr }, /* JMB366 */
+ /* JMicron 360/1/3/5/6, match class to avoid IDE function */
+ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
/* ATI */
{ PCI_VDEVICE(ATI, 0x4380), board_ahci }, /* ATI SB600 non-raid */
@@ -439,8 +445,10 @@ static struct pci_driver ahci_pci_driver = {
.id_table = ahci_pci_tbl,
.probe = ahci_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ahci_pci_device_suspend,
.resume = ahci_pci_device_resume,
+#endif
};
@@ -580,6 +588,7 @@ static void ahci_power_up(void __iomem *port_mmio, u32 cap)
writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
}
+#ifdef CONFIG_PM
static void ahci_power_down(void __iomem *port_mmio, u32 cap)
{
u32 cmd, scontrol;
@@ -597,6 +606,7 @@ static void ahci_power_down(void __iomem *port_mmio, u32 cap)
cmd &= ~PORT_CMD_SPIN_UP;
writel(cmd, port_mmio + PORT_CMD);
}
+#endif
static void ahci_init_port(void __iomem *port_mmio, u32 cap,
dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
@@ -1160,23 +1170,32 @@ static void ahci_host_intr(struct ata_port *ap)
known_irq = 1;
}
- if (status & PORT_IRQ_SDB_FIS &&
- pp->ncq_saw_spurious_sdb_cnt < 10) {
- /* SDB FIS containing spurious completions might be
- * dangerous, we need to know more about them. Print
- * more of it.
- */
+ if (status & PORT_IRQ_SDB_FIS) {
const __le32 *f = pp->rx_fis + RX_FIS_SDB;
- ata_port_printk(ap, KERN_INFO, "Spurious SDB FIS during NCQ "
- "issue=0x%x SAct=0x%x FIS=%08x:%08x%s\n",
+ if (le32_to_cpu(f[1])) {
+ /* SDB FIS containing spurious completions
+ * might be dangerous, whine and fail commands
+ * with HSM violation. EH will turn off NCQ
+ * after several such failures.
+ */
+ ata_ehi_push_desc(ehi,
+ "spurious completions during NCQ "
+ "issue=0x%x SAct=0x%x FIS=%08x:%08x",
readl(port_mmio + PORT_CMD_ISSUE),
readl(port_mmio + PORT_SCR_ACT),
- le32_to_cpu(f[0]), le32_to_cpu(f[1]),
- pp->ncq_saw_spurious_sdb_cnt < 10 ?
- "" : ", shutting up");
-
- pp->ncq_saw_spurious_sdb_cnt++;
+ le32_to_cpu(f[0]), le32_to_cpu(f[1]));
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ata_port_freeze(ap);
+ } else {
+ if (!pp->ncq_saw_sdb)
+ ata_port_printk(ap, KERN_INFO,
+ "spurious SDB FIS %08x:%08x during NCQ, "
+ "this message won't be printed again\n",
+ le32_to_cpu(f[0]), le32_to_cpu(f[1]));
+ pp->ncq_saw_sdb = 1;
+ }
known_irq = 1;
}
@@ -1329,6 +1348,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
}
}
+#ifdef CONFIG_PM
static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
@@ -1407,6 +1427,7 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
return 0;
}
+#endif
static int ahci_port_start(struct ata_port *ap)
{
@@ -1665,13 +1686,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- if (pdev->vendor == PCI_VENDOR_ID_JMICRON) {
- /* Function 1 is the PATA controller except on the 368, where
- we are not AHCI anyway */
- if (PCI_FUNC(pdev->devfn))
- return -ENODEV;
- }
-
rc = pcim_enable_device(pdev);
if (rc)
return rc;
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index be66ea08da5..d8e79882b88 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -26,7 +26,7 @@
#include <linux/libata.h>
#define DRV_NAME "ata_generic"
-#define DRV_VERSION "0.2.10"
+#define DRV_VERSION "0.2.11"
/*
* A generic parallel ATA driver using libata
@@ -90,10 +90,10 @@ static int generic_set_mode(struct ata_port *ap, struct ata_device **unused)
/* We do need the right mode information for DMA or PIO
and this comes from the current configuration flags */
if (dma_enabled & (1 << (5 + i))) {
- dev->xfer_mode = XFER_MW_DMA_0;
- dev->xfer_shift = ATA_SHIFT_MWDMA;
+ ata_id_to_dma_mode(dev, XFER_MW_DMA_0);
dev->flags &= ~ATA_DFLAG_PIO;
} else {
+ ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
dev->xfer_mode = XFER_PIO_0;
dev->xfer_shift = ATA_SHIFT_PIO;
dev->flags |= ATA_DFLAG_PIO;
@@ -119,8 +119,10 @@ static struct scsi_host_template generic_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations generic_port_ops = {
@@ -230,8 +232,10 @@ static struct pci_driver ata_generic_pci_driver = {
.id_table = ata_generic,
.probe = ata_generic_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static int __init ata_generic_init(void)
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 4d716c7347e..b952c584338 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -93,7 +93,7 @@
#include <linux/libata.h>
#define DRV_NAME "ata_piix"
-#define DRV_VERSION "2.00ac7"
+#define DRV_VERSION "2.10ac1"
enum {
PIIX_IOCFG = 0x54, /* IDE I/O configuration register */
@@ -169,8 +169,6 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* Intel PIIX4 for the 430TX/440BX/MX chipset: UDMA 33 */
/* Also PIIX4E (fn3 rev 2) and PIIX4M (fn3 rev 3) */
{ 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
- { 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
- { 0x8086, 0x25a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* Intel PIIX4 */
{ 0x8086, 0x7199, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
/* Intel PIIX4 */
@@ -255,8 +253,10 @@ static struct pci_driver piix_pci_driver = {
.id_table = piix_pci_tbl,
.probe = piix_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static struct scsi_host_template piix_sht = {
@@ -275,8 +275,10 @@ static struct scsi_host_template piix_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static const struct ata_port_operations piix_pata_ops = {
@@ -665,14 +667,9 @@ static int ich_pata_prereset(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) {
- ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
- ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
- return 0;
- }
-
+ if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
+ return -ENOENT;
ich_pata_cbl_detect(ap);
-
return ata_std_prereset(ap);
}
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index b4e8be5d292..019d8ffdde5 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -34,6 +34,13 @@ struct taskfile_array {
u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */
};
+/*
+ * Helper - belongs in the PCI layer somewhere eventually
+ */
+static int is_pci_dev(struct device *dev)
+{
+ return (dev->bus == &pci_bus_type);
+}
/**
* sata_get_dev_handle - finds acpi_handle and PCI device.function
@@ -53,6 +60,9 @@ static int sata_get_dev_handle(struct device *dev, acpi_handle *handle,
struct pci_dev *pci_dev;
acpi_integer addr;
+ if (!is_pci_dev(dev))
+ return -ENODEV;
+
pci_dev = to_pci_dev(dev); /* NOTE: PCI-specific */
/* Please refer to the ACPI spec for the syntax of _ADR. */
addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn);
@@ -84,7 +94,12 @@ static int pata_get_dev_handle(struct device *dev, acpi_handle *handle,
acpi_status status;
struct acpi_device_info *dinfo = NULL;
int ret = -ENODEV;
- struct pci_dev *pdev = to_pci_dev(dev);
+ struct pci_dev *pdev;
+
+ if (!is_pci_dev(dev))
+ return -ENODEV;
+
+ pdev = to_pci_dev(dev);
bus = pdev->bus->number;
devnum = PCI_SLOT(pdev->devfn);
@@ -294,9 +309,8 @@ static int do_drive_get_GTF(struct ata_port *ap, int ix,
return 0;
if (ata_msg_probe(ap))
- ata_dev_printk(atadev, KERN_DEBUG,
- "%s: ENTER: ap->id: %d, port#: %d\n",
- __FUNCTION__, ap->id, ap->port_no);
+ ata_dev_printk(atadev, KERN_DEBUG, "%s: ENTER: port#: %d\n",
+ __FUNCTION__, ap->port_no);
if (!ata_dev_enabled(atadev) || (ap->flags & ATA_FLAG_DISABLED)) {
if (ata_msg_probe(ap))
@@ -456,6 +470,9 @@ static void taskfile_load_raw(struct ata_port *ap,
struct ata_device *atadev,
const struct taskfile_array *gtf)
{
+ struct ata_taskfile tf;
+ unsigned int err;
+
if (ata_msg_probe(ap))
ata_dev_printk(atadev, KERN_DEBUG, "%s: (0x1f1-1f7): hex: "
"%02x %02x %02x %02x %02x %02x %02x\n",
@@ -468,35 +485,25 @@ static void taskfile_load_raw(struct ata_port *ap,
&& (gtf->tfa[6] == 0))
return;
- if (ap->ops->qc_issue) {
- struct ata_taskfile tf;
- unsigned int err;
-
- ata_tf_init(atadev, &tf);
-
- /* convert gtf to tf */
- tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */
- tf.protocol = atadev->class == ATA_DEV_ATAPI ?
- ATA_PROT_ATAPI_NODATA : ATA_PROT_NODATA;
- tf.feature = gtf->tfa[0]; /* 0x1f1 */
- tf.nsect = gtf->tfa[1]; /* 0x1f2 */
- tf.lbal = gtf->tfa[2]; /* 0x1f3 */
- tf.lbam = gtf->tfa[3]; /* 0x1f4 */
- tf.lbah = gtf->tfa[4]; /* 0x1f5 */
- tf.device = gtf->tfa[5]; /* 0x1f6 */
- tf.command = gtf->tfa[6]; /* 0x1f7 */
-
- err = ata_exec_internal(atadev, &tf, NULL, DMA_NONE, NULL, 0);
- if (err && ata_msg_probe(ap))
- ata_dev_printk(atadev, KERN_ERR,
- "%s: ata_exec_internal failed: %u\n",
- __FUNCTION__, err);
- } else
- if (ata_msg_warn(ap))
- ata_dev_printk(atadev, KERN_WARNING,
- "%s: SATA driver is missing qc_issue function"
- " entry points\n",
- __FUNCTION__);
+ ata_tf_init(atadev, &tf);
+
+ /* convert gtf to tf */
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */
+ tf.protocol = atadev->class == ATA_DEV_ATAPI ?
+ ATA_PROT_ATAPI_NODATA : ATA_PROT_NODATA;
+ tf.feature = gtf->tfa[0]; /* 0x1f1 */
+ tf.nsect = gtf->tfa[1]; /* 0x1f2 */
+ tf.lbal = gtf->tfa[2]; /* 0x1f3 */
+ tf.lbam = gtf->tfa[3]; /* 0x1f4 */
+ tf.lbah = gtf->tfa[4]; /* 0x1f5 */
+ tf.device = gtf->tfa[5]; /* 0x1f6 */
+ tf.command = gtf->tfa[6]; /* 0x1f7 */
+
+ err = ata_exec_internal(atadev, &tf, NULL, DMA_NONE, NULL, 0);
+ if (err && ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_ERR,
+ "%s: ata_exec_internal failed: %u\n",
+ __FUNCTION__, err);
}
/**
@@ -521,9 +528,8 @@ static int do_drive_set_taskfiles(struct ata_port *ap,
struct taskfile_array *gtf;
if (ata_msg_probe(ap))
- ata_dev_printk(atadev, KERN_DEBUG,
- "%s: ENTER: ap->id: %d, port#: %d\n",
- __FUNCTION__, ap->id, ap->port_no);
+ ata_dev_printk(atadev, KERN_DEBUG, "%s: ENTER: port#: %d\n",
+ __FUNCTION__, ap->port_no);
if (noacpi || !(ap->cbl == ATA_CBL_SATA))
return 0;
@@ -627,9 +633,8 @@ int ata_acpi_push_id(struct ata_port *ap, unsigned int ix)
return 0;
if (ata_msg_probe(ap))
- ata_dev_printk(atadev, KERN_DEBUG,
- "%s: ap->id: %d, ix = %d, port#: %d\n",
- __FUNCTION__, ap->id, ix, ap->port_no);
+ ata_dev_printk(atadev, KERN_DEBUG, "%s: ix = %d, port#: %d\n",
+ __FUNCTION__, ix, ap->port_no);
/* Don't continue if not a SATA device. */
if (!(ap->cbl == ATA_CBL_SATA)) {
@@ -685,9 +690,8 @@ int ata_acpi_push_id(struct ata_port *ap, unsigned int ix)
if (err < 0) {
if (ata_msg_probe(ap))
ata_dev_printk(atadev, KERN_DEBUG,
- "ata%u(%u): %s _SDD error: status = 0x%x\n",
- ap->id, ap->device->devno,
- __FUNCTION__, status);
+ "%s _SDD error: status = 0x%x\n",
+ __FUNCTION__, status);
}
/* always return success */
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index e900c5edefc..3c1f8830ac8 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -59,7 +59,7 @@
#include "libata.h"
-#define DRV_VERSION "2.10" /* must be exactly four chars */
+#define DRV_VERSION "2.20" /* must be exactly four chars */
/* debounce timing parameters in msecs { interval, duration, timeout } */
@@ -72,7 +72,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
static void ata_dev_xfermask(struct ata_device *dev);
-static unsigned int ata_unique_id = 1;
+static unsigned int ata_print_id = 1;
static struct workqueue_struct *ata_wq;
struct workqueue_struct *ata_aux_wq;
@@ -315,9 +315,7 @@ int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf->flags |= tf_flags;
- if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF |
- ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ &&
- likely(tag != ATA_TAG_INTERNAL)) {
+ if (ata_ncq_enabled(dev) && likely(tag != ATA_TAG_INTERNAL)) {
/* yay, NCQ */
if (!lba_48_ok(block, n_block))
return -ERANGE;
@@ -600,6 +598,8 @@ void ata_dev_disable(struct ata_device *dev)
{
if (ata_dev_enabled(dev) && ata_msg_drv(dev->ap)) {
ata_dev_printk(dev, KERN_WARNING, "disabled\n");
+ ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 |
+ ATA_DNXFER_QUIET);
dev->class++;
}
}
@@ -708,7 +708,7 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf)
* Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE.
*/
-static unsigned int
+unsigned int
ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
{
struct ata_taskfile tf;
@@ -824,6 +824,48 @@ static u64 ata_id_n_sectors(const u16 *id)
}
/**
+ * ata_id_to_dma_mode - Identify DMA mode from id block
+ * @dev: device to identify
+ * @mode: mode to assume if we cannot tell
+ *
+ * Set up the timing values for the device based upon the identify
+ * reported values for the DMA mode. This function is used by drivers
+ * which rely upon firmware configured modes, but wish to report the
+ * mode correctly when possible.
+ *
+ * In addition we emit similarly formatted messages to the default
+ * ata_dev_set_mode handler, in order to provide consistency of
+ * presentation.
+ */
+
+void ata_id_to_dma_mode(struct ata_device *dev, u8 unknown)
+{
+ unsigned int mask;
+ u8 mode;
+
+ /* Pack the DMA modes */
+ mask = ((dev->id[63] >> 8) << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA;
+ if (dev->id[53] & 0x04)
+ mask |= ((dev->id[88] >> 8) << ATA_SHIFT_UDMA) & ATA_MASK_UDMA;
+
+ /* Select the mode in use */
+ mode = ata_xfer_mask2mode(mask);
+
+ if (mode != 0) {
+ ata_dev_printk(dev, KERN_INFO, "configured for %s\n",
+ ata_mode_string(mask));
+ } else {
+ /* SWDMA perhaps ? */
+ mode = unknown;
+ ata_dev_printk(dev, KERN_INFO, "configured for DMA\n");
+ }
+
+ /* Configure the device reporting */
+ dev->xfer_mode = mode;
+ dev->xfer_shift = ata_xfer_mode2shift(mode);
+}
+
+/**
* ata_noop_dev_select - Select device 0/1 on ATA bus
* @ap: ATA channel to manipulate
* @device: ATA device (numbered from zero) to select
@@ -891,8 +933,8 @@ void ata_dev_select(struct ata_port *ap, unsigned int device,
unsigned int wait, unsigned int can_sleep)
{
if (ata_msg_probe(ap))
- ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, ata%u: "
- "device %u, wait %u\n", ap->id, device, wait);
+ ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, "
+ "device %u, wait %u\n", device, wait);
if (wait)
ata_wait_idle(ap);
@@ -1392,8 +1434,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
int rc;
if (ata_msg_ctl(ap))
- ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
- __FUNCTION__, ap->id, dev->devno);
+ ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__);
ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
@@ -1430,7 +1471,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
if (err_mask) {
if (err_mask & AC_ERR_NODEV_HINT) {
DPRINTK("ata%u.%d: NODEV after polling detection\n",
- ap->id, dev->devno);
+ ap->print_id, dev->devno);
return -ENOENT;
}
@@ -1558,15 +1599,13 @@ int ata_dev_configure(struct ata_device *dev)
int rc;
if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
- ata_dev_printk(dev, KERN_INFO,
- "%s: ENTER/EXIT (host %u, dev %u) -- nodev\n",
- __FUNCTION__, ap->id, dev->devno);
+ ata_dev_printk(dev, KERN_INFO, "%s: ENTER/EXIT -- nodev\n",
+ __FUNCTION__);
return 0;
}
if (ata_msg_probe(ap))
- ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
- __FUNCTION__, ap->id, dev->devno);
+ ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__);
/* set _SDD */
rc = ata_acpi_push_id(ap, dev->devno);
@@ -1610,8 +1649,9 @@ int ata_dev_configure(struct ata_device *dev)
if (dev->class == ATA_DEV_ATA) {
if (ata_id_is_cfa(id)) {
if (id[162] & 1) /* CPRM may make this media unusable */
- ata_dev_printk(dev, KERN_WARNING, "ata%u: device %u supports DRM functions and may not be fully accessable.\n",
- ap->id, dev->devno);
+ ata_dev_printk(dev, KERN_WARNING,
+ "supports DRM functions and may "
+ "not be fully accessable.\n");
snprintf(revbuf, 7, "CFA");
}
else
@@ -1679,7 +1719,7 @@ int ata_dev_configure(struct ata_device *dev)
"%s: %s, %s, max %s\n",
revbuf, modelbuf, fwrevbuf,
ata_mode_string(xfer_mask));
- ata_dev_printk(dev, KERN_INFO,
+ ata_dev_printk(dev, KERN_INFO,
"%Lu sectors, multi %u, CHS %u/%u/%u\n",
(unsigned long long)dev->n_sectors,
dev->multi_count, dev->cylinders,
@@ -1778,7 +1818,7 @@ int ata_bus_probe(struct ata_port *ap)
{
unsigned int classes[ATA_MAX_DEVICES];
int tries[ATA_MAX_DEVICES];
- int i, rc, down_xfermask;
+ int i, rc;
struct ata_device *dev;
ata_port_probe(ap);
@@ -1787,8 +1827,6 @@ int ata_bus_probe(struct ata_port *ap)
tries[i] = ATA_PROBE_MAX_TRIES;
retry:
- down_xfermask = 0;
-
/* reset and determine device classes */
ap->ops->phy_reset(ap);
@@ -1812,8 +1850,11 @@ int ata_bus_probe(struct ata_port *ap)
for (i = 0; i < ATA_MAX_DEVICES; i++)
ap->device[i].pio_mode = XFER_PIO_0;
- /* read IDENTIFY page and configure devices */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ /* read IDENTIFY page and configure devices. We have to do the identify
+ specific sequence bass-ackwards so that PDIAG- is released by
+ the slave device */
+
+ for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) {
dev = &ap->device[i];
if (tries[i])
@@ -1826,6 +1867,15 @@ int ata_bus_probe(struct ata_port *ap)
dev->id);
if (rc)
goto fail;
+ }
+
+ /* After the identify sequence we can now set up the devices. We do
+ this in the normal order so that the user doesn't get confused */
+
+ for(i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+ if (!ata_dev_enabled(dev))
+ continue;
ap->eh_context.i.flags |= ATA_EHI_PRINTINFO;
rc = ata_dev_configure(dev);
@@ -1836,10 +1886,8 @@ int ata_bus_probe(struct ata_port *ap)
/* configure transfer mode */
rc = ata_set_mode(ap, &dev);
- if (rc) {
- down_xfermask = 1;
+ if (rc)
goto fail;
- }
for (i = 0; i < ATA_MAX_DEVICES; i++)
if (ata_dev_enabled(&ap->device[i]))
@@ -1851,25 +1899,29 @@ int ata_bus_probe(struct ata_port *ap)
return -ENODEV;
fail:
+ tries[dev->devno]--;
+
switch (rc) {
case -EINVAL:
- case -ENODEV:
+ /* eeek, something went very wrong, give up */
tries[dev->devno] = 0;
break;
+
+ case -ENODEV:
+ /* give it just one more chance */
+ tries[dev->devno] = min(tries[dev->devno], 1);
case -EIO:
- sata_down_spd_limit(ap);
- /* fall through */
- default:
- tries[dev->devno]--;
- if (down_xfermask &&
- ata_down_xfermask_limit(dev, tries[dev->devno] == 1))
- tries[dev->devno] = 0;
+ if (tries[dev->devno] == 1) {
+ /* This is the last chance, better to slow
+ * down than lose it.
+ */
+ sata_down_spd_limit(ap);
+ ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
+ }
}
- if (!tries[dev->devno]) {
- ata_down_xfermask_limit(dev, 1);
+ if (!tries[dev->devno])
ata_dev_disable(dev);
- }
goto retry;
}
@@ -2300,7 +2352,7 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
/**
* ata_down_xfermask_limit - adjust dev xfer masks downward
* @dev: Device to adjust xfer masks
- * @force_pio0: Force PIO0
+ * @sel: ATA_DNXFER_* selector
*
* Adjust xfer masks of @dev downward. Note that this function
* does not apply the change. Invoking ata_set_mode() afterwards
@@ -2312,37 +2364,78 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
* RETURNS:
* 0 on success, negative errno on failure
*/
-int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0)
+int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel)
{
- unsigned long xfer_mask;
- int highbit;
+ char buf[32];
+ unsigned int orig_mask, xfer_mask;
+ unsigned int pio_mask, mwdma_mask, udma_mask;
+ int quiet, highbit;
- xfer_mask = ata_pack_xfermask(dev->pio_mask, dev->mwdma_mask,
- dev->udma_mask);
+ quiet = !!(sel & ATA_DNXFER_QUIET);
+ sel &= ~ATA_DNXFER_QUIET;
- if (!xfer_mask)
- goto fail;
- /* don't gear down to MWDMA from UDMA, go directly to PIO */
- if (xfer_mask & ATA_MASK_UDMA)
- xfer_mask &= ~ATA_MASK_MWDMA;
+ xfer_mask = orig_mask = ata_pack_xfermask(dev->pio_mask,
+ dev->mwdma_mask,
+ dev->udma_mask);
+ ata_unpack_xfermask(xfer_mask, &pio_mask, &mwdma_mask, &udma_mask);
- highbit = fls(xfer_mask) - 1;
- xfer_mask &= ~(1 << highbit);
- if (force_pio0)
- xfer_mask &= 1 << ATA_SHIFT_PIO;
- if (!xfer_mask)
- goto fail;
+ switch (sel) {
+ case ATA_DNXFER_PIO:
+ highbit = fls(pio_mask) - 1;
+ pio_mask &= ~(1 << highbit);
+ break;
+
+ case ATA_DNXFER_DMA:
+ if (udma_mask) {
+ highbit = fls(udma_mask) - 1;
+ udma_mask &= ~(1 << highbit);
+ if (!udma_mask)
+ return -ENOENT;
+ } else if (mwdma_mask) {
+ highbit = fls(mwdma_mask) - 1;
+ mwdma_mask &= ~(1 << highbit);
+ if (!mwdma_mask)
+ return -ENOENT;
+ }
+ break;
+
+ case ATA_DNXFER_40C:
+ udma_mask &= ATA_UDMA_MASK_40C;
+ break;
+
+ case ATA_DNXFER_FORCE_PIO0:
+ pio_mask &= 1;
+ case ATA_DNXFER_FORCE_PIO:
+ mwdma_mask = 0;
+ udma_mask = 0;
+ break;
+
+ default:
+ BUG();
+ }
+
+ xfer_mask &= ata_pack_xfermask(pio_mask, mwdma_mask, udma_mask);
+
+ if (!(xfer_mask & ATA_MASK_PIO) || xfer_mask == orig_mask)
+ return -ENOENT;
+
+ if (!quiet) {
+ if (xfer_mask & (ATA_MASK_MWDMA | ATA_MASK_UDMA))
+ snprintf(buf, sizeof(buf), "%s:%s",
+ ata_mode_string(xfer_mask),
+ ata_mode_string(xfer_mask & ATA_MASK_PIO));
+ else
+ snprintf(buf, sizeof(buf), "%s",
+ ata_mode_string(xfer_mask));
+
+ ata_dev_printk(dev, KERN_WARNING,
+ "limiting speed to %s\n", buf);
+ }
ata_unpack_xfermask(xfer_mask, &dev->pio_mask, &dev->mwdma_mask,
&dev->udma_mask);
- ata_dev_printk(dev, KERN_WARNING, "limiting speed to %s\n",
- ata_mode_string(xfer_mask));
-
return 0;
-
- fail:
- return -EINVAL;
}
static int ata_dev_set_mode(struct ata_device *dev)
@@ -2475,12 +2568,11 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
* host channels are not permitted to do so.
*/
if (used_dma && (ap->host->flags & ATA_HOST_SIMPLEX))
- ap->host->simplex_claimed = 1;
+ ap->host->simplex_claimed = ap;
/* step5: chip specific finalisation */
if (ap->ops->post_set_mode)
ap->ops->post_set_mode(ap);
-
out:
if (rc)
*r_failed_dev = dev;
@@ -2609,7 +2701,7 @@ static unsigned int ata_bus_softreset(struct ata_port *ap,
{
struct ata_ioports *ioaddr = &ap->ioaddr;
- DPRINTK("ata%u: bus reset via SRST\n", ap->id);
+ DPRINTK("ata%u: bus reset via SRST\n", ap->print_id);
/* software reset. causes dev0 to be selected */
iowrite8(ap->ctl, ioaddr->ctl_addr);
@@ -2669,7 +2761,7 @@ void ata_bus_reset(struct ata_port *ap)
u8 err;
unsigned int dev0, dev1 = 0, devmask = 0;
- DPRINTK("ENTER, host %u, port %u\n", ap->id, ap->port_no);
+ DPRINTK("ENTER, host %u, port %u\n", ap->print_id, ap->port_no);
/* determine if device 0/1 are present */
if (ap->flags & ATA_FLAG_SATA_RESET)
@@ -3256,7 +3348,6 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "WPI CDD-820", NULL, ATA_HORKAGE_NODMA },
{ "SAMSUNG CD-ROM SC-148C", NULL, ATA_HORKAGE_NODMA },
{ "SAMSUNG CD-ROM SC", NULL, ATA_HORKAGE_NODMA },
- { "SanDisk SDP3B-64", NULL, ATA_HORKAGE_NODMA },
{ "ATAPI CD-ROM DRIVE 40X MAXIMUM",NULL,ATA_HORKAGE_NODMA },
{ "_NEC DV5800A", NULL, ATA_HORKAGE_NODMA },
{ "SAMSUNG CD-ROM SN-124","N001", ATA_HORKAGE_NODMA },
@@ -3266,6 +3357,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* Devices where NCQ should be avoided */
/* NCQ is slow */
{ "WDC WD740ADFD-00", NULL, ATA_HORKAGE_NONCQ },
+ /* http://thread.gmane.org/gmane.linux.ide/14907 */
+ { "FUJITSU MHT2060BH", NULL, ATA_HORKAGE_NONCQ },
/* Devices with NCQ limits */
@@ -3362,7 +3455,8 @@ static void ata_dev_xfermask(struct ata_device *dev)
"device is on DMA blacklist, disabling DMA\n");
}
- if ((host->flags & ATA_HOST_SIMPLEX) && host->simplex_claimed) {
+ if ((host->flags & ATA_HOST_SIMPLEX) &&
+ host->simplex_claimed && host->simplex_claimed != ap) {
xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
ata_dev_printk(dev, KERN_WARNING, "simplex DMA is claimed by "
"other device, disabling DMA\n");
@@ -3739,7 +3833,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
struct scatterlist *lsg = &sg[qc->n_elem - 1];
int n_elem, pre_n_elem, dir, trim_sg = 0;
- VPRINTK("ENTER, ata%u\n", ap->id);
+ VPRINTK("ENTER, ata%u\n", ap->print_id);
WARN_ON(!(qc->flags & ATA_QCFLAG_SG));
/* we must lengthen transfers to end on a 32-bit boundary */
@@ -4140,7 +4234,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
if (do_write != i_write)
goto err_out;
- VPRINTK("ata%u: xfering %d bytes\n", ap->id, bytes);
+ VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes);
__atapi_pio_bytes(qc, bytes);
@@ -4257,7 +4351,7 @@ int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
fsm_start:
DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n",
- ap->id, qc->tf.protocol, ap->hsm_task_state, status);
+ ap->print_id, qc->tf.protocol, ap->hsm_task_state, status);
switch (ap->hsm_task_state) {
case HSM_ST_FIRST:
@@ -4290,8 +4384,8 @@ fsm_start:
* let the EH abort the command or reset the device.
*/
if (unlikely(status & (ATA_ERR | ATA_DF))) {
- printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n",
- ap->id, status);
+ ata_port_printk(ap, KERN_WARNING, "DRQ=1 with device "
+ "error, dev_stat 0x%X\n", status);
qc->err_mask |= AC_ERR_HSM;
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
@@ -4348,8 +4442,9 @@ fsm_start:
* let the EH abort the command or reset the device.
*/
if (unlikely(status & (ATA_ERR | ATA_DF))) {
- printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n",
- ap->id, status);
+ ata_port_printk(ap, KERN_WARNING, "DRQ=1 with "
+ "device error, dev_stat 0x%X\n",
+ status);
qc->err_mask |= AC_ERR_HSM;
ap->hsm_task_state = HSM_ST_ERR;
goto fsm_start;
@@ -4435,7 +4530,7 @@ fsm_start:
/* no more data to transfer */
DPRINTK("ata%u: dev %u command complete, drv_stat 0x%x\n",
- ap->id, qc->dev->devno, status);
+ ap->print_id, qc->dev->devno, status);
WARN_ON(qc->err_mask);
@@ -4977,7 +5072,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap,
u8 status, host_stat = 0;
VPRINTK("ata%u: protocol %d task_state %d\n",
- ap->id, qc->tf.protocol, ap->hsm_task_state);
+ ap->print_id, qc->tf.protocol, ap->hsm_task_state);
/* Check whether we are expecting interrupt in this state */
switch (ap->hsm_task_state) {
@@ -4998,7 +5093,8 @@ inline unsigned int ata_host_intr (struct ata_port *ap,
qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
/* check status of DMA engine */
host_stat = ap->ops->bmdma_status(ap);
- VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
+ VPRINTK("ata%u: host_stat 0x%X\n",
+ ap->print_id, host_stat);
/* if it's not our irq... */
if (!(host_stat & ATA_DMA_INTR))
@@ -5259,6 +5355,7 @@ int ata_flush_cache(struct ata_device *dev)
return 0;
}
+#ifdef CONFIG_PM
static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
unsigned int action, unsigned int ehi_flags,
int wait)
@@ -5374,6 +5471,7 @@ void ata_host_resume(struct ata_host *host)
ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
host->dev->power.power_state = PMSG_ON;
}
+#endif
/**
* ata_port_start - Set port up for dma.
@@ -5457,7 +5555,7 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host,
ap->lock = &host->lock;
ap->flags = ATA_FLAG_DISABLED;
- ap->id = ata_unique_id++;
+ ap->print_id = ata_print_id++;
ap->ctl = ATA_DEVCTL_OBS;
ap->host = host;
ap->dev = ent->dev;
@@ -5528,7 +5626,7 @@ static void ata_port_init_shost(struct ata_port *ap, struct Scsi_Host *shost)
{
ap->scsi_host = shost;
- shost->unique_id = ap->id;
+ shost->unique_id = ap->print_id;
shost->max_id = 16;
shost->max_lun = 1;
shost->max_channel = 1;
@@ -5587,17 +5685,23 @@ static void ata_host_release(struct device *gendev, void *res)
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
- if (!ap)
- continue;
-
- if (ap->ops->port_stop)
+ if (ap && ap->ops->port_stop)
ap->ops->port_stop(ap);
-
- scsi_host_put(ap->scsi_host);
}
if (host->ops->host_stop)
host->ops->host_stop(host);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ if (ap)
+ scsi_host_put(ap->scsi_host);
+
+ host->ports[i] = NULL;
+ }
+
+ dev_set_drvdata(gendev, NULL);
}
/**
@@ -5792,9 +5896,9 @@ int ata_device_add(const struct ata_probe_ent *ent)
/* wait for EH to finish */
ata_port_wait_eh(ap);
} else {
- DPRINTK("ata%u: bus probe begin\n", ap->id);
+ DPRINTK("ata%u: bus probe begin\n", ap->print_id);
rc = ata_bus_probe(ap);
- DPRINTK("ata%u: bus probe end\n", ap->id);
+ DPRINTK("ata%u: bus probe end\n", ap->print_id);
if (rc) {
/* FIXME: do something useful here?
@@ -5820,7 +5924,6 @@ int ata_device_add(const struct ata_probe_ent *ent)
err_out:
devres_release_group(dev, ata_device_add);
- dev_set_drvdata(dev, NULL);
VPRINTK("EXIT, returning %d\n", rc);
return 0;
}
@@ -5905,11 +6008,7 @@ ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
{
struct ata_probe_ent *probe_ent;
- /* XXX - the following if can go away once all LLDs are managed */
- if (!list_empty(&dev->devres_head))
- probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
- else
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+ probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
if (!probe_ent) {
printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
kobject_name(&(dev->kobj)));
@@ -6012,14 +6111,14 @@ int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits)
return (tmp == bits->val) ? 1 : 0;
}
+#ifdef CONFIG_PM
void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
pci_save_state(pdev);
+ pci_disable_device(pdev);
- if (mesg.event == PM_EVENT_SUSPEND) {
- pci_disable_device(pdev);
+ if (mesg.event == PM_EVENT_SUSPEND)
pci_set_power_state(pdev, PCI_D3hot);
- }
}
int ata_pci_device_do_resume(struct pci_dev *pdev)
@@ -6064,6 +6163,8 @@ int ata_pci_device_resume(struct pci_dev *pdev)
ata_host_resume(host);
return rc;
}
+#endif /* CONFIG_PM */
+
#endif /* CONFIG_PCI */
@@ -6241,6 +6342,7 @@ EXPORT_SYMBOL_GPL(ata_bmdma_drive_eh);
EXPORT_SYMBOL_GPL(ata_bmdma_error_handler);
EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd);
EXPORT_SYMBOL_GPL(ata_port_probe);
+EXPORT_SYMBOL_GPL(ata_dev_disable);
EXPORT_SYMBOL_GPL(sata_set_spd);
EXPORT_SYMBOL_GPL(sata_phy_debounce);
EXPORT_SYMBOL_GPL(sata_phy_resume);
@@ -6271,10 +6373,13 @@ EXPORT_SYMBOL_GPL(sata_scr_write);
EXPORT_SYMBOL_GPL(sata_scr_write_flush);
EXPORT_SYMBOL_GPL(ata_port_online);
EXPORT_SYMBOL_GPL(ata_port_offline);
+#ifdef CONFIG_PM
EXPORT_SYMBOL_GPL(ata_host_suspend);
EXPORT_SYMBOL_GPL(ata_host_resume);
+#endif /* CONFIG_PM */
EXPORT_SYMBOL_GPL(ata_id_string);
EXPORT_SYMBOL_GPL(ata_id_c_string);
+EXPORT_SYMBOL_GPL(ata_id_to_dma_mode);
EXPORT_SYMBOL_GPL(ata_device_blacklisted);
EXPORT_SYMBOL_GPL(ata_scsi_simulate);
@@ -6287,16 +6392,20 @@ EXPORT_SYMBOL_GPL(pci_test_config_bits);
EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
EXPORT_SYMBOL_GPL(ata_pci_init_one);
EXPORT_SYMBOL_GPL(ata_pci_remove_one);
+#ifdef CONFIG_PM
EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend);
EXPORT_SYMBOL_GPL(ata_pci_device_do_resume);
EXPORT_SYMBOL_GPL(ata_pci_device_suspend);
EXPORT_SYMBOL_GPL(ata_pci_device_resume);
+#endif /* CONFIG_PM */
EXPORT_SYMBOL_GPL(ata_pci_default_filter);
EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
#endif /* CONFIG_PCI */
+#ifdef CONFIG_PM
EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
+#endif /* CONFIG_PM */
EXPORT_SYMBOL_GPL(ata_eng_timeout);
EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
@@ -6311,3 +6420,4 @@ EXPORT_SYMBOL_GPL(ata_irq_on);
EXPORT_SYMBOL_GPL(ata_dummy_irq_on);
EXPORT_SYMBOL_GPL(ata_irq_ack);
EXPORT_SYMBOL_GPL(ata_dummy_irq_ack);
+EXPORT_SYMBOL_GPL(ata_dev_try_classify);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 52c85af7fe9..7349c3dbf77 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -44,10 +44,41 @@
#include "libata.h"
+enum {
+ ATA_EH_SPDN_NCQ_OFF = (1 << 0),
+ ATA_EH_SPDN_SPEED_DOWN = (1 << 1),
+ ATA_EH_SPDN_FALLBACK_TO_PIO = (1 << 2),
+};
+
static void __ata_port_freeze(struct ata_port *ap);
static void ata_eh_finish(struct ata_port *ap);
+#ifdef CONFIG_PM
static void ata_eh_handle_port_suspend(struct ata_port *ap);
static void ata_eh_handle_port_resume(struct ata_port *ap);
+static int ata_eh_suspend(struct ata_port *ap,
+ struct ata_device **r_failed_dev);
+static void ata_eh_prep_resume(struct ata_port *ap);
+static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev);
+#else /* CONFIG_PM */
+static void ata_eh_handle_port_suspend(struct ata_port *ap)
+{ }
+
+static void ata_eh_handle_port_resume(struct ata_port *ap)
+{ }
+
+static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+ return 0;
+}
+
+static void ata_eh_prep_resume(struct ata_port *ap)
+{ }
+
+static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+ return 0;
+}
+#endif /* CONFIG_PM */
static void ata_ering_record(struct ata_ering *ering, int is_io,
unsigned int err_mask)
@@ -65,12 +96,9 @@ static void ata_ering_record(struct ata_ering *ering, int is_io,
ent->timestamp = get_jiffies_64();
}
-static struct ata_ering_entry * ata_ering_top(struct ata_ering *ering)
+static void ata_ering_clear(struct ata_ering *ering)
{
- struct ata_ering_entry *ent = &ering->ring[ering->cursor];
- if (!ent->err_mask)
- return NULL;
- return ent;
+ memset(ering, 0, sizeof(*ering));
}
static int ata_ering_map(struct ata_ering *ering,
@@ -585,7 +613,7 @@ static void __ata_port_freeze(struct ata_port *ap)
ap->pflags |= ATA_PFLAG_FROZEN;
- DPRINTK("ata%u port frozen\n", ap->id);
+ DPRINTK("ata%u port frozen\n", ap->print_id);
}
/**
@@ -658,7 +686,7 @@ void ata_eh_thaw_port(struct ata_port *ap)
spin_unlock_irqrestore(ap->lock, flags);
- DPRINTK("ata%u port thawed\n", ap->id);
+ DPRINTK("ata%u port thawed\n", ap->print_id);
}
static void ata_eh_scsidone(struct scsi_cmnd *scmd)
@@ -1159,87 +1187,99 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
return action;
}
-static int ata_eh_categorize_ering_entry(struct ata_ering_entry *ent)
+static int ata_eh_categorize_error(int is_io, unsigned int err_mask)
{
- if (ent->err_mask & (AC_ERR_ATA_BUS | AC_ERR_TIMEOUT))
+ if (err_mask & AC_ERR_ATA_BUS)
return 1;
- if (ent->is_io) {
- if (ent->err_mask & AC_ERR_HSM)
- return 1;
- if ((ent->err_mask &
- (AC_ERR_DEV|AC_ERR_MEDIA|AC_ERR_INVALID)) == AC_ERR_DEV)
+ if (err_mask & AC_ERR_TIMEOUT)
+ return 2;
+
+ if (is_io) {
+ if (err_mask & AC_ERR_HSM)
return 2;
+ if ((err_mask &
+ (AC_ERR_DEV|AC_ERR_MEDIA|AC_ERR_INVALID)) == AC_ERR_DEV)
+ return 3;
}
return 0;
}
-struct speed_down_needed_arg {
+struct speed_down_verdict_arg {
u64 since;
- int nr_errors[3];
+ int nr_errors[4];
};
-static int speed_down_needed_cb(struct ata_ering_entry *ent, void *void_arg)
+static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg)
{
- struct speed_down_needed_arg *arg = void_arg;
+ struct speed_down_verdict_arg *arg = void_arg;
+ int cat = ata_eh_categorize_error(ent->is_io, ent->err_mask);
if (ent->timestamp < arg->since)
return -1;
- arg->nr_errors[ata_eh_categorize_ering_entry(ent)]++;
+ arg->nr_errors[cat]++;
return 0;
}
/**
- * ata_eh_speed_down_needed - Determine wheter speed down is necessary
+ * ata_eh_speed_down_verdict - Determine speed down verdict
* @dev: Device of interest
*
* This function examines error ring of @dev and determines
- * whether speed down is necessary. Speed down is necessary if
- * there have been more than 3 of Cat-1 errors or 10 of Cat-2
- * errors during last 15 minutes.
+ * whether NCQ needs to be turned off, transfer speed should be
+ * stepped down, or falling back to PIO is necessary.
*
- * Cat-1 errors are ATA_BUS, TIMEOUT for any command and HSM
- * violation for known supported commands.
+ * Cat-1 is ATA_BUS error for any command.
*
- * Cat-2 errors are unclassified DEV error for known supported
+ * Cat-2 is TIMEOUT for any command or HSM violation for known
+ * supported commands.
+ *
+ * Cat-3 is is unclassified DEV error for known supported
* command.
*
+ * NCQ needs to be turned off if there have been more than 3
+ * Cat-2 + Cat-3 errors during last 10 minutes.
+ *
+ * Speed down is necessary if there have been more than 3 Cat-1 +
+ * Cat-2 errors or 10 Cat-3 errors during last 10 minutes.
+ *
+ * Falling back to PIO mode is necessary if there have been more
+ * than 10 Cat-1 + Cat-2 + Cat-3 errors during last 5 minutes.
+ *
* LOCKING:
* Inherited from caller.
*
* RETURNS:
- * 1 if speed down is necessary, 0 otherwise
+ * OR of ATA_EH_SPDN_* flags.
*/
-static int ata_eh_speed_down_needed(struct ata_device *dev)
+static unsigned int ata_eh_speed_down_verdict(struct ata_device *dev)
{
- const u64 interval = 15LLU * 60 * HZ;
- static const int err_limits[3] = { -1, 3, 10 };
- struct speed_down_needed_arg arg;
- struct ata_ering_entry *ent;
- int err_cat;
- u64 j64;
+ const u64 j5mins = 5LLU * 60 * HZ, j10mins = 10LLU * 60 * HZ;
+ u64 j64 = get_jiffies_64();
+ struct speed_down_verdict_arg arg;
+ unsigned int verdict = 0;
- ent = ata_ering_top(&dev->ering);
- if (!ent)
- return 0;
+ /* scan past 10 mins of error history */
+ memset(&arg, 0, sizeof(arg));
+ arg.since = j64 - min(j64, j10mins);
+ ata_ering_map(&dev->ering, speed_down_verdict_cb, &arg);
- err_cat = ata_eh_categorize_ering_entry(ent);
- if (err_cat == 0)
- return 0;
+ if (arg.nr_errors[2] + arg.nr_errors[3] > 3)
+ verdict |= ATA_EH_SPDN_NCQ_OFF;
+ if (arg.nr_errors[1] + arg.nr_errors[2] > 3 || arg.nr_errors[3] > 10)
+ verdict |= ATA_EH_SPDN_SPEED_DOWN;
+ /* scan past 3 mins of error history */
memset(&arg, 0, sizeof(arg));
+ arg.since = j64 - min(j64, j5mins);
+ ata_ering_map(&dev->ering, speed_down_verdict_cb, &arg);
- j64 = get_jiffies_64();
- if (j64 >= interval)
- arg.since = j64 - interval;
- else
- arg.since = 0;
-
- ata_ering_map(&dev->ering, speed_down_needed_cb, &arg);
+ if (arg.nr_errors[1] + arg.nr_errors[2] + arg.nr_errors[3] > 10)
+ verdict |= ATA_EH_SPDN_FALLBACK_TO_PIO;
- return arg.nr_errors[err_cat] > err_limits[err_cat];
+ return verdict;
}
/**
@@ -1257,31 +1297,80 @@ static int ata_eh_speed_down_needed(struct ata_device *dev)
* Kernel thread context (may sleep).
*
* RETURNS:
- * 0 on success, -errno otherwise
+ * Determined recovery action.
*/
-static int ata_eh_speed_down(struct ata_device *dev, int is_io,
- unsigned int err_mask)
+static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
+ unsigned int err_mask)
{
- if (!err_mask)
+ unsigned int verdict;
+ unsigned int action = 0;
+
+ /* don't bother if Cat-0 error */
+ if (ata_eh_categorize_error(is_io, err_mask) == 0)
return 0;
/* record error and determine whether speed down is necessary */
ata_ering_record(&dev->ering, is_io, err_mask);
+ verdict = ata_eh_speed_down_verdict(dev);
- if (!ata_eh_speed_down_needed(dev))
- return 0;
+ /* turn off NCQ? */
+ if ((verdict & ATA_EH_SPDN_NCQ_OFF) &&
+ (dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ |
+ ATA_DFLAG_NCQ_OFF)) == ATA_DFLAG_NCQ) {
+ dev->flags |= ATA_DFLAG_NCQ_OFF;
+ ata_dev_printk(dev, KERN_WARNING,
+ "NCQ disabled due to excessive errors\n");
+ goto done;
+ }
- /* speed down SATA link speed if possible */
- if (sata_down_spd_limit(dev->ap) == 0)
- return ATA_EH_HARDRESET;
+ /* speed down? */
+ if (verdict & ATA_EH_SPDN_SPEED_DOWN) {
+ /* speed down SATA link speed if possible */
+ if (sata_down_spd_limit(dev->ap) == 0) {
+ action |= ATA_EH_HARDRESET;
+ goto done;
+ }
- /* lower transfer mode */
- if (ata_down_xfermask_limit(dev, 0) == 0)
- return ATA_EH_SOFTRESET;
+ /* lower transfer mode */
+ if (dev->spdn_cnt < 2) {
+ static const int dma_dnxfer_sel[] =
+ { ATA_DNXFER_DMA, ATA_DNXFER_40C };
+ static const int pio_dnxfer_sel[] =
+ { ATA_DNXFER_PIO, ATA_DNXFER_FORCE_PIO0 };
+ int sel;
+
+ if (dev->xfer_shift != ATA_SHIFT_PIO)
+ sel = dma_dnxfer_sel[dev->spdn_cnt];
+ else
+ sel = pio_dnxfer_sel[dev->spdn_cnt];
+
+ dev->spdn_cnt++;
+
+ if (ata_down_xfermask_limit(dev, sel) == 0) {
+ action |= ATA_EH_SOFTRESET;
+ goto done;
+ }
+ }
+ }
+
+ /* Fall back to PIO? Slowing down to PIO is meaningless for
+ * SATA. Consider it only for PATA.
+ */
+ if ((verdict & ATA_EH_SPDN_FALLBACK_TO_PIO) && (dev->spdn_cnt >= 2) &&
+ (dev->ap->cbl != ATA_CBL_SATA) &&
+ (dev->xfer_shift != ATA_SHIFT_PIO)) {
+ if (ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO) == 0) {
+ dev->spdn_cnt = 0;
+ action |= ATA_EH_SOFTRESET;
+ goto done;
+ }
+ }
- ata_dev_printk(dev, KERN_ERR,
- "speed down requested but no transfer mode left\n");
return 0;
+ done:
+ /* device has been slowed down, blow error history */
+ ata_ering_clear(&dev->ering);
+ return action;
}
/**
@@ -1726,6 +1815,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
return rc;
}
+#ifdef CONFIG_PM
/**
* ata_eh_suspend - handle suspend EH action
* @ap: target host port
@@ -1883,6 +1973,7 @@ static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev)
DPRINTK("EXIT\n");
return 0;
}
+#endif /* CONFIG_PM */
static int ata_port_nr_enabled(struct ata_port *ap)
{
@@ -1964,7 +2055,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
{
struct ata_eh_context *ehc = &ap->eh_context;
struct ata_device *dev;
- int down_xfermask, i, rc;
+ int i, rc;
DPRINTK("ENTER\n");
@@ -1993,7 +2084,6 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
}
retry:
- down_xfermask = 0;
rc = 0;
/* if UNLOADING, finish immediately */
@@ -2038,10 +2128,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
/* configure transfer mode if necessary */
if (ehc->i.flags & ATA_EHI_SETMODE) {
rc = ata_set_mode(ap, &dev);
- if (rc) {
- down_xfermask = 1;
+ if (rc)
goto dev_fail;
- }
ehc->i.flags &= ~ATA_EHI_SETMODE;
}
@@ -2053,20 +2141,27 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
goto out;
dev_fail:
+ ehc->tries[dev->devno]--;
+
switch (rc) {
- case -ENODEV:
- /* device missing, schedule probing */
- ehc->i.probe_mask |= (1 << dev->devno);
case -EINVAL:
+ /* eeek, something went very wrong, give up */
ehc->tries[dev->devno] = 0;
break;
+
+ case -ENODEV:
+ /* device missing or wrong IDENTIFY data, schedule probing */
+ ehc->i.probe_mask |= (1 << dev->devno);
+ /* give it just one more chance */
+ ehc->tries[dev->devno] = min(ehc->tries[dev->devno], 1);
case -EIO:
- sata_down_spd_limit(ap);
- default:
- ehc->tries[dev->devno]--;
- if (down_xfermask &&
- ata_down_xfermask_limit(dev, ehc->tries[dev->devno] == 1))
- ehc->tries[dev->devno] = 0;
+ if (ehc->tries[dev->devno] == 1) {
+ /* This is the last chance, better to slow
+ * down than lose it.
+ */
+ sata_down_spd_limit(ap);
+ ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
+ }
}
if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
@@ -2181,6 +2276,7 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_eh_finish(ap);
}
+#ifdef CONFIG_PM
/**
* ata_eh_handle_port_suspend - perform port suspend operation
* @ap: port to suspend
@@ -2296,3 +2392,4 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
}
spin_unlock_irqrestore(ap->lock, flags);
}
+#endif /* CONFIG_PM */
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 0009818a430..6cc817a1020 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -333,6 +333,7 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
scsi_cmd[8] = args[3];
scsi_cmd[10] = args[4];
scsi_cmd[12] = args[5];
+ scsi_cmd[13] = args[6] & 0x0f;
scsi_cmd[14] = args[0];
/* Good values for timeout and retries? Values below
@@ -509,6 +510,7 @@ static void ata_dump_status(unsigned id, struct ata_taskfile *tf)
}
}
+#ifdef CONFIG_PM
/**
* ata_scsi_device_suspend - suspend ATA device associated with sdev
* @sdev: the SCSI device to suspend
@@ -633,6 +635,7 @@ int ata_scsi_device_resume(struct scsi_device *sdev)
sdev->sdev_gendev.power.power_state = PMSG_ON;
return 0;
}
+#endif /* CONFIG_PM */
/**
* ata_to_sense_error - convert ATA error to SCSI error
@@ -781,7 +784,7 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc)
*/
if (qc->err_mask ||
tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
- ata_to_sense_error(qc->ap->id, tf->command, tf->feature,
+ ata_to_sense_error(qc->ap->print_id, tf->command, tf->feature,
&sb[1], &sb[2], &sb[3], verbose);
sb[1] &= 0x0f;
}
@@ -854,7 +857,7 @@ static void ata_gen_ata_sense(struct ata_queued_cmd *qc)
*/
if (qc->err_mask ||
tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
- ata_to_sense_error(qc->ap->id, tf->command, tf->feature,
+ ata_to_sense_error(qc->ap->print_id, tf->command, tf->feature,
&sb[1], &sb[2], &sb[3], verbose);
sb[1] &= 0x0f;
}
@@ -986,29 +989,32 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev;
unsigned long flags;
- int max_depth;
- if (queue_depth < 1)
+ if (queue_depth < 1 || queue_depth == sdev->queue_depth)
return sdev->queue_depth;
dev = ata_scsi_find_dev(ap, sdev);
if (!dev || !ata_dev_enabled(dev))
return sdev->queue_depth;
- max_depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));
- max_depth = min(ATA_MAX_QUEUE - 1, max_depth);
- if (queue_depth > max_depth)
- queue_depth = max_depth;
-
- scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);
-
+ /* NCQ enabled? */
spin_lock_irqsave(ap->lock, flags);
- if (queue_depth > 1)
- dev->flags &= ~ATA_DFLAG_NCQ_OFF;
- else
+ dev->flags &= ~ATA_DFLAG_NCQ_OFF;
+ if (queue_depth == 1 || !ata_ncq_enabled(dev)) {
dev->flags |= ATA_DFLAG_NCQ_OFF;
+ queue_depth = 1;
+ }
spin_unlock_irqrestore(ap->lock, flags);
+ /* limit and apply queue depth */
+ queue_depth = min(queue_depth, sdev->host->can_queue);
+ queue_depth = min(queue_depth, ata_id_queue_depth(dev->id));
+ queue_depth = min(queue_depth, ATA_MAX_QUEUE - 1);
+
+ if (sdev->queue_depth == queue_depth)
+ return -EINVAL;
+
+ scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);
return queue_depth;
}
@@ -1469,7 +1475,7 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
}
if (need_sense && !ap->ops->error_handler)
- ata_dump_status(ap->id, &qc->result_tf);
+ ata_dump_status(ap->print_id, &qc->result_tf);
qc->scsidone(cmd);
@@ -1495,11 +1501,9 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
{
struct ata_port *ap = dev->ap;
+ int is_ncq = is_io && ata_ncq_enabled(dev);
- if (!(dev->flags & ATA_DFLAG_NCQ))
- return 0;
-
- if (is_io) {
+ if (is_ncq) {
if (!ata_tag_valid(ap->active_tag))
return 0;
} else {
@@ -2774,7 +2778,7 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap,
u8 *scsicmd = cmd->cmnd;
DPRINTK("CDB (%u:%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- ap->id,
+ ap->print_id,
scsidev->channel, scsidev->id, scsidev->lun,
scsicmd[0], scsicmd[1], scsicmd[2], scsicmd[3],
scsicmd[4], scsicmd[5], scsicmd[6], scsicmd[7],
@@ -3234,7 +3238,7 @@ struct ata_port *ata_sas_port_alloc(struct ata_host *host,
ata_port_init(ap, host, ent, 0);
ap->lock = shost->host_lock;
- kfree(ent);
+ devm_kfree(host->dev, ent);
return ap;
}
EXPORT_SYMBOL_GPL(ata_sas_port_alloc);
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 16bc3e35bdd..2ffcca063d8 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -175,7 +175,7 @@ void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
*/
void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
{
- DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
+ DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
iowrite8(tf->command, ap->ioaddr.command_addr);
ata_pause(ap);
@@ -521,7 +521,7 @@ void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
static int ata_resources_present(struct pci_dev *pdev, int port)
{
int i;
-
+
/* Check the PCI resources for this channel are enabled */
port = port * 2;
for (i = 0; i < 2; i ++) {
@@ -531,7 +531,7 @@ static int ata_resources_present(struct pci_dev *pdev, int port)
}
return 1;
}
-
+
/**
* ata_pci_init_native_mode - Initialize native-mode driver
* @pdev: pci device to be initialized
@@ -576,7 +576,7 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
-
+
/* Discard disabled ports. Some controllers show their
unused channels this way */
if (ata_resources_present(pdev, 0) == 0)
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 0ad7781d72a..c42671493e8 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -41,6 +41,15 @@ struct ata_scsi_args {
enum {
/* flags for ata_dev_read_id() */
ATA_READID_POSTRESET = (1 << 0), /* reading ID after reset */
+
+ /* selector for ata_down_xfermask_limit() */
+ ATA_DNXFER_PIO = 0, /* speed down PIO */
+ ATA_DNXFER_DMA = 1, /* speed down DMA */
+ ATA_DNXFER_40C = 2, /* apply 40c cable limit */
+ ATA_DNXFER_FORCE_PIO = 3, /* force PIO */
+ ATA_DNXFER_FORCE_PIO0 = 4, /* force PIO0 */
+
+ ATA_DNXFER_QUIET = (1 << 31),
};
extern struct workqueue_struct *ata_aux_wq;
@@ -69,7 +78,7 @@ extern int ata_dev_revalidate(struct ata_device *dev, unsigned int flags);
extern int ata_dev_configure(struct ata_device *dev);
extern int sata_down_spd_limit(struct ata_port *ap);
extern int sata_set_spd_needed(struct ata_port *ap);
-extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0);
+extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
extern void ata_sg_clean(struct ata_queued_cmd *qc);
extern void ata_qc_free(struct ata_queued_cmd *qc);
@@ -150,7 +159,5 @@ extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
/* libata-sff.c */
extern u8 ata_irq_on(struct ata_port *ap);
-/* pata_sis.c */
-extern struct ata_port_info sis_info133;
#endif /* __LIBATA_H__ */
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index ab44d18850f..11ea552a58c 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -34,7 +34,7 @@
#include <linux/dmi.h>
#define DRV_NAME "pata_ali"
-#define DRV_VERSION "0.7.2"
+#define DRV_VERSION "0.7.3"
/*
* Cable special cases
@@ -345,8 +345,10 @@ static struct scsi_host_template ali_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
/*
@@ -667,11 +669,13 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return ata_pci_init_one(pdev, port_info, 2);
}
+#ifdef CONFIG_PM
static int ali_reinit_one(struct pci_dev *pdev)
{
ali_init_chipset(pdev);
return ata_pci_device_resume(pdev);
}
+#endif
static const struct pci_device_id ali[] = {
{ PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), },
@@ -685,8 +689,10 @@ static struct pci_driver ali_pci_driver = {
.id_table = ali,
.probe = ali_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ali_reinit_one,
+#endif
};
static int __init ali_init(void)
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 619e44b0403..18381762908 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -25,7 +25,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_amd"
-#define DRV_VERSION "0.2.7"
+#define DRV_VERSION "0.2.8"
/**
* timing_setup - shared timing computation and load
@@ -128,7 +128,7 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse
static int amd_pre_reset(struct ata_port *ap)
{
- static const u32 bitmask[2] = {0x03, 0xC0};
+ static const u32 bitmask[2] = {0x03, 0x0C};
static const struct pci_bits amd_enable_bits[] = {
{ 0x40, 1, 0x02, 0x02 },
{ 0x40, 1, 0x01, 0x01 }
@@ -247,7 +247,7 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev)
*/
static int nv_pre_reset(struct ata_port *ap) {
- static const u8 bitmask[2] = {0x03, 0xC0};
+ static const u8 bitmask[2] = {0x03, 0x0C};
static const struct pci_bits nv_enable_bits[] = {
{ 0x50, 1, 0x02, 0x02 },
{ 0x50, 1, 0x01, 0x01 }
@@ -334,8 +334,10 @@ static struct scsi_host_template amd_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations amd33_port_ops = {
@@ -663,6 +665,7 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return ata_pci_init_one(pdev, port_info, 2);
}
+#ifdef CONFIG_PM
static int amd_reinit_one(struct pci_dev *pdev)
{
if (pdev->vendor == PCI_VENDOR_ID_AMD) {
@@ -679,6 +682,7 @@ static int amd_reinit_one(struct pci_dev *pdev)
}
return ata_pci_device_resume(pdev);
}
+#endif
static const struct pci_device_id amd[] = {
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_COBRA_7401), 0 },
@@ -708,8 +712,10 @@ static struct pci_driver amd_pci_driver = {
.id_table = amd,
.probe = amd_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = amd_reinit_one,
+#endif
};
static int __init amd_init(void)
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index c3eb40c91c8..51d9923be02 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -224,8 +224,10 @@ static struct scsi_host_template atiixp_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations atiixp_port_ops = {
@@ -290,8 +292,10 @@ static struct pci_driver atiixp_pci_driver = {
.id_table = atiixp,
.probe = atiixp_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.resume = ata_pci_device_resume,
.suspend = ata_pci_device_suspend,
+#endif
};
static int __init atiixp_init(void)
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index da098282b5f..5b13bdd1edc 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -1,5 +1,5 @@
/*
- * pata_cmd64x.c - ATI PATA for new ATA layer
+ * pata_cmd64x.c - CMD64x PATA for new ATA layer
* (C) 2005 Red Hat Inc
* Alan Cox <alan@redhat.com>
*
@@ -285,8 +285,10 @@ static struct scsi_host_template cmd64x_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations cmd64x_port_ops = {
@@ -479,6 +481,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return ata_pci_init_one(pdev, port_info, 2);
}
+#ifdef CONFIG_PM
static int cmd64x_reinit_one(struct pci_dev *pdev)
{
u8 mrdmode;
@@ -492,6 +495,7 @@ static int cmd64x_reinit_one(struct pci_dev *pdev)
#endif
return ata_pci_device_resume(pdev);
}
+#endif
static const struct pci_device_id cmd64x[] = {
{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 },
@@ -507,8 +511,10 @@ static struct pci_driver cmd64x_pci_driver = {
.id_table = cmd64x,
.probe = cmd64x_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = cmd64x_reinit_one,
+#endif
};
static int __init cmd64x_init(void)
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index 1ce8fcfd782..7ef834250a4 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -41,7 +41,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_cs5520"
-#define DRV_VERSION "0.6.3"
+#define DRV_VERSION "0.6.4"
struct pio_clocks
{
@@ -167,8 +167,10 @@ static struct scsi_host_template cs5520_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations cs5520_port_ops = {
@@ -306,9 +308,9 @@ static void __devexit cs5520_remove_one(struct pci_dev *pdev)
struct ata_host *host = dev_get_drvdata(dev);
ata_host_detach(host);
- dev_set_drvdata(dev, NULL);
}
+#ifdef CONFIG_PM
/**
* cs5520_reinit_one - device resume
* @pdev: PCI device
@@ -325,6 +327,31 @@ static int cs5520_reinit_one(struct pci_dev *pdev)
pci_write_config_byte(pdev, 0x60, pcicfg | 0x40);
return ata_pci_device_resume(pdev);
}
+
+/**
+ * cs5520_pci_device_suspend - device suspend
+ * @pdev: PCI device
+ *
+ * We have to cut and waste bits from the standard method because
+ * the 5520 is a bit odd and not just a pure ATA device. As a result
+ * we must not disable it. The needed code is short and this avoids
+ * chip specific mess in the core code.
+ */
+
+static int cs5520_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ int rc = 0;
+
+ rc = ata_host_suspend(host, mesg);
+ if (rc)
+ return rc;
+
+ pci_save_state(pdev);
+ return 0;
+}
+#endif /* CONFIG_PM */
+
/* For now keep DMA off. We can set it for all but A rev CS5510 once the
core ATA code can handle it */
@@ -340,8 +367,10 @@ static struct pci_driver cs5520_pci_driver = {
.id_table = pata_cs5520,
.probe = cs5520_init_one,
.remove = cs5520_remove_one,
- .suspend = ata_pci_device_suspend,
+#ifdef CONFIG_PM
+ .suspend = cs5520_pci_device_suspend,
.resume = cs5520_reinit_one,
+#endif
};
static int __init cs5520_init(void)
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index 3d7b7d87ec6..db63e80e608 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -35,7 +35,7 @@
#include <linux/dmi.h>
#define DRV_NAME "pata_cs5530"
-#define DRV_VERSION "0.7.1"
+#define DRV_VERSION "0.7.2"
static void __iomem *cs5530_port_base(struct ata_port *ap)
{
@@ -188,8 +188,10 @@ static struct scsi_host_template cs5530_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations cs5530_port_ops = {
@@ -376,6 +378,7 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return ata_pci_init_one(pdev, port_info, 2);
}
+#ifdef CONFIG_PM
static int cs5530_reinit_one(struct pci_dev *pdev)
{
/* If we fail on resume we are doomed */
@@ -383,6 +386,7 @@ static int cs5530_reinit_one(struct pci_dev *pdev)
BUG();
return ata_pci_device_resume(pdev);
}
+#endif /* CONFIG_PM */
static const struct pci_device_id cs5530[] = {
{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), },
@@ -395,8 +399,10 @@ static struct pci_driver cs5530_pci_driver = {
.id_table = cs5530,
.probe = cs5530_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = cs5530_reinit_one,
+#endif
};
static int __init cs5530_init(void)
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index 17bc693cc51..1572e5c9031 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -185,8 +185,10 @@ static struct scsi_host_template cs5535_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations cs5535_port_ops = {
@@ -270,8 +272,10 @@ static struct pci_driver cs5535_pci_driver = {
.id_table = cs5535,
.probe = cs5535_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static int __init cs5535_init(void)
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index 63f48f08763..f69dde5f706 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -136,8 +136,10 @@ static struct scsi_host_template cy82c693_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations cy82c693_port_ops = {
@@ -206,8 +208,10 @@ static struct pci_driver cy82c693_pci_driver = {
.id_table = cy82c693,
.probe = cy82c693_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static int __init cy82c693_init(void)
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index c19b6a8a7dc..dac7a6554f6 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -234,8 +234,10 @@ static struct scsi_host_template efar_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static const struct ata_port_operations efar_ops = {
@@ -317,8 +319,10 @@ static struct pci_driver efar_pci_driver = {
.id_table = efar_pci_tbl,
.probe = efar_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static int __init efar_init(void)
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index 27d724b5eea..baf35f87603 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -27,7 +27,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt366"
-#define DRV_VERSION "0.5.3"
+#define DRV_VERSION "0.6.0"
struct hpt_clock {
u8 xfer_speed;
@@ -328,8 +328,10 @@ static struct scsi_host_template hpt36x_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
/*
@@ -457,12 +459,13 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, port_info, 2);
}
+#ifdef CONFIG_PM
static int hpt36x_reinit_one(struct pci_dev *dev)
{
hpt36x_init_chipset(dev);
return ata_pci_device_resume(dev);
}
-
+#endif
static const struct pci_device_id hpt36x[] = {
{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
@@ -474,8 +477,10 @@ static struct pci_driver hpt36x_pci_driver = {
.id_table = hpt36x,
.probe = hpt36x_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = hpt36x_reinit_one,
+#endif
};
static int __init hpt36x_init(void)
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index 4ffc392052c..f331eeeafa0 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -25,7 +25,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt37x"
-#define DRV_VERSION "0.5.2"
+#define DRV_VERSION "0.6.0"
struct hpt_clock {
u8 xfer_speed;
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index 483ce7c12c9..813485c8526 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -119,8 +119,10 @@ static struct scsi_host_template hpt3x3_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations hpt3x3_port_ops = {
@@ -206,11 +208,13 @@ static int hpt3x3_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, port_info, 2);
}
+#ifdef CONFIG_PM
static int hpt3x3_reinit_one(struct pci_dev *dev)
{
hpt3x3_init_chipset(dev);
return ata_pci_device_resume(dev);
}
+#endif
static const struct pci_device_id hpt3x3[] = {
{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT343), },
@@ -223,8 +227,10 @@ static struct pci_driver hpt3x3_pci_driver = {
.id_table = hpt3x3,
.probe = hpt3x3_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = hpt3x3_reinit_one,
+#endif
};
static int __init hpt3x3_init(void)
diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c
index 1bf5ec18b2e..1a61cc89174 100644
--- a/drivers/ata/pata_isapnp.c
+++ b/drivers/ata/pata_isapnp.c
@@ -17,7 +17,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_isapnp"
-#define DRV_VERSION "0.1.5"
+#define DRV_VERSION "0.2.0"
static struct scsi_host_template isapnp_sht = {
.module = THIS_MODULE,
@@ -128,7 +128,6 @@ static void isapnp_remove_one(struct pnp_dev *idev)
struct ata_host *host = dev_get_drvdata(dev);
ata_host_detach(host);
- dev_set_drvdata(dev, NULL);
}
static struct pnp_device_id isapnp_devices[] = {
diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c
index 7eac869dfcd..ea734701555 100644
--- a/drivers/ata/pata_it8213.c
+++ b/drivers/ata/pata_it8213.c
@@ -246,8 +246,10 @@ static struct scsi_host_template it8213_sht = {
.dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static const struct ata_port_operations it8213_ops = {
@@ -330,8 +332,10 @@ static struct pci_driver it8213_pci_driver = {
.id_table = it8213_pci_tbl,
.probe = it8213_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static int __init it8213_init(void)
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 73394c75be4..35ecb2ba067 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -80,7 +80,7 @@
#define DRV_NAME "pata_it821x"
-#define DRV_VERSION "0.3.3"
+#define DRV_VERSION "0.3.4"
struct it821x_dev
{
@@ -503,10 +503,12 @@ static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused
/* We do need the right mode information for DMA or PIO
and this comes from the current configuration flags */
if (dma_enabled & (1 << (5 + i))) {
+ ata_dev_printk(dev, KERN_INFO, "configured for DMA\n");
dev->xfer_mode = XFER_MW_DMA_0;
dev->xfer_shift = ATA_SHIFT_MWDMA;
dev->flags &= ~ATA_DFLAG_PIO;
} else {
+ ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
dev->xfer_mode = XFER_PIO_0;
dev->xfer_shift = ATA_SHIFT_PIO;
dev->flags |= ATA_DFLAG_PIO;
@@ -644,8 +646,10 @@ static struct scsi_host_template it821x_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations it821x_smart_port_ops = {
@@ -778,6 +782,7 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return ata_pci_init_one(pdev, port_info, 2);
}
+#ifdef CONFIG_PM
static int it821x_reinit_one(struct pci_dev *pdev)
{
/* Resume - turn raid back off if need be */
@@ -785,6 +790,7 @@ static int it821x_reinit_one(struct pci_dev *pdev)
it821x_disable_raid(pdev);
return ata_pci_device_resume(pdev);
}
+#endif
static const struct pci_device_id it821x[] = {
{ PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), },
@@ -798,8 +804,10 @@ static struct pci_driver it821x_pci_driver = {
.id_table = it821x,
.probe = it821x_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = it821x_reinit_one,
+#endif
};
static int __init it821x_init(void)
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c
index 3222ac7b945..9a0523b5c94 100644
--- a/drivers/ata/pata_ixp4xx_cf.c
+++ b/drivers/ata/pata_ixp4xx_cf.c
@@ -23,15 +23,16 @@
#include <scsi/scsi_host.h>
#define DRV_NAME "pata_ixp4xx_cf"
-#define DRV_VERSION "0.1.1ac1"
+#define DRV_VERSION "0.1.2"
-static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device *adev)
+static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error)
{
int i;
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];
- if (ata_dev_enabled(dev)) {
+ if (ata_dev_ready(dev)) {
+ ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n");
dev->pio_mode = XFER_PIO_0;
dev->xfer_mode = XFER_PIO_0;
dev->xfer_shift = ATA_SHIFT_PIO;
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
index 7a635dd326f..43763c99ea0 100644
--- a/drivers/ata/pata_jmicron.c
+++ b/drivers/ata/pata_jmicron.c
@@ -137,6 +137,10 @@ static struct scsi_host_template jmicron_sht = {
.slave_destroy = ata_scsi_slave_destroy,
/* Use standard CHS mapping rules */
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
+#endif
};
static const struct ata_port_operations jmicron_ops = {
@@ -202,49 +206,20 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i
};
struct ata_port_info *port_info[2] = { &info, &info };
- u32 reg;
-
- /* PATA controller is fn 1, AHCI is fn 0 */
- if (id->driver_data != 368 && PCI_FUNC(pdev->devfn) != 1)
- return -ENODEV;
-
- /* The 365/66 have two PATA channels, redirect the second */
- if (id->driver_data == 365 || id->driver_data == 366) {
- pci_read_config_dword(pdev, 0x80, &reg);
- reg |= (1 << 24); /* IDE1 to PATA IDE secondary */
- pci_write_config_dword(pdev, 0x80, reg);
- }
-
return ata_pci_init_one(pdev, port_info, 2);
}
-static int jmicron_reinit_one(struct pci_dev *pdev)
-{
- u32 reg;
-
- switch(pdev->device) {
- case PCI_DEVICE_ID_JMICRON_JMB368:
- break;
- case PCI_DEVICE_ID_JMICRON_JMB365:
- case PCI_DEVICE_ID_JMICRON_JMB366:
- /* Restore mapping or disks swap and boy does it get ugly */
- pci_read_config_dword(pdev, 0x80, &reg);
- reg |= (1 << 24); /* IDE1 to PATA IDE secondary */
- pci_write_config_dword(pdev, 0x80, reg);
- /* Fall through */
- default:
- /* Make sure AHCI is turned back on */
- pci_write_config_byte(pdev, 0x41, 0xa1);
- }
- return ata_pci_device_resume(pdev);
-}
-
static const struct pci_device_id jmicron_pci_tbl[] = {
- { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 361},
- { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 363},
- { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365), 365},
- { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366), 366},
- { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368), 368},
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 361 },
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 363 },
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 365 },
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 366 },
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 368 },
{ } /* terminate list */
};
@@ -254,8 +229,10 @@ static struct pci_driver jmicron_pci_driver = {
.id_table = jmicron_pci_tbl,
.probe = jmicron_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
- .resume = jmicron_reinit_one,
+ .resume = ata_pci_device_resume,
+#endif
};
static int __init jmicron_init(void)
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index 98c1fee4b30..86fbcd6a742 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -64,12 +64,12 @@
#include <linux/platform_device.h>
#define DRV_NAME "pata_legacy"
-#define DRV_VERSION "0.5.3"
+#define DRV_VERSION "0.5.4"
#define NR_HOST 6
static int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 };
-static int legacy_irq[NR_HOST] = { 15, 14, 11, 10, 8, 12 };
+static int legacy_irq[NR_HOST] = { 14, 15, 11, 10, 8, 12 };
struct legacy_data {
unsigned long timing;
@@ -186,7 +186,10 @@ static struct ata_port_operations legacy_port_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -298,7 +301,10 @@ static struct ata_port_operations pdc20230_port_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -350,7 +356,10 @@ static struct ata_port_operations ht6560a_port_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -413,7 +422,10 @@ static struct ata_port_operations ht6560b_port_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -531,7 +543,10 @@ static struct ata_port_operations opti82c611a_port_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -661,7 +676,10 @@ static struct ata_port_operations opti82c46x_port_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
.qc_prep = ata_qc_prep,
.qc_issue = opti82c46x_qc_issue_prot,
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c
index 13a70ac6f1d..6dd7c4ef3e6 100644
--- a/drivers/ata/pata_marvell.c
+++ b/drivers/ata/pata_marvell.c
@@ -103,8 +103,10 @@ static struct scsi_host_template marvell_sht = {
.slave_destroy = ata_scsi_slave_destroy,
/* Use standard CHS mapping rules */
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static const struct ata_port_operations marvell_ops = {
@@ -199,8 +201,10 @@ static struct pci_driver marvell_pci_driver = {
.id_table = marvell_pci_tbl,
.probe = marvell_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static int __init marvell_init(void)
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 29e1809e5ec..f5d88729ca7 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -280,6 +280,10 @@ static struct scsi_host_template mpc52xx_ata_sht = {
.dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
+#endif
};
static struct ata_port_operations mpc52xx_ata_port_ops = {
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
index f2e7115f7ab..4abe45ac19a 100644
--- a/drivers/ata/pata_mpiix.c
+++ b/drivers/ata/pata_mpiix.c
@@ -165,8 +165,10 @@ static struct scsi_host_template mpiix_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations mpiix_port_ops = {
@@ -270,8 +272,10 @@ static struct pci_driver mpiix_pci_driver = {
.id_table = mpiix,
.probe = mpiix_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static int __init mpiix_init(void)
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
index e8393e19be4..38f99b38a5e 100644
--- a/drivers/ata/pata_netcell.c
+++ b/drivers/ata/pata_netcell.c
@@ -63,8 +63,10 @@ static struct scsi_host_template netcell_sht = {
.slave_destroy = ata_scsi_slave_destroy,
/* Use standard CHS mapping rules */
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static const struct ata_port_operations netcell_ops = {
@@ -153,8 +155,10 @@ static struct pci_driver netcell_pci_driver = {
.id_table = netcell_pci_tbl,
.probe = netcell_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static int __init netcell_init(void)
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index 3d1fa487c48..9944a28daa9 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -157,8 +157,10 @@ static struct scsi_host_template ns87410_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations ns87410_port_ops = {
@@ -212,8 +214,10 @@ static struct pci_driver ns87410_pci_driver = {
.id_table = ns87410,
.probe = ns87410_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static int __init ns87410_init(void)
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
index 45215aa05e7..da68cd19efd 100644
--- a/drivers/ata/pata_oldpiix.c
+++ b/drivers/ata/pata_oldpiix.c
@@ -25,7 +25,7 @@
#include <linux/ata.h>
#define DRV_NAME "pata_oldpiix"
-#define DRV_VERSION "0.5.3"
+#define DRV_VERSION "0.5.4"
/**
* oldpiix_pre_reset - probe begin
@@ -209,10 +209,9 @@ static unsigned int oldpiix_qc_issue_prot(struct ata_queued_cmd *qc)
struct ata_device *adev = qc->dev;
if (adev != ap->private_data) {
+ oldpiix_set_piomode(ap, adev);
if (adev->dma_mode)
oldpiix_set_dmamode(ap, adev);
- else if (adev->pio_mode)
- oldpiix_set_piomode(ap, adev);
}
return ata_qc_issue_prot(qc);
}
@@ -234,8 +233,10 @@ static struct scsi_host_template oldpiix_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static const struct ata_port_operations oldpiix_pata_ops = {
@@ -317,8 +318,10 @@ static struct pci_driver oldpiix_pci_driver = {
.id_table = oldpiix_pci_tbl,
.probe = oldpiix_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static int __init oldpiix_init(void)
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
index da1aa148b37..3fd3a35c224 100644
--- a/drivers/ata/pata_opti.c
+++ b/drivers/ata/pata_opti.c
@@ -34,7 +34,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_opti"
-#define DRV_VERSION "0.2.7"
+#define DRV_VERSION "0.2.8"
enum {
READ_REG = 0, /* index of Read cycle timing register */
@@ -179,8 +179,10 @@ static struct scsi_host_template opti_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations opti_port_ops = {
@@ -244,8 +246,10 @@ static struct pci_driver opti_pci_driver = {
.id_table = opti,
.probe = opti_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static int __init opti_init(void)
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
index d80b36e209c..9764907e8a1 100644
--- a/drivers/ata/pata_optidma.c
+++ b/drivers/ata/pata_optidma.c
@@ -33,7 +33,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_optidma"
-#define DRV_VERSION "0.2.3"
+#define DRV_VERSION "0.2.4"
enum {
READ_REG = 0, /* index of Read cycle timing register */
@@ -360,8 +360,10 @@ static struct scsi_host_template optidma_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations optidma_port_ops = {
@@ -524,8 +526,10 @@ static struct pci_driver optidma_pci_driver = {
.id_table = optidma,
.probe = optidma_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static int __init optidma_init(void)
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 36468ec6454..103720f873c 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -42,7 +42,7 @@
#define DRV_NAME "pata_pcmcia"
-#define DRV_VERSION "0.2.11"
+#define DRV_VERSION "0.3.0"
/*
* Private data structure to glue stuff together
@@ -308,7 +308,6 @@ static void pcmcia_remove_one(struct pcmcia_device *pdev)
if (info->ndev) {
struct ata_host *host = dev_get_drvdata(dev);
ata_host_detach(host);
- dev_set_drvdata(dev, NULL);
}
info->ndev = 0;
pdev->priv = NULL;
@@ -320,14 +319,17 @@ static void pcmcia_remove_one(struct pcmcia_device *pdev)
static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_FUNC_ID(4),
PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */
+ PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000), /* I-O Data CFA */
+ PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001), /* Mitsubishi CFA */
PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
- PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),
+ PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), /* SanDisk CFA */
PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */
PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */
PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */
PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001),
- PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar */
+ PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0100), /* Viking CFA */
+ PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar, Viking CFA */
PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0),
PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74),
PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9),
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index 61537873d28..93bcdadb7be 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -35,7 +35,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_pdc2027x"
-#define DRV_VERSION "0.74-ac5"
+#define DRV_VERSION "0.8"
#undef PDC_DEBUG
#ifdef PDC_DEBUG
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index 6dd63413a52..acdc52cbe38 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -2,13 +2,14 @@
* pata_pdc202xx_old.c - Promise PDC202xx PATA for new ATA layer
* (C) 2005 Red Hat Inc
* Alan Cox <alan@redhat.com>
+ * (C) 2007 Bartlomiej Zolnierkiewicz
*
* Based in part on linux/drivers/ide/pci/pdc202xx_old.c
*
* First cut with LBA48/ATAPI
*
* TODO:
- * Channel interlock/reset on both required ?
+ * Channel interlock/reset on both required
*/
#include <linux/kernel.h>
@@ -21,7 +22,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_pdc202xx_old"
-#define DRV_VERSION "0.2.3"
+#define DRV_VERSION "0.4.0"
/**
* pdc2024x_pre_reset - probe begin
@@ -76,7 +77,7 @@ static void pdc2026x_error_handler(struct ata_port *ap)
static void pdc202xx_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- int port = 0x60 + 4 * ap->port_no + 2 * adev->devno;
+ int port = 0x60 + 8 * ap->port_no + 4 * adev->devno;
static u16 pio_timing[5] = {
0x0913, 0x050C , 0x0308, 0x0206, 0x0104
};
@@ -85,7 +86,7 @@ static void pdc202xx_configure_piomode(struct ata_port *ap, struct ata_device *a
pci_read_config_byte(pdev, port, &r_ap);
pci_read_config_byte(pdev, port + 1, &r_bp);
r_ap &= ~0x3F; /* Preserve ERRDY_EN, SYNC_IN */
- r_bp &= ~0x07;
+ r_bp &= ~0x1F;
r_ap |= (pio_timing[pio] >> 8);
r_bp |= (pio_timing[pio] & 0xFF);
@@ -123,7 +124,7 @@ static void pdc202xx_set_piomode(struct ata_port *ap, struct ata_device *adev)
static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- int port = 0x60 + 4 * ap->port_no + 2 * adev->devno;
+ int port = 0x60 + 8 * ap->port_no + 4 * adev->devno;
static u8 udma_timing[6][2] = {
{ 0x60, 0x03 }, /* 33 Mhz Clock */
{ 0x40, 0x02 },
@@ -132,12 +133,17 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{ 0x20, 0x01 },
{ 0x20, 0x01 }
};
+ static u8 mdma_timing[3][2] = {
+ { 0x60, 0x03 },
+ { 0x60, 0x04 },
+ { 0xe0, 0x0f },
+ };
u8 r_bp, r_cp;
pci_read_config_byte(pdev, port + 1, &r_bp);
pci_read_config_byte(pdev, port + 2, &r_cp);
- r_bp &= ~0xF0;
+ r_bp &= ~0xE0;
r_cp &= ~0x0F;
if (adev->dma_mode >= XFER_UDMA_0) {
@@ -147,8 +153,8 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev)
} else {
int speed = adev->dma_mode - XFER_MW_DMA_0;
- r_bp |= 0x60;
- r_cp |= (5 - speed);
+ r_bp |= mdma_timing[speed][0];
+ r_cp |= mdma_timing[speed][1];
}
pci_write_config_byte(pdev, port + 1, r_bp);
pci_write_config_byte(pdev, port + 2, r_cp);
@@ -267,8 +273,10 @@ static struct scsi_host_template pdc202xx_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations pdc2024x_port_ops = {
@@ -399,8 +407,10 @@ static struct pci_driver pdc202xx_pci_driver = {
.id_table = pdc202xx,
.probe = pdc202xx_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static int __init pdc202xx_init(void)
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 479a326114e..4b82a5435a4 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -42,6 +42,7 @@ static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unuse
dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
dev->xfer_shift = ATA_SHIFT_PIO;
dev->flags |= ATA_DFLAG_PIO;
+ ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
}
}
return 0;
@@ -227,7 +228,6 @@ static int __devexit pata_platform_remove(struct platform_device *pdev)
struct ata_host *host = dev_get_drvdata(dev);
ata_host_detach(host);
- dev_set_drvdata(dev, NULL);
return 0;
}
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
index 4362141976a..c3810012f3f 100644
--- a/drivers/ata/pata_qdi.c
+++ b/drivers/ata/pata_qdi.c
@@ -26,7 +26,7 @@
#include <linux/platform_device.h>
#define DRV_NAME "pata_qdi"
-#define DRV_VERSION "0.2.4"
+#define DRV_VERSION "0.3.0"
#define NR_HOST 4 /* Two 6580s */
@@ -363,7 +363,8 @@ static __init int qdi_init(void)
release_region(port, 2);
continue;
}
- ct += qdi_init_one(port, 6500, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04);
+ if (qdi_init_one(port, 6500, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04) == 0)
+ ct++;
}
if (((r & 0xF0) == 0xA0) || (r & 0xF0) == 0x50) {
/* QD6580: dual channel */
@@ -375,11 +376,14 @@ static __init int qdi_init(void)
res = inb(port + 3);
if (res & 1) {
/* Single channel mode */
- ct += qdi_init_one(port, 6580, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04);
+ if (qdi_init_one(port, 6580, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04))
+ ct++;
} else {
/* Dual channel mode */
- ct += qdi_init_one(port, 6580, 0x1F0, 14, r & 0x04);
- ct += qdi_init_one(port + 2, 6580, 0x170, 15, r & 0x04);
+ if (qdi_init_one(port, 6580, 0x1F0, 14, r & 0x04) == 0)
+ ct++;
+ if (qdi_init_one(port + 2, 6580, 0x170, 15, r & 0x04) == 0)
+ ct++;
}
}
}
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
index 0d1e571ef63..9a9132c9e33 100644
--- a/drivers/ata/pata_radisys.c
+++ b/drivers/ata/pata_radisys.c
@@ -228,8 +228,10 @@ static struct scsi_host_template radisys_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static const struct ata_port_operations radisys_pata_ops = {
@@ -312,8 +314,10 @@ static struct pci_driver radisys_pci_driver = {
.id_table = radisys_pci_tbl,
.probe = radisys_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static int __init radisys_init(void)
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index 71a2bac09e0..f522daa2a6a 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -71,6 +71,7 @@ static int rz1000_set_mode(struct ata_port *ap, struct ata_device **unused)
dev->xfer_mode = XFER_PIO_0;
dev->xfer_shift = ATA_SHIFT_PIO;
dev->flags |= ATA_DFLAG_PIO;
+ ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
}
}
return 0;
@@ -93,8 +94,10 @@ static struct scsi_host_template rz1000_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations rz1000_port_ops = {
@@ -177,6 +180,7 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en
return -ENODEV;
}
+#ifdef CONFIG_PM
static int rz1000_reinit_one(struct pci_dev *pdev)
{
/* If this fails on resume (which is a "cant happen" case), we
@@ -185,6 +189,7 @@ static int rz1000_reinit_one(struct pci_dev *pdev)
panic("rz1000 fifo");
return ata_pci_device_resume(pdev);
}
+#endif
static const struct pci_device_id pata_rz1000[] = {
{ PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), },
@@ -198,8 +203,10 @@ static struct pci_driver rz1000_pci_driver = {
.id_table = pata_rz1000,
.probe = rz1000_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = rz1000_reinit_one,
+#endif
};
static int __init rz1000_init(void)
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index 58e42fbd14f..93b3ed0f9e8 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -194,8 +194,10 @@ static struct scsi_host_template sc1200_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations sc1200_port_ops = {
@@ -210,7 +212,10 @@ static struct ata_port_operations sc1200_port_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -266,8 +271,10 @@ static struct pci_driver sc1200_pci_driver = {
.id_table = sc1200,
.probe = sc1200_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static int __init sc1200_init(void)
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
new file mode 100644
index 00000000000..f3ed141fdc0
--- /dev/null
+++ b/drivers/ata/pata_scc.c
@@ -0,0 +1,1230 @@
+/*
+ * Support for IDE interfaces on Celleb platform
+ *
+ * (C) Copyright 2006 TOSHIBA CORPORATION
+ *
+ * This code is based on drivers/ata/ata_piix.c:
+ * Copyright 2003-2005 Red Hat Inc
+ * Copyright 2003-2005 Jeff Garzik
+ * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2003 Red Hat Inc <alan@redhat.com>
+ *
+ * and drivers/ata/ahci.c:
+ * Copyright 2004-2005 Red Hat, Inc.
+ *
+ * and drivers/ata/libata-core.c:
+ * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
+ * Copyright 2003-2004 Jeff Garzik
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_scc"
+#define DRV_VERSION "0.1"
+
+#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4
+
+/* PCI BARs */
+#define SCC_CTRL_BAR 0
+#define SCC_BMID_BAR 1
+
+/* offset of CTRL registers */
+#define SCC_CTL_PIOSHT 0x000
+#define SCC_CTL_PIOCT 0x004
+#define SCC_CTL_MDMACT 0x008
+#define SCC_CTL_MCRCST 0x00C
+#define SCC_CTL_SDMACT 0x010
+#define SCC_CTL_SCRCST 0x014
+#define SCC_CTL_UDENVT 0x018
+#define SCC_CTL_TDVHSEL 0x020
+#define SCC_CTL_MODEREG 0x024
+#define SCC_CTL_ECMODE 0xF00
+#define SCC_CTL_MAEA0 0xF50
+#define SCC_CTL_MAEC0 0xF54
+#define SCC_CTL_CCKCTRL 0xFF0
+
+/* offset of BMID registers */
+#define SCC_DMA_CMD 0x000
+#define SCC_DMA_STATUS 0x004
+#define SCC_DMA_TABLE_OFS 0x008
+#define SCC_DMA_INTMASK 0x010
+#define SCC_DMA_INTST 0x014
+#define SCC_DMA_PTERADD 0x018
+#define SCC_REG_CMD_ADDR 0x020
+#define SCC_REG_DATA 0x000
+#define SCC_REG_ERR 0x004
+#define SCC_REG_FEATURE 0x004
+#define SCC_REG_NSECT 0x008
+#define SCC_REG_LBAL 0x00C
+#define SCC_REG_LBAM 0x010
+#define SCC_REG_LBAH 0x014
+#define SCC_REG_DEVICE 0x018
+#define SCC_REG_STATUS 0x01C
+#define SCC_REG_CMD 0x01C
+#define SCC_REG_ALTSTATUS 0x020
+
+/* register value */
+#define TDVHSEL_MASTER 0x00000001
+#define TDVHSEL_SLAVE 0x00000004
+
+#define MODE_JCUSFEN 0x00000080
+
+#define ECMODE_VALUE 0x01
+
+#define CCKCTRL_ATARESET 0x00040000
+#define CCKCTRL_BUFCNT 0x00020000
+#define CCKCTRL_CRST 0x00010000
+#define CCKCTRL_OCLKEN 0x00000100
+#define CCKCTRL_ATACLKOEN 0x00000002
+#define CCKCTRL_LCLKEN 0x00000001
+
+#define QCHCD_IOS_SS 0x00000001
+
+#define QCHSD_STPDIAG 0x00020000
+
+#define INTMASK_MSK 0xD1000012
+#define INTSTS_SERROR 0x80000000
+#define INTSTS_PRERR 0x40000000
+#define INTSTS_RERR 0x10000000
+#define INTSTS_ICERR 0x01000000
+#define INTSTS_BMSINT 0x00000010
+#define INTSTS_BMHE 0x00000008
+#define INTSTS_IOIRQS 0x00000004
+#define INTSTS_INTRQ 0x00000002
+#define INTSTS_ACTEINT 0x00000001
+
+
+/* PIO transfer mode table */
+/* JCHST */
+static const unsigned long JCHSTtbl[2][7] = {
+ {0x0E, 0x05, 0x02, 0x03, 0x02, 0x00, 0x00}, /* 100MHz */
+ {0x13, 0x07, 0x04, 0x04, 0x03, 0x00, 0x00} /* 133MHz */
+};
+
+/* JCHHT */
+static const unsigned long JCHHTtbl[2][7] = {
+ {0x0E, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00}, /* 100MHz */
+ {0x13, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00} /* 133MHz */
+};
+
+/* JCHCT */
+static const unsigned long JCHCTtbl[2][7] = {
+ {0x1D, 0x1D, 0x1C, 0x0B, 0x06, 0x00, 0x00}, /* 100MHz */
+ {0x27, 0x26, 0x26, 0x0E, 0x09, 0x00, 0x00} /* 133MHz */
+};
+
+/* DMA transfer mode table */
+/* JCHDCTM/JCHDCTS */
+static const unsigned long JCHDCTxtbl[2][7] = {
+ {0x0A, 0x06, 0x04, 0x03, 0x01, 0x00, 0x00}, /* 100MHz */
+ {0x0E, 0x09, 0x06, 0x04, 0x02, 0x01, 0x00} /* 133MHz */
+};
+
+/* JCSTWTM/JCSTWTS */
+static const unsigned long JCSTWTxtbl[2][7] = {
+ {0x06, 0x04, 0x03, 0x02, 0x02, 0x02, 0x00}, /* 100MHz */
+ {0x09, 0x06, 0x04, 0x02, 0x02, 0x02, 0x02} /* 133MHz */
+};
+
+/* JCTSS */
+static const unsigned long JCTSStbl[2][7] = {
+ {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00}, /* 100MHz */
+ {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05} /* 133MHz */
+};
+
+/* JCENVT */
+static const unsigned long JCENVTtbl[2][7] = {
+ {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00}, /* 100MHz */
+ {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02} /* 133MHz */
+};
+
+/* JCACTSELS/JCACTSELM */
+static const unsigned long JCACTSELtbl[2][7] = {
+ {0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00}, /* 100MHz */
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} /* 133MHz */
+};
+
+static const struct pci_device_id scc_pci_tbl[] = {
+ {PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { } /* terminate list */
+};
+
+/**
+ * scc_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set PIO mode for device.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void scc_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ void __iomem *ctrl_base = ap->host->iomap[SCC_CTRL_BAR];
+ void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL;
+ void __iomem *piosht_port = ctrl_base + SCC_CTL_PIOSHT;
+ void __iomem *pioct_port = ctrl_base + SCC_CTL_PIOCT;
+ unsigned long reg;
+ int offset;
+
+ reg = in_be32(cckctrl_port);
+ if (reg & CCKCTRL_ATACLKOEN)
+ offset = 1; /* 133MHz */
+ else
+ offset = 0; /* 100MHz */
+
+ reg = JCHSTtbl[offset][pio] << 16 | JCHHTtbl[offset][pio];
+ out_be32(piosht_port, reg);
+ reg = JCHCTtbl[offset][pio];
+ out_be32(pioct_port, reg);
+}
+
+/**
+ * scc_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ * @udma: udma mode, 0 - 6
+ *
+ * Set UDMA mode for device.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int udma = adev->dma_mode;
+ unsigned int is_slave = (adev->devno != 0);
+ u8 speed = udma;
+ void __iomem *ctrl_base = ap->host->iomap[SCC_CTRL_BAR];
+ void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL;
+ void __iomem *mdmact_port = ctrl_base + SCC_CTL_MDMACT;
+ void __iomem *mcrcst_port = ctrl_base + SCC_CTL_MCRCST;
+ void __iomem *sdmact_port = ctrl_base + SCC_CTL_SDMACT;
+ void __iomem *scrcst_port = ctrl_base + SCC_CTL_SCRCST;
+ void __iomem *udenvt_port = ctrl_base + SCC_CTL_UDENVT;
+ void __iomem *tdvhsel_port = ctrl_base + SCC_CTL_TDVHSEL;
+ int offset, idx;
+
+ if (in_be32(cckctrl_port) & CCKCTRL_ATACLKOEN)
+ offset = 1; /* 133MHz */
+ else
+ offset = 0; /* 100MHz */
+
+ if (speed >= XFER_UDMA_0)
+ idx = speed - XFER_UDMA_0;
+ else
+ return;
+
+ if (is_slave) {
+ out_be32(sdmact_port, JCHDCTxtbl[offset][idx]);
+ out_be32(scrcst_port, JCSTWTxtbl[offset][idx]);
+ out_be32(tdvhsel_port,
+ (in_be32(tdvhsel_port) & ~TDVHSEL_SLAVE) | (JCACTSELtbl[offset][idx] << 2));
+ } else {
+ out_be32(mdmact_port, JCHDCTxtbl[offset][idx]);
+ out_be32(mcrcst_port, JCSTWTxtbl[offset][idx]);
+ out_be32(tdvhsel_port,
+ (in_be32(tdvhsel_port) & ~TDVHSEL_MASTER) | JCACTSELtbl[offset][idx]);
+ }
+ out_be32(udenvt_port,
+ JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]);
+}
+
+/**
+ * scc_tf_load - send taskfile registers to host controller
+ * @ap: Port to which output is sent
+ * @tf: ATA taskfile register set
+ *
+ * Note: Original code is ata_tf_load().
+ */
+
+static void scc_tf_load (struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+ if (tf->ctl != ap->last_ctl) {
+ out_be32(ioaddr->ctl_addr, tf->ctl);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ out_be32(ioaddr->feature_addr, tf->hob_feature);
+ out_be32(ioaddr->nsect_addr, tf->hob_nsect);
+ out_be32(ioaddr->lbal_addr, tf->hob_lbal);
+ out_be32(ioaddr->lbam_addr, tf->hob_lbam);
+ out_be32(ioaddr->lbah_addr, tf->hob_lbah);
+ VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+ tf->hob_feature,
+ tf->hob_nsect,
+ tf->hob_lbal,
+ tf->hob_lbam,
+ tf->hob_lbah);
+ }
+
+ if (is_addr) {
+ out_be32(ioaddr->feature_addr, tf->feature);
+ out_be32(ioaddr->nsect_addr, tf->nsect);
+ out_be32(ioaddr->lbal_addr, tf->lbal);
+ out_be32(ioaddr->lbam_addr, tf->lbam);
+ out_be32(ioaddr->lbah_addr, tf->lbah);
+ VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+ tf->feature,
+ tf->nsect,
+ tf->lbal,
+ tf->lbam,
+ tf->lbah);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE) {
+ out_be32(ioaddr->device_addr, tf->device);
+ VPRINTK("device 0x%X\n", tf->device);
+ }
+
+ ata_wait_idle(ap);
+}
+
+/**
+ * scc_check_status - Read device status reg & clear interrupt
+ * @ap: port where the device is
+ *
+ * Note: Original code is ata_check_status().
+ */
+
+static u8 scc_check_status (struct ata_port *ap)
+{
+ return in_be32(ap->ioaddr.status_addr);
+}
+
+/**
+ * scc_tf_read - input device's ATA taskfile shadow registers
+ * @ap: Port from which input is read
+ * @tf: ATA taskfile register set for storing input
+ *
+ * Note: Original code is ata_tf_read().
+ */
+
+static void scc_tf_read (struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ tf->command = scc_check_status(ap);
+ tf->feature = in_be32(ioaddr->error_addr);
+ tf->nsect = in_be32(ioaddr->nsect_addr);
+ tf->lbal = in_be32(ioaddr->lbal_addr);
+ tf->lbam = in_be32(ioaddr->lbam_addr);
+ tf->lbah = in_be32(ioaddr->lbah_addr);
+ tf->device = in_be32(ioaddr->device_addr);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ out_be32(ioaddr->ctl_addr, tf->ctl | ATA_HOB);
+ tf->hob_feature = in_be32(ioaddr->error_addr);
+ tf->hob_nsect = in_be32(ioaddr->nsect_addr);
+ tf->hob_lbal = in_be32(ioaddr->lbal_addr);
+ tf->hob_lbam = in_be32(ioaddr->lbam_addr);
+ tf->hob_lbah = in_be32(ioaddr->lbah_addr);
+ }
+}
+
+/**
+ * scc_exec_command - issue ATA command to host controller
+ * @ap: port to which command is being issued
+ * @tf: ATA taskfile register set
+ *
+ * Note: Original code is ata_exec_command().
+ */
+
+static void scc_exec_command (struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+
+ out_be32(ap->ioaddr.command_addr, tf->command);
+ ata_pause(ap);
+}
+
+/**
+ * scc_check_altstatus - Read device alternate status reg
+ * @ap: port where the device is
+ */
+
+static u8 scc_check_altstatus (struct ata_port *ap)
+{
+ return in_be32(ap->ioaddr.altstatus_addr);
+}
+
+/**
+ * scc_std_dev_select - Select device 0/1 on ATA bus
+ * @ap: ATA channel to manipulate
+ * @device: ATA device (numbered from zero) to select
+ *
+ * Note: Original code is ata_std_dev_select().
+ */
+
+static void scc_std_dev_select (struct ata_port *ap, unsigned int device)
+{
+ u8 tmp;
+
+ if (device == 0)
+ tmp = ATA_DEVICE_OBS;
+ else
+ tmp = ATA_DEVICE_OBS | ATA_DEV1;
+
+ out_be32(ap->ioaddr.device_addr, tmp);
+ ata_pause(ap);
+}
+
+/**
+ * scc_bmdma_setup - Set up PCI IDE BMDMA transaction
+ * @qc: Info associated with this ATA transaction.
+ *
+ * Note: Original code is ata_bmdma_setup().
+ */
+
+static void scc_bmdma_setup (struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+ u8 dmactl;
+ void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+ /* load PRD table addr */
+ out_be32(mmio + SCC_DMA_TABLE_OFS, ap->prd_dma);
+
+ /* specify data direction, triple-check start bit is clear */
+ dmactl = in_be32(mmio + SCC_DMA_CMD);
+ dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+ if (!rw)
+ dmactl |= ATA_DMA_WR;
+ out_be32(mmio + SCC_DMA_CMD, dmactl);
+
+ /* issue r/w command */
+ ap->ops->exec_command(ap, &qc->tf);
+}
+
+/**
+ * scc_bmdma_start - Start a PCI IDE BMDMA transaction
+ * @qc: Info associated with this ATA transaction.
+ *
+ * Note: Original code is ata_bmdma_start().
+ */
+
+static void scc_bmdma_start (struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ u8 dmactl;
+ void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+ /* start host DMA transaction */
+ dmactl = in_be32(mmio + SCC_DMA_CMD);
+ out_be32(mmio + SCC_DMA_CMD, dmactl | ATA_DMA_START);
+}
+
+/**
+ * scc_devchk - PATA device presence detection
+ * @ap: ATA channel to examine
+ * @device: Device to examine (starting at zero)
+ *
+ * Note: Original code is ata_devchk().
+ */
+
+static unsigned int scc_devchk (struct ata_port *ap,
+ unsigned int device)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ u8 nsect, lbal;
+
+ ap->ops->dev_select(ap, device);
+
+ out_be32(ioaddr->nsect_addr, 0x55);
+ out_be32(ioaddr->lbal_addr, 0xaa);
+
+ out_be32(ioaddr->nsect_addr, 0xaa);
+ out_be32(ioaddr->lbal_addr, 0x55);
+
+ out_be32(ioaddr->nsect_addr, 0x55);
+ out_be32(ioaddr->lbal_addr, 0xaa);
+
+ nsect = in_be32(ioaddr->nsect_addr);
+ lbal = in_be32(ioaddr->lbal_addr);
+
+ if ((nsect == 0x55) && (lbal == 0xaa))
+ return 1; /* we found a device */
+
+ return 0; /* nothing found */
+}
+
+/**
+ * scc_bus_post_reset - PATA device post reset
+ *
+ * Note: Original code is ata_bus_post_reset().
+ */
+
+static void scc_bus_post_reset (struct ata_port *ap, unsigned int devmask)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ unsigned int dev0 = devmask & (1 << 0);
+ unsigned int dev1 = devmask & (1 << 1);
+ unsigned long timeout;
+
+ /* if device 0 was found in ata_devchk, wait for its
+ * BSY bit to clear
+ */
+ if (dev0)
+ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+ /* if device 1 was found in ata_devchk, wait for
+ * register access, then wait for BSY to clear
+ */
+ timeout = jiffies + ATA_TMOUT_BOOT;
+ while (dev1) {
+ u8 nsect, lbal;
+
+ ap->ops->dev_select(ap, 1);
+ nsect = in_be32(ioaddr->nsect_addr);
+ lbal = in_be32(ioaddr->lbal_addr);
+ if ((nsect == 1) && (lbal == 1))
+ break;
+ if (time_after(jiffies, timeout)) {
+ dev1 = 0;
+ break;
+ }
+ msleep(50); /* give drive a breather */
+ }
+ if (dev1)
+ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+ /* is all this really necessary? */
+ ap->ops->dev_select(ap, 0);
+ if (dev1)
+ ap->ops->dev_select(ap, 1);
+ if (dev0)
+ ap->ops->dev_select(ap, 0);
+}
+
+/**
+ * scc_bus_softreset - PATA device software reset
+ *
+ * Note: Original code is ata_bus_softreset().
+ */
+
+static unsigned int scc_bus_softreset (struct ata_port *ap,
+ unsigned int devmask)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ DPRINTK("ata%u: bus reset via SRST\n", ap->print_id);
+
+ /* software reset. causes dev0 to be selected */
+ out_be32(ioaddr->ctl_addr, ap->ctl);
+ udelay(20);
+ out_be32(ioaddr->ctl_addr, ap->ctl | ATA_SRST);
+ udelay(20);
+ out_be32(ioaddr->ctl_addr, ap->ctl);
+
+ /* spec mandates ">= 2ms" before checking status.
+ * We wait 150ms, because that was the magic delay used for
+ * ATAPI devices in Hale Landis's ATADRVR, for the period of time
+ * between when the ATA command register is written, and then
+ * status is checked. Because waiting for "a while" before
+ * checking status is fine, post SRST, we perform this magic
+ * delay here as well.
+ *
+ * Old drivers/ide uses the 2mS rule and then waits for ready
+ */
+ msleep(150);
+
+ /* Before we perform post reset processing we want to see if
+ * the bus shows 0xFF because the odd clown forgets the D7
+ * pulldown resistor.
+ */
+ if (scc_check_status(ap) == 0xFF)
+ return 0;
+
+ scc_bus_post_reset(ap, devmask);
+
+ return 0;
+}
+
+/**
+ * scc_std_softreset - reset host port via ATA SRST
+ * @ap: port to reset
+ * @classes: resulting classes of attached devices
+ *
+ * Note: Original code is ata_std_softreset().
+ */
+
+static int scc_std_softreset (struct ata_port *ap, unsigned int *classes)
+{
+ unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+ unsigned int devmask = 0, err_mask;
+ u8 err;
+
+ DPRINTK("ENTER\n");
+
+ if (ata_port_offline(ap)) {
+ classes[0] = ATA_DEV_NONE;
+ goto out;
+ }
+
+ /* determine if device 0/1 are present */
+ if (scc_devchk(ap, 0))
+ devmask |= (1 << 0);
+ if (slave_possible && scc_devchk(ap, 1))
+ devmask |= (1 << 1);
+
+ /* select device 0 again */
+ ap->ops->dev_select(ap, 0);
+
+ /* issue bus reset */
+ DPRINTK("about to softreset, devmask=%x\n", devmask);
+ err_mask = scc_bus_softreset(ap, devmask);
+ if (err_mask) {
+ ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",
+ err_mask);
+ return -EIO;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_dev_try_classify(ap, 0, &err);
+ if (slave_possible && err != 0x81)
+ classes[1] = ata_dev_try_classify(ap, 1, &err);
+
+ out:
+ DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
+ return 0;
+}
+
+/**
+ * scc_bmdma_stop - Stop PCI IDE BMDMA transfer
+ * @qc: Command we are ending DMA for
+ */
+
+static void scc_bmdma_stop (struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ void __iomem *ctrl_base = ap->host->iomap[SCC_CTRL_BAR];
+ void __iomem *bmid_base = ap->host->iomap[SCC_BMID_BAR];
+ u32 reg;
+
+ while (1) {
+ reg = in_be32(bmid_base + SCC_DMA_INTST);
+
+ if (reg & INTSTS_SERROR) {
+ printk(KERN_WARNING "%s: SERROR\n", DRV_NAME);
+ out_be32(bmid_base + SCC_DMA_INTST, INTSTS_SERROR|INTSTS_BMSINT);
+ out_be32(bmid_base + SCC_DMA_CMD,
+ in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
+ continue;
+ }
+
+ if (reg & INTSTS_PRERR) {
+ u32 maea0, maec0;
+ maea0 = in_be32(ctrl_base + SCC_CTL_MAEA0);
+ maec0 = in_be32(ctrl_base + SCC_CTL_MAEC0);
+ printk(KERN_WARNING "%s: PRERR [addr:%x cmd:%x]\n", DRV_NAME, maea0, maec0);
+ out_be32(bmid_base + SCC_DMA_INTST, INTSTS_PRERR|INTSTS_BMSINT);
+ out_be32(bmid_base + SCC_DMA_CMD,
+ in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
+ continue;
+ }
+
+ if (reg & INTSTS_RERR) {
+ printk(KERN_WARNING "%s: Response Error\n", DRV_NAME);
+ out_be32(bmid_base + SCC_DMA_INTST, INTSTS_RERR|INTSTS_BMSINT);
+ out_be32(bmid_base + SCC_DMA_CMD,
+ in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
+ continue;
+ }
+
+ if (reg & INTSTS_ICERR) {
+ out_be32(bmid_base + SCC_DMA_CMD,
+ in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
+ printk(KERN_WARNING "%s: Illegal Configuration\n", DRV_NAME);
+ out_be32(bmid_base + SCC_DMA_INTST, INTSTS_ICERR|INTSTS_BMSINT);
+ continue;
+ }
+
+ if (reg & INTSTS_BMSINT) {
+ unsigned int classes;
+ printk(KERN_WARNING "%s: Internal Bus Error\n", DRV_NAME);
+ out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMSINT);
+ /* TBD: SW reset */
+ scc_std_softreset(ap, &classes);
+ continue;
+ }
+
+ if (reg & INTSTS_BMHE) {
+ out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMHE);
+ continue;
+ }
+
+ if (reg & INTSTS_ACTEINT) {
+ out_be32(bmid_base + SCC_DMA_INTST, INTSTS_ACTEINT);
+ continue;
+ }
+
+ if (reg & INTSTS_IOIRQS) {
+ out_be32(bmid_base + SCC_DMA_INTST, INTSTS_IOIRQS);
+ continue;
+ }
+ break;
+ }
+
+ /* clear start/stop bit */
+ out_be32(bmid_base + SCC_DMA_CMD,
+ in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
+
+ /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
+ ata_altstatus(ap); /* dummy read */
+}
+
+/**
+ * scc_bmdma_status - Read PCI IDE BMDMA status
+ * @ap: Port associated with this ATA transaction.
+ */
+
+static u8 scc_bmdma_status (struct ata_port *ap)
+{
+ u8 host_stat;
+ void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+ host_stat = in_be32(mmio + SCC_DMA_STATUS);
+
+ /* Workaround for PTERADD: emulate DMA_INTR when
+ * - IDE_STATUS[ERR] = 1
+ * - INT_STATUS[INTRQ] = 1
+ * - DMA_STATUS[IORACTA] = 1
+ */
+ if (!(host_stat & ATA_DMA_INTR)) {
+ u32 int_status = in_be32(mmio + SCC_DMA_INTST);
+ if (ata_altstatus(ap) & ATA_ERR &&
+ int_status & INTSTS_INTRQ &&
+ host_stat & ATA_DMA_ACTIVE)
+ host_stat |= ATA_DMA_INTR;
+ }
+
+ return host_stat;
+}
+
+/**
+ * scc_data_xfer - Transfer data by PIO
+ * @adev: device for this I/O
+ * @buf: data buffer
+ * @buflen: buffer length
+ * @write_data: read/write
+ *
+ * Note: Original code is ata_data_xfer().
+ */
+
+static void scc_data_xfer (struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data)
+{
+ struct ata_port *ap = adev->ap;
+ unsigned int words = buflen >> 1;
+ unsigned int i;
+ u16 *buf16 = (u16 *) buf;
+ void __iomem *mmio = ap->ioaddr.data_addr;
+
+ /* Transfer multiple of 2 bytes */
+ if (write_data) {
+ for (i = 0; i < words; i++)
+ out_be32(mmio, cpu_to_le16(buf16[i]));
+ } else {
+ for (i = 0; i < words; i++)
+ buf16[i] = le16_to_cpu(in_be32(mmio));
+ }
+
+ /* Transfer trailing 1 byte, if any. */
+ if (unlikely(buflen & 0x01)) {
+ u16 align_buf[1] = { 0 };
+ unsigned char *trailing_buf = buf + buflen - 1;
+
+ if (write_data) {
+ memcpy(align_buf, trailing_buf, 1);
+ out_be32(mmio, cpu_to_le16(align_buf[0]));
+ } else {
+ align_buf[0] = le16_to_cpu(in_be32(mmio));
+ memcpy(trailing_buf, align_buf, 1);
+ }
+ }
+}
+
+/**
+ * scc_irq_on - Enable interrupts on a port.
+ * @ap: Port on which interrupts are enabled.
+ *
+ * Note: Original code is ata_irq_on().
+ */
+
+static u8 scc_irq_on (struct ata_port *ap)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ u8 tmp;
+
+ ap->ctl &= ~ATA_NIEN;
+ ap->last_ctl = ap->ctl;
+
+ out_be32(ioaddr->ctl_addr, ap->ctl);
+ tmp = ata_wait_idle(ap);
+
+ ap->ops->irq_clear(ap);
+
+ return tmp;
+}
+
+/**
+ * scc_irq_ack - Acknowledge a device interrupt.
+ * @ap: Port on which interrupts are enabled.
+ *
+ * Note: Original code is ata_irq_ack().
+ */
+
+static u8 scc_irq_ack (struct ata_port *ap, unsigned int chk_drq)
+{
+ unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
+ u8 host_stat, post_stat, status;
+
+ status = ata_busy_wait(ap, bits, 1000);
+ if (status & bits)
+ if (ata_msg_err(ap))
+ printk(KERN_ERR "abnormal status 0x%X\n", status);
+
+ /* get controller status; clear intr, err bits */
+ host_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS);
+ out_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS,
+ host_stat | ATA_DMA_INTR | ATA_DMA_ERR);
+
+ post_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS);
+
+ if (ata_msg_intr(ap))
+ printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
+ __FUNCTION__,
+ host_stat, post_stat, status);
+
+ return status;
+}
+
+/**
+ * scc_bmdma_freeze - Freeze BMDMA controller port
+ * @ap: port to freeze
+ *
+ * Note: Original code is ata_bmdma_freeze().
+ */
+
+static void scc_bmdma_freeze (struct ata_port *ap)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ ap->ctl |= ATA_NIEN;
+ ap->last_ctl = ap->ctl;
+
+ out_be32(ioaddr->ctl_addr, ap->ctl);
+
+ /* Under certain circumstances, some controllers raise IRQ on
+ * ATA_NIEN manipulation. Also, many controllers fail to mask
+ * previously pending IRQ on ATA_NIEN assertion. Clear it.
+ */
+ ata_chk_status(ap);
+
+ ap->ops->irq_clear(ap);
+}
+
+/**
+ * scc_pata_prereset - prepare for reset
+ * @ap: ATA port to be reset
+ */
+
+static int scc_pata_prereset (struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * scc_std_postreset - standard postreset callback
+ * @ap: the target ata_port
+ * @classes: classes of attached devices
+ *
+ * Note: Original code is ata_std_postreset().
+ */
+
+static void scc_std_postreset (struct ata_port *ap, unsigned int *classes)
+{
+ DPRINTK("ENTER\n");
+
+ /* re-enable interrupts */
+ if (!ap->ops->error_handler)
+ ap->ops->irq_on(ap);
+
+ /* is double-select really necessary? */
+ if (classes[0] != ATA_DEV_NONE)
+ ap->ops->dev_select(ap, 1);
+ if (classes[1] != ATA_DEV_NONE)
+ ap->ops->dev_select(ap, 0);
+
+ /* bail out if no device is present */
+ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
+ DPRINTK("EXIT, no device\n");
+ return;
+ }
+
+ /* set up device control */
+ if (ap->ioaddr.ctl_addr)
+ out_be32(ap->ioaddr.ctl_addr, ap->ctl);
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * scc_error_handler - Stock error handler for BMDMA controller
+ * @ap: port to handle error for
+ */
+
+static void scc_error_handler (struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, scc_pata_prereset, scc_std_softreset, NULL,
+ scc_std_postreset);
+}
+
+/**
+ * scc_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt.
+ * @ap: Port associated with this ATA transaction.
+ *
+ * Note: Original code is ata_bmdma_irq_clear().
+ */
+
+static void scc_bmdma_irq_clear (struct ata_port *ap)
+{
+ void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+ if (!mmio)
+ return;
+
+ out_be32(mmio + SCC_DMA_STATUS, in_be32(mmio + SCC_DMA_STATUS));
+}
+
+/**
+ * scc_port_start - Set port up for dma.
+ * @ap: Port to initialize
+ *
+ * Allocate space for PRD table using ata_port_start().
+ * Set PRD table address for PTERADD. (PRD Transfer End Read)
+ */
+
+static int scc_port_start (struct ata_port *ap)
+{
+ void __iomem *mmio = ap->ioaddr.bmdma_addr;
+ int rc;
+
+ rc = ata_port_start(ap);
+ if (rc)
+ return rc;
+
+ out_be32(mmio + SCC_DMA_PTERADD, ap->prd_dma);
+ return 0;
+}
+
+/**
+ * scc_port_stop - Undo scc_port_start()
+ * @ap: Port to shut down
+ *
+ * Reset PTERADD.
+ */
+
+static void scc_port_stop (struct ata_port *ap)
+{
+ void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+ out_be32(mmio + SCC_DMA_PTERADD, 0);
+}
+
+static struct scsi_host_template scc_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
+ .resume = ata_scsi_device_resume,
+ .suspend = ata_scsi_device_suspend,
+#endif
+};
+
+static const struct ata_port_operations scc_pata_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = scc_set_piomode,
+ .set_dmamode = scc_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = scc_tf_load,
+ .tf_read = scc_tf_read,
+ .exec_command = scc_exec_command,
+ .check_status = scc_check_status,
+ .check_altstatus = scc_check_altstatus,
+ .dev_select = scc_std_dev_select,
+
+ .bmdma_setup = scc_bmdma_setup,
+ .bmdma_start = scc_bmdma_start,
+ .bmdma_stop = scc_bmdma_stop,
+ .bmdma_status = scc_bmdma_status,
+ .data_xfer = scc_data_xfer,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .freeze = scc_bmdma_freeze,
+ .error_handler = scc_error_handler,
+ .post_internal_cmd = scc_bmdma_stop,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = scc_bmdma_irq_clear,
+ .irq_on = scc_irq_on,
+ .irq_ack = scc_irq_ack,
+
+ .port_start = scc_port_start,
+ .port_stop = scc_port_stop,
+};
+
+static struct ata_port_info scc_port_info[] = {
+ {
+ .sht = &scc_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x00,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &scc_pata_ops,
+ },
+};
+
+/**
+ * scc_reset_controller - initialize SCC PATA controller.
+ */
+
+static int scc_reset_controller(struct ata_probe_ent *probe_ent)
+{
+ void __iomem *ctrl_base = probe_ent->iomap[SCC_CTRL_BAR];
+ void __iomem *bmid_base = probe_ent->iomap[SCC_BMID_BAR];
+ void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL;
+ void __iomem *mode_port = ctrl_base + SCC_CTL_MODEREG;
+ void __iomem *ecmode_port = ctrl_base + SCC_CTL_ECMODE;
+ void __iomem *intmask_port = bmid_base + SCC_DMA_INTMASK;
+ void __iomem *dmastatus_port = bmid_base + SCC_DMA_STATUS;
+ u32 reg = 0;
+
+ out_be32(cckctrl_port, reg);
+ reg |= CCKCTRL_ATACLKOEN;
+ out_be32(cckctrl_port, reg);
+ reg |= CCKCTRL_LCLKEN | CCKCTRL_OCLKEN;
+ out_be32(cckctrl_port, reg);
+ reg |= CCKCTRL_CRST;
+ out_be32(cckctrl_port, reg);
+
+ for (;;) {
+ reg = in_be32(cckctrl_port);
+ if (reg & CCKCTRL_CRST)
+ break;
+ udelay(5000);
+ }
+
+ reg |= CCKCTRL_ATARESET;
+ out_be32(cckctrl_port, reg);
+ out_be32(ecmode_port, ECMODE_VALUE);
+ out_be32(mode_port, MODE_JCUSFEN);
+ out_be32(intmask_port, INTMASK_MSK);
+
+ if (in_be32(dmastatus_port) & QCHSD_STPDIAG) {
+ printk(KERN_WARNING "%s: failed to detect 80c cable. (PDIAG# is high)\n", DRV_NAME);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * scc_setup_ports - initialize ioaddr with SCC PATA port offsets.
+ * @ioaddr: IO address structure to be initialized
+ * @base: base address of BMID region
+ */
+
+static void scc_setup_ports (struct ata_ioports *ioaddr, void __iomem *base)
+{
+ ioaddr->cmd_addr = base + SCC_REG_CMD_ADDR;
+ ioaddr->altstatus_addr = ioaddr->cmd_addr + SCC_REG_ALTSTATUS;
+ ioaddr->ctl_addr = ioaddr->cmd_addr + SCC_REG_ALTSTATUS;
+ ioaddr->bmdma_addr = base;
+ ioaddr->data_addr = ioaddr->cmd_addr + SCC_REG_DATA;
+ ioaddr->error_addr = ioaddr->cmd_addr + SCC_REG_ERR;
+ ioaddr->feature_addr = ioaddr->cmd_addr + SCC_REG_FEATURE;
+ ioaddr->nsect_addr = ioaddr->cmd_addr + SCC_REG_NSECT;
+ ioaddr->lbal_addr = ioaddr->cmd_addr + SCC_REG_LBAL;
+ ioaddr->lbam_addr = ioaddr->cmd_addr + SCC_REG_LBAM;
+ ioaddr->lbah_addr = ioaddr->cmd_addr + SCC_REG_LBAH;
+ ioaddr->device_addr = ioaddr->cmd_addr + SCC_REG_DEVICE;
+ ioaddr->status_addr = ioaddr->cmd_addr + SCC_REG_STATUS;
+ ioaddr->command_addr = ioaddr->cmd_addr + SCC_REG_CMD;
+}
+
+static int scc_host_init(struct ata_probe_ent *probe_ent)
+{
+ struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+ int rc;
+
+ rc = scc_reset_controller(probe_ent);
+ if (rc)
+ return rc;
+
+ probe_ent->n_ports = 1;
+
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
+
+ scc_setup_ports(&probe_ent->port[0], probe_ent->iomap[SCC_BMID_BAR]);
+
+ pci_set_master(pdev);
+
+ return 0;
+}
+
+/**
+ * scc_init_one - Register SCC PATA device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in scc_pci_tbl matching with @pdev
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ unsigned int board_idx = (unsigned int) ent->driver_data;
+ struct device *dev = &pdev->dev;
+ struct ata_probe_ent *probe_ent;
+ int rc;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pcim_iomap_regions(pdev, (1 << SCC_CTRL_BAR) | (1 << SCC_BMID_BAR), DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
+
+ probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (!probe_ent)
+ return -ENOMEM;
+
+ probe_ent->dev = dev;
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ probe_ent->sht = scc_port_info[board_idx].sht;
+ probe_ent->port_flags = scc_port_info[board_idx].flags;
+ probe_ent->pio_mask = scc_port_info[board_idx].pio_mask;
+ probe_ent->udma_mask = scc_port_info[board_idx].udma_mask;
+ probe_ent->port_ops = scc_port_info[board_idx].port_ops;
+
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = IRQF_SHARED;
+ probe_ent->iomap = pcim_iomap_table(pdev);
+
+ rc = scc_host_init(probe_ent);
+ if (rc)
+ return rc;
+
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+
+ devm_kfree(dev, probe_ent);
+ return 0;
+}
+
+static struct pci_driver scc_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = scc_pci_tbl,
+ .probe = scc_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+#endif
+};
+
+static int __init scc_init (void)
+{
+ int rc;
+
+ DPRINTK("pci_register_driver\n");
+ rc = pci_register_driver(&scc_pci_driver);
+ if (rc)
+ return rc;
+
+ DPRINTK("done\n");
+ return 0;
+}
+
+static void __exit scc_exit (void)
+{
+ pci_unregister_driver(&scc_pci_driver);
+}
+
+module_init(scc_init);
+module_exit(scc_exit);
+
+MODULE_AUTHOR("Toshiba corp");
+MODULE_DESCRIPTION("SCSI low-level driver for Toshiba SCC PATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, scc_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index ad5b43fef3d..598eef810a7 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -41,7 +41,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_serverworks"
-#define DRV_VERSION "0.3.9"
+#define DRV_VERSION "0.4.0"
#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
#define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
@@ -319,8 +319,10 @@ static struct scsi_host_template serverworks_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations serverworks_osb4_port_ops = {
@@ -548,6 +550,7 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id
return ata_pci_init_one(pdev, port_info, ports);
}
+#ifdef CONFIG_PM
static int serverworks_reinit_one(struct pci_dev *pdev)
{
/* Force master latency timer to 64 PCI clocks */
@@ -571,6 +574,7 @@ static int serverworks_reinit_one(struct pci_dev *pdev)
}
return ata_pci_device_resume(pdev);
}
+#endif
static const struct pci_device_id serverworks[] = {
{ PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0},
@@ -587,8 +591,10 @@ static struct pci_driver serverworks_pci_driver = {
.id_table = serverworks,
.probe = serverworks_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = serverworks_reinit_one,
+#endif
};
static int __init serverworks_init(void)
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index ed79fabe025..dab2889a556 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -33,7 +33,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_sil680"
-#define DRV_VERSION "0.4.1"
+#define DRV_VERSION "0.4.5"
/**
* sil680_selreg - return register base
@@ -139,10 +139,13 @@ static void sil680_set_piomode(struct ata_port *ap, struct ata_device *adev)
unsigned long tfaddr = sil680_selreg(ap, 0x02);
unsigned long addr = sil680_seldev(ap, adev, 0x04);
+ unsigned long addr_mask = 0x80 + 4 * ap->port_no;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
int pio = adev->pio_mode - XFER_PIO_0;
int lowest_pio = pio;
+ int port_shift = 4 * adev->devno;
u16 reg;
+ u8 mode;
struct ata_device *pair = ata_dev_pair(adev);
@@ -153,10 +156,17 @@ static void sil680_set_piomode(struct ata_port *ap, struct ata_device *adev)
pci_write_config_word(pdev, tfaddr, speed_t[lowest_pio]);
pci_read_config_word(pdev, tfaddr-2, &reg);
+ pci_read_config_byte(pdev, addr_mask, &mode);
+
reg &= ~0x0200; /* Clear IORDY */
- if (ata_pio_need_iordy(adev))
+ mode &= ~(3 << port_shift); /* Clear IORDY and DMA bits */
+
+ if (ata_pio_need_iordy(adev)) {
reg |= 0x0200; /* Enable IORDY */
+ mode |= 1 << port_shift;
+ }
pci_write_config_word(pdev, tfaddr-2, reg);
+ pci_write_config_byte(pdev, addr_mask, mode);
}
/**
@@ -226,6 +236,10 @@ static struct scsi_host_template sil680_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
+#endif
};
static struct ata_port_operations sil680_port_ops = {
@@ -367,11 +381,13 @@ static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return ata_pci_init_one(pdev, port_info, 2);
}
+#ifdef CONFIG_PM
static int sil680_reinit_one(struct pci_dev *pdev)
{
sil680_init_chip(pdev);
return ata_pci_device_resume(pdev);
}
+#endif
static const struct pci_device_id sil680[] = {
{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), },
@@ -384,8 +400,10 @@ static struct pci_driver sil680_pci_driver = {
.id_table = sil680,
.probe = sil680_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = sil680_reinit_one,
+#endif
};
static int __init sil680_init(void)
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index 560103d55b2..f4820786593 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -32,11 +32,10 @@
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#include <linux/ata.h>
-#include "libata.h"
+#include "sis.h"
-#undef DRV_NAME /* already defined in libata.h, for libata-core */
#define DRV_NAME "pata_sis"
-#define DRV_VERSION "0.4.5"
+#define DRV_VERSION "0.5.0"
struct sis_chipset {
u16 device; /* PCI host ID */
@@ -151,7 +150,7 @@ static int sis_66_pre_reset(struct ata_port *ap)
if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) {
ata_port_disable(ap);
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
+ ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
return 0;
}
/* Older chips keep cable detect in bits 4/5 of reg 0x48 */
@@ -197,7 +196,7 @@ static int sis_old_pre_reset(struct ata_port *ap)
if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) {
ata_port_disable(ap);
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
+ ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
return 0;
}
ap->cbl = ATA_CBL_PATA40;
@@ -576,8 +575,10 @@ static struct scsi_host_template sis_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static const struct ata_port_operations sis_133_ops = {
@@ -1033,8 +1034,10 @@ static struct pci_driver sis_pci_driver = {
.id_table = sis_pci_tbl,
.probe = sis_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static int __init sis_init(void)
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index 96e890fd645..b681441cfcb 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -7,6 +7,13 @@
* SL82C105/Winbond 553 IDE driver
*
* and in part on the documentation and errata sheet
+ *
+ *
+ * Note: The controller like many controllers has shared timings for
+ * PIO and DMA. We thus flip to the DMA timings in dma_start and flip back
+ * in the dma_stop function. Thus we actually don't need a set_dmamode
+ * method as the PIO method is always called and will set the right PIO
+ * timing parameters.
*/
#include <linux/kernel.h>
@@ -19,7 +26,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_sl82c105"
-#define DRV_VERSION "0.2.3"
+#define DRV_VERSION "0.3.0"
enum {
/*
@@ -126,33 +133,6 @@ static void sl82c105_configure_dmamode(struct ata_port *ap, struct ata_device *a
}
/**
- * sl82c105_set_dmamode - set initial DMA mode data
- * @ap: ATA interface
- * @adev: ATA device
- *
- * Called to do the DMA mode setup. This replaces the PIO timings
- * for the device in question. Set appropriate PIO timings not DMA
- * timings at this point.
- */
-
-static void sl82c105_set_dmamode(struct ata_port *ap, struct ata_device *adev)
-{
- switch(adev->dma_mode) {
- case XFER_MW_DMA_0:
- sl82c105_configure_piomode(ap, adev, 0);
- break;
- case XFER_MW_DMA_1:
- sl82c105_configure_piomode(ap, adev, 3);
- break;
- case XFER_MW_DMA_2:
- sl82c105_configure_piomode(ap, adev, 4);
- break;
- default:
- BUG();
- }
-}
-
-/**
* sl82c105_reset_engine - Reset the DMA engine
* @ap: ATA interface
*
@@ -222,7 +202,7 @@ static void sl82c105_bmdma_stop(struct ata_queued_cmd *qc)
/* This will redo the initial setup of the DMA device to matching
PIO timings */
- sl82c105_set_dmamode(ap, qc->dev);
+ sl82c105_set_piomode(ap, qc->dev);
}
static struct scsi_host_template sl82c105_sht = {
@@ -246,7 +226,6 @@ static struct scsi_host_template sl82c105_sht = {
static struct ata_port_operations sl82c105_port_ops = {
.port_disable = ata_port_disable,
.set_piomode = sl82c105_set_piomode,
- .set_dmamode = sl82c105_set_dmamode,
.mode_filter = ata_pci_default_filter,
.tf_load = ata_tf_load,
@@ -255,7 +234,10 @@ static struct ata_port_operations sl82c105_port_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
.error_handler = sl82c105_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = sl82c105_bmdma_start,
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index 453ab90b721..71418f2a0cd 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -193,8 +193,10 @@ static struct scsi_host_template triflex_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations triflex_port_ops = {
@@ -260,8 +262,10 @@ static struct pci_driver triflex_pci_driver = {
.id_table = triflex,
.probe = triflex_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
+#endif
};
static int __init triflex_init(void)
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index 220fcd6c549..946ade0e1f1 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -170,7 +170,7 @@ static int via_pre_reset(struct ata_port *ap)
ap->cbl = ATA_CBL_PATA40;
else
ap->cbl = ATA_CBL_PATA_UNK;
-
+
return ata_std_prereset(ap);
}
@@ -305,8 +305,10 @@ static struct scsi_host_template via_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.resume = ata_scsi_device_resume,
.suspend = ata_scsi_device_suspend,
+#endif
};
static struct ata_port_operations via_port_ops = {
@@ -560,6 +562,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return ata_pci_init_one(pdev, port_info, 2);
}
+#ifdef CONFIG_PM
/**
* via_reinit_one - reinit after resume
* @pdev; PCI device
@@ -592,6 +595,7 @@ static int via_reinit_one(struct pci_dev *pdev)
}
return ata_pci_device_resume(pdev);
}
+#endif
static const struct pci_device_id via[] = {
{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), },
@@ -607,8 +611,10 @@ static struct pci_driver via_pci_driver = {
.id_table = via,
.probe = via_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = via_reinit_one,
+#endif
};
static int __init via_init(void)
diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c
index 0888b4f19f4..6c111035fc8 100644
--- a/drivers/ata/pata_winbond.c
+++ b/drivers/ata/pata_winbond.c
@@ -17,7 +17,7 @@
#include <linux/platform_device.h>
#define DRV_NAME "pata_winbond"
-#define DRV_VERSION "0.0.1"
+#define DRV_VERSION "0.0.2"
#define NR_HOST 4 /* Two winbond controllers, two channels each */
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index 857ac23217a..5dd3ca8b5f2 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -44,7 +44,7 @@
#include <linux/libata.h>
#define DRV_NAME "pdc_adma"
-#define DRV_VERSION "0.04"
+#define DRV_VERSION "0.05"
/* macro to calculate base address for ATA regs */
#define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40))
@@ -498,7 +498,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host)
if ((status & ATA_BUSY))
continue;
DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
- ap->id, qc->tf.protocol, status);
+ ap->print_id, qc->tf.protocol, status);
/* complete taskfile transaction */
pp->state = adma_state_idle;
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 31b636fac98..3193a603d1a 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -135,8 +135,10 @@ static struct scsi_host_template inic_sht = {
.slave_configure = inic_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.suspend = ata_scsi_device_suspend,
.resume = ata_scsi_device_resume,
+#endif
};
static const int scr_map[] = {
@@ -632,6 +634,7 @@ static int init_controller(void __iomem *mmio_base, u16 hctl)
return 0;
}
+#ifdef CONFIG_PM
static int inic_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
@@ -642,7 +645,6 @@ static int inic_pci_device_resume(struct pci_dev *pdev)
ata_pci_device_do_resume(pdev);
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
- printk("XXX\n");
rc = init_controller(mmio_base, hpriv->cached_hctl);
if (rc)
return rc;
@@ -652,6 +654,7 @@ static int inic_pci_device_resume(struct pci_dev *pdev)
return 0;
}
+#endif
static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -755,8 +758,10 @@ static const struct pci_device_id inic_pci_tbl[] = {
static struct pci_driver inic_pci_driver = {
.name = DRV_NAME,
.id_table = inic_pci_tbl,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = inic_pci_device_resume,
+#endif
.probe = inic_init_one,
.remove = ata_pci_remove_one,
};
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index d689df52eae..a65ba636aaa 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -35,7 +35,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_mv"
-#define DRV_VERSION "0.7"
+#define DRV_VERSION "0.8"
enum {
/* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -137,14 +137,19 @@ enum {
PCI_ERR = (1 << 18),
TRAN_LO_DONE = (1 << 19), /* 6xxx: IRQ coalescing */
TRAN_HI_DONE = (1 << 20), /* 6xxx: IRQ coalescing */
+ PORTS_0_3_COAL_DONE = (1 << 8),
+ PORTS_4_7_COAL_DONE = (1 << 17),
PORTS_0_7_COAL_DONE = (1 << 21), /* 6xxx: IRQ coalescing */
GPIO_INT = (1 << 22),
SELF_INT = (1 << 23),
TWSI_INT = (1 << 24),
HC_MAIN_RSVD = (0x7f << 25), /* bits 31-25 */
+ HC_MAIN_RSVD_5 = (0x1fff << 19), /* bits 31-19 */
HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_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),
/* SATAHC registers */
HC_CFG_OFS = 0,
@@ -814,23 +819,27 @@ static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
/* set up non-NCQ EDMA configuration */
- cfg &= ~0x1f; /* clear queue depth */
- cfg &= ~EDMA_CFG_NCQ; /* clear NCQ mode */
cfg &= ~(1 << 9); /* disable equeue */
- if (IS_GEN_I(hpriv))
+ if (IS_GEN_I(hpriv)) {
+ cfg &= ~0x1f; /* clear queue depth */
cfg |= (1 << 8); /* enab config burst size mask */
+ }
- else if (IS_GEN_II(hpriv))
+ else if (IS_GEN_II(hpriv)) {
+ cfg &= ~0x1f; /* clear queue depth */
cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
+ cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */
+ }
else if (IS_GEN_IIE(hpriv)) {
- cfg |= (1 << 23); /* dis RX PM port mask */
- cfg &= ~(1 << 16); /* dis FIS-based switching (for now) */
+ cfg |= (1 << 23); /* do not mask PM field in rx'd FIS */
+ cfg |= (1 << 22); /* enab 4-entry host queue cache */
cfg &= ~(1 << 19); /* dis 128-entry queue (for now?) */
cfg |= (1 << 18); /* enab early completion */
- cfg |= (1 << 17); /* enab host q cache */
- cfg |= (1 << 22); /* enab cutthrough */
+ cfg |= (1 << 17); /* enab cut-through (dis stor&forwrd) */
+ cfg &= ~(1 << 16); /* dis FIS-based switching (for now) */
+ cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */
}
writelfl(cfg, port_mmio + EDMA_CFG_OFS);
@@ -1276,7 +1285,7 @@ static void mv_err_intr(struct ata_port *ap, int reset_allowed)
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
}
DPRINTK(KERN_ERR "ata%u: port error; EDMA err cause: 0x%08x "
- "SERR: 0x%08x\n", ap->id, edma_err_cause, serr);
+ "SERR: 0x%08x\n", ap->print_id, edma_err_cause, serr);
/* Clear EDMA now that SERR cleanup done */
writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
@@ -2052,7 +2061,7 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio)
port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS;
/* unused: */
- port->cmd_addr = port->bmdma_addr = port->scr_addr = 0;
+ port->cmd_addr = port->bmdma_addr = port->scr_addr = NULL;
/* Clear any currently outstanding port interrupt conditions */
serr_ofs = mv_scr_offset(SCR_ERROR);
@@ -2240,7 +2249,11 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
/* and unmask interrupt generation for host regs */
writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS);
- writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
+
+ if (IS_50XX(hpriv))
+ writelfl(~HC_MAIN_MASKED_IRQS_5, mmio + HC_MAIN_IRQ_MASK_OFS);
+ else
+ writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
"PCI int cause/mask=0x%08x/0x%08x\n",
@@ -2347,7 +2360,7 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return rc;
/* Enable interrupts */
- if (msi && !pci_enable_msi(pdev))
+ if (msi && pci_enable_msi(pdev))
pci_intx(pdev, 1);
mv_dump_pci_cfg(pdev, 0x68);
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index ab92f208dae..9d9670a9b11 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -219,6 +219,7 @@ struct nv_adma_port_priv {
void __iomem * gen_block;
void __iomem * notifier_clear_block;
u8 flags;
+ int last_issue_ncq;
};
struct nv_host_priv {
@@ -229,7 +230,9 @@ struct nv_host_priv {
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static void nv_remove_one (struct pci_dev *pdev);
+#ifdef CONFIG_PM
static int nv_pci_device_resume(struct pci_dev *pdev);
+#endif
static void nv_ck804_host_stop(struct ata_host *host);
static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
@@ -250,14 +253,13 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance);
static void nv_adma_irq_clear(struct ata_port *ap);
static int nv_adma_port_start(struct ata_port *ap);
static void nv_adma_port_stop(struct ata_port *ap);
+#ifdef CONFIG_PM
static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg);
static int nv_adma_port_resume(struct ata_port *ap);
+#endif
static void nv_adma_error_handler(struct ata_port *ap);
static void nv_adma_host_stop(struct ata_host *host);
-static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc);
-static void nv_adma_bmdma_start(struct ata_queued_cmd *qc);
-static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc);
-static u8 nv_adma_bmdma_status(struct ata_port *ap);
+static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc);
enum nv_host_type
{
@@ -297,8 +299,10 @@ static struct pci_driver nv_pci_driver = {
.name = DRV_NAME,
.id_table = nv_pci_tbl,
.probe = nv_init_one,
+#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = nv_pci_device_resume,
+#endif
.remove = nv_remove_one,
};
@@ -318,8 +322,10 @@ static struct scsi_host_template nv_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.suspend = ata_scsi_device_suspend,
.resume = ata_scsi_device_resume,
+#endif
};
static struct scsi_host_template nv_adma_sht = {
@@ -338,8 +344,10 @@ static struct scsi_host_template nv_adma_sht = {
.slave_configure = nv_adma_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.suspend = ata_scsi_device_suspend,
.resume = ata_scsi_device_resume,
+#endif
};
static const struct ata_port_operations nv_generic_ops = {
@@ -432,16 +440,16 @@ static const struct ata_port_operations nv_adma_ops = {
.exec_command = ata_exec_command,
.check_status = ata_check_status,
.dev_select = ata_std_dev_select,
- .bmdma_setup = nv_adma_bmdma_setup,
- .bmdma_start = nv_adma_bmdma_start,
- .bmdma_stop = nv_adma_bmdma_stop,
- .bmdma_status = nv_adma_bmdma_status,
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
.qc_prep = nv_adma_qc_prep,
.qc_issue = nv_adma_qc_issue,
.freeze = nv_ck804_freeze,
.thaw = nv_ck804_thaw,
.error_handler = nv_adma_error_handler,
- .post_internal_cmd = nv_adma_bmdma_stop,
+ .post_internal_cmd = nv_adma_post_internal_cmd,
.data_xfer = ata_data_xfer,
.irq_handler = nv_adma_interrupt,
.irq_clear = nv_adma_irq_clear,
@@ -451,8 +459,10 @@ static const struct ata_port_operations nv_adma_ops = {
.scr_write = nv_scr_write,
.port_start = nv_adma_port_start,
.port_stop = nv_adma_port_stop,
+#ifdef CONFIG_PM
.port_suspend = nv_adma_port_suspend,
.port_resume = nv_adma_port_resume,
+#endif
.host_stop = nv_adma_host_stop,
};
@@ -661,30 +671,31 @@ static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb)
{
unsigned int idx = 0;
- cpb[idx++] = cpu_to_le16((ATA_REG_DEVICE << 8) | tf->device | WNB);
-
- if ((tf->flags & ATA_TFLAG_LBA48) == 0) {
- cpb[idx++] = cpu_to_le16(IGN);
- cpb[idx++] = cpu_to_le16(IGN);
- cpb[idx++] = cpu_to_le16(IGN);
- cpb[idx++] = cpu_to_le16(IGN);
- cpb[idx++] = cpu_to_le16(IGN);
- }
- else {
- cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->hob_feature);
- cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->hob_nsect);
- cpb[idx++] = cpu_to_le16((ATA_REG_LBAL << 8) | tf->hob_lbal);
- cpb[idx++] = cpu_to_le16((ATA_REG_LBAM << 8) | tf->hob_lbam);
- cpb[idx++] = cpu_to_le16((ATA_REG_LBAH << 8) | tf->hob_lbah);
+ if(tf->flags & ATA_TFLAG_ISADDR) {
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->hob_feature | WNB);
+ cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->hob_nsect);
+ cpb[idx++] = cpu_to_le16((ATA_REG_LBAL << 8) | tf->hob_lbal);
+ cpb[idx++] = cpu_to_le16((ATA_REG_LBAM << 8) | tf->hob_lbam);
+ cpb[idx++] = cpu_to_le16((ATA_REG_LBAH << 8) | tf->hob_lbah);
+ cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->feature);
+ } else
+ cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->feature | WNB);
+
+ cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->nsect);
+ cpb[idx++] = cpu_to_le16((ATA_REG_LBAL << 8) | tf->lbal);
+ cpb[idx++] = cpu_to_le16((ATA_REG_LBAM << 8) | tf->lbam);
+ cpb[idx++] = cpu_to_le16((ATA_REG_LBAH << 8) | tf->lbah);
}
- cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->feature);
- cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->nsect);
- cpb[idx++] = cpu_to_le16((ATA_REG_LBAL << 8) | tf->lbal);
- cpb[idx++] = cpu_to_le16((ATA_REG_LBAM << 8) | tf->lbam);
- cpb[idx++] = cpu_to_le16((ATA_REG_LBAH << 8) | tf->lbah);
+
+ if(tf->flags & ATA_TFLAG_DEVICE)
+ cpb[idx++] = cpu_to_le16((ATA_REG_DEVICE << 8) | tf->device);
cpb[idx++] = cpu_to_le16((ATA_REG_CMD << 8) | tf->command | CMDEND);
+ while(idx < 12)
+ cpb[idx++] = cpu_to_le16(IGN);
+
return idx;
}
@@ -741,6 +752,17 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
DPRINTK("Completing qc from tag %d with err_mask %u\n",cpb_num,
qc->err_mask);
ata_qc_complete(qc);
+ } else {
+ struct ata_eh_info *ehi = &ap->eh_info;
+ /* Notifier bits set without a command may indicate the drive
+ is misbehaving. Raise host state machine violation on this
+ condition. */
+ ata_port_printk(ap, KERN_ERR, "notifier for tag %d with no command?\n",
+ cpb_num);
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ata_port_freeze(ap);
+ return 1;
}
}
return 0;
@@ -852,22 +874,20 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
if (status & (NV_ADMA_STAT_DONE |
NV_ADMA_STAT_CPBERR)) {
- /** Check CPBs for completed commands */
+ u32 check_commands;
+ int pos, error = 0;
+
+ if(ata_tag_valid(ap->active_tag))
+ check_commands = 1 << ap->active_tag;
+ else
+ check_commands = ap->sactive;
- if (ata_tag_valid(ap->active_tag)) {
- /* Non-NCQ command */
- nv_adma_check_cpb(ap, ap->active_tag,
- notifier_error & (1 << ap->active_tag));
- } else {
- int pos, error = 0;
- u32 active = ap->sactive;
-
- while ((pos = ffs(active)) && !error) {
- pos--;
- error = nv_adma_check_cpb(ap, pos,
- notifier_error & (1 << pos) );
- active &= ~(1 << pos );
- }
+ /** Check CPBs for completed commands */
+ while ((pos = ffs(check_commands)) && !error) {
+ pos--;
+ error = nv_adma_check_cpb(ap, pos,
+ notifier_error & (1 << pos) );
+ check_commands &= ~(1 << pos );
}
}
}
@@ -905,73 +925,12 @@ static void nv_adma_irq_clear(struct ata_port *ap)
iowrite8(ioread8(dma_stat_addr), dma_stat_addr);
}
-static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
- struct nv_adma_port_priv *pp = ap->private_data;
- u8 dmactl;
-
- if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) {
- WARN_ON(1);
- return;
- }
-
- /* load PRD table addr. */
- iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
-
- /* specify data direction, triple-check start bit is clear */
- dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
- dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
- if (!rw)
- dmactl |= ATA_DMA_WR;
-
- iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
-
- /* issue r/w command */
- ata_exec_command(ap, &qc->tf);
-}
-
-static void nv_adma_bmdma_start(struct ata_queued_cmd *qc)
+static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc)
{
- struct ata_port *ap = qc->ap;
- struct nv_adma_port_priv *pp = ap->private_data;
- u8 dmactl;
-
- if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) {
- WARN_ON(1);
- return;
- }
-
- /* start host DMA transaction */
- dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
- iowrite8(dmactl | ATA_DMA_START,
- ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
-}
-
-static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct nv_adma_port_priv *pp = ap->private_data;
-
- if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE))
- return;
-
- /* clear start/stop bit */
- iowrite8(ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
- ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
-
- /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
- ata_altstatus(ap); /* dummy read */
-}
-
-static u8 nv_adma_bmdma_status(struct ata_port *ap)
-{
- struct nv_adma_port_priv *pp = ap->private_data;
-
- WARN_ON(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE));
+ struct nv_adma_port_priv *pp = qc->ap->private_data;
- return ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ if(pp->flags & NV_ADMA_PORT_REGISTER_MODE)
+ ata_bmdma_post_internal_cmd(qc);
}
static int nv_adma_port_start(struct ata_port *ap)
@@ -1040,14 +999,15 @@ static int nv_adma_port_start(struct ata_port *ap)
/* clear GO for register mode, enable interrupt */
tmp = readw(mmio + NV_ADMA_CTL);
- writew( (tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);
+ writew( (tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN |
+ NV_ADMA_CTL_HOTPLUG_IEN, mmio + NV_ADMA_CTL);
tmp = readw(mmio + NV_ADMA_CTL);
writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
- readl( mmio + NV_ADMA_CTL ); /* flush posted write */
+ readw( mmio + NV_ADMA_CTL ); /* flush posted write */
udelay(1);
writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
- readl( mmio + NV_ADMA_CTL ); /* flush posted write */
+ readw( mmio + NV_ADMA_CTL ); /* flush posted write */
return 0;
}
@@ -1061,6 +1021,7 @@ static void nv_adma_port_stop(struct ata_port *ap)
writew(0, mmio + NV_ADMA_CTL);
}
+#ifdef CONFIG_PM
static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg)
{
struct nv_adma_port_priv *pp = ap->private_data;
@@ -1099,17 +1060,19 @@ static int nv_adma_port_resume(struct ata_port *ap)
/* clear GO for register mode, enable interrupt */
tmp = readw(mmio + NV_ADMA_CTL);
- writew((tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);
+ writew( (tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN |
+ NV_ADMA_CTL_HOTPLUG_IEN, mmio + NV_ADMA_CTL);
tmp = readw(mmio + NV_ADMA_CTL);
writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
- readl( mmio + NV_ADMA_CTL ); /* flush posted write */
+ readw( mmio + NV_ADMA_CTL ); /* flush posted write */
udelay(1);
writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
- readl( mmio + NV_ADMA_CTL ); /* flush posted write */
+ readw( mmio + NV_ADMA_CTL ); /* flush posted write */
return 0;
}
+#endif
static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port)
{
@@ -1163,11 +1126,7 @@ static void nv_adma_fill_aprd(struct ata_queued_cmd *qc,
int idx,
struct nv_adma_prd *aprd)
{
- u8 flags;
-
- memset(aprd, 0, sizeof(struct nv_adma_prd));
-
- flags = 0;
+ u8 flags = 0;
if (qc->tf.flags & ATA_TFLAG_WRITE)
flags |= NV_APRD_WRITE;
if (idx == qc->n_elem - 1)
@@ -1178,6 +1137,7 @@ static void nv_adma_fill_aprd(struct ata_queued_cmd *qc,
aprd->addr = cpu_to_le64(((u64)sg_dma_address(sg)));
aprd->len = cpu_to_le32(((u32)sg_dma_len(sg))); /* len in bytes */
aprd->flags = flags;
+ aprd->packet_len = 0;
}
static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb)
@@ -1198,6 +1158,8 @@ static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb)
}
if (idx > 5)
cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag)));
+ else
+ cpb->next_aprd = cpu_to_le64(0);
}
static int nv_adma_use_reg_mode(struct ata_queued_cmd *qc)
@@ -1230,7 +1192,10 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
return;
}
- memset(cpb, 0, sizeof(struct nv_adma_cpb));
+ cpb->resp_flags = NV_CPB_RESP_DONE;
+ wmb();
+ cpb->ctl_flags = 0;
+ wmb();
cpb->len = 3;
cpb->tag = qc->tag;
@@ -1254,12 +1219,15 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
finished filling in all of the contents */
wmb();
cpb->ctl_flags = ctl_flags;
+ wmb();
+ cpb->resp_flags = 0;
}
static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc)
{
struct nv_adma_port_priv *pp = qc->ap->private_data;
void __iomem *mmio = pp->ctl_block;
+ int curr_ncq = (qc->tf.protocol == ATA_PROT_NCQ);
VPRINTK("ENTER\n");
@@ -1274,6 +1242,14 @@ static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc)
/* write append register, command tag in lower 8 bits
and (number of cpbs to append -1) in top 8 bits */
wmb();
+
+ if(curr_ncq != pp->last_issue_ncq) {
+ /* Seems to need some delay before switching between NCQ and non-NCQ
+ commands, else we get command timeouts and such. */
+ udelay(20);
+ pp->last_issue_ncq = curr_ncq;
+ }
+
writew(qc->tag, mmio + NV_ADMA_APPEND);
DPRINTK("Issued tag %u\n",qc->tag);
@@ -1447,6 +1423,30 @@ static void nv_adma_error_handler(struct ata_port *ap)
int i;
u16 tmp;
+ if(ata_tag_valid(ap->active_tag) || ap->sactive) {
+ u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
+ u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
+ u32 gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL);
+ u32 status = readw(mmio + NV_ADMA_STAT);
+ u8 cpb_count = readb(mmio + NV_ADMA_CPB_COUNT);
+ u8 next_cpb_idx = readb(mmio + NV_ADMA_NEXT_CPB_IDX);
+
+ ata_port_printk(ap, KERN_ERR, "EH in ADMA mode, notifier 0x%X "
+ "notifier_error 0x%X gen_ctl 0x%X status 0x%X "
+ "next cpb count 0x%X next cpb idx 0x%x\n",
+ notifier, notifier_error, gen_ctl, status,
+ cpb_count, next_cpb_idx);
+
+ for( i=0;i<NV_ADMA_MAX_CPBS;i++) {
+ struct nv_adma_cpb *cpb = &pp->cpb[i];
+ if( (ata_tag_valid(ap->active_tag) && i == ap->active_tag) ||
+ ap->sactive & (1 << i) )
+ ata_port_printk(ap, KERN_ERR,
+ "CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n",
+ i, cpb->ctl_flags, cpb->resp_flags);
+ }
+ }
+
/* Push us back into port register mode for error handling. */
nv_adma_register_mode(ap);
@@ -1460,10 +1460,10 @@ static void nv_adma_error_handler(struct ata_port *ap)
/* Reset channel */
tmp = readw(mmio + NV_ADMA_CTL);
writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
- readl( mmio + NV_ADMA_CTL ); /* flush posted write */
+ readw( mmio + NV_ADMA_CTL ); /* flush posted write */
udelay(1);
writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
- readl( mmio + NV_ADMA_CTL ); /* flush posted write */
+ readw( mmio + NV_ADMA_CTL ); /* flush posted write */
}
ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset,
@@ -1575,6 +1575,7 @@ static void nv_remove_one (struct pci_dev *pdev)
kfree(hpriv);
}
+#ifdef CONFIG_PM
static int nv_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
@@ -1622,6 +1623,7 @@ static int nv_pci_device_resume(struct pci_dev *pdev)
return 0;
}
+#endif
static void nv_ck804_host_stop(struct ata_host *host)
{
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index cf9ed8c3930..2339813ce9f 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -45,7 +45,7 @@
#include "sata_promise.h"
#define DRV_NAME "sata_promise"
-#define DRV_VERSION "1.05"
+#define DRV_VERSION "2.00"
enum {
@@ -218,6 +218,7 @@ static const struct ata_port_operations pdc_pata_ops = {
.freeze = pdc_freeze,
.thaw = pdc_thaw,
.error_handler = pdc_error_handler,
+ .post_internal_cmd = pdc_post_internal_cmd,
.data_xfer = ata_data_xfer,
.irq_handler = pdc_interrupt,
.irq_clear = pdc_irq_clear,
@@ -776,7 +777,8 @@ static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc)
return pdc_check_atapi_dma(qc);
}
-static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base)
+static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base,
+ void __iomem *scr_addr)
{
port->cmd_addr = base;
port->data_addr = base;
@@ -791,6 +793,7 @@ static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base)
port->status_addr = base + 0x1c;
port->altstatus_addr =
port->ctl_addr = base + 0x38;
+ port->scr_addr = scr_addr;
}
@@ -903,11 +906,8 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
base = probe_ent->iomap[PDC_MMIO_BAR];
- pdc_ata_setup_port(&probe_ent->port[0], base + 0x200);
- pdc_ata_setup_port(&probe_ent->port[1], base + 0x280);
-
- probe_ent->port[0].scr_addr = base + 0x400;
- probe_ent->port[1].scr_addr = base + 0x500;
+ pdc_ata_setup_port(&probe_ent->port[0], base + 0x200, base + 0x400);
+ pdc_ata_setup_port(&probe_ent->port[1], base + 0x280, base + 0x500);
/* notice 4-port boards */
switch (board_idx) {
@@ -916,12 +916,8 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
/* Fall through */
case board_20319:
probe_ent->n_ports = 4;
-
- pdc_ata_setup_port(&probe_ent->port[2], base + 0x300);
- pdc_ata_setup_port(&probe_ent->port[3], base + 0x380);
-
- probe_ent->port[2].scr_addr = base + 0x600;
- probe_ent->port[3].scr_addr = base + 0x700;
+ pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, base + 0x600);
+ pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, base + 0x700);
break;
case board_2057x:
hp->flags |= PDC_FLAG_GEN_II;
@@ -931,7 +927,7 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
tmp = readb(base + PDC_FLASH_CTL+1);
if (!(tmp & 0x80)) {
probe_ent->n_ports = 3;
- pdc_ata_setup_port(&probe_ent->port[2], base + 0x300);
+ pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL);
hp->port_flags[2] = ATA_FLAG_SLAVE_POSS;
printk(KERN_INFO DRV_NAME " PATA port found\n");
} else
@@ -941,12 +937,8 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
break;
case board_20619:
probe_ent->n_ports = 4;
-
- pdc_ata_setup_port(&probe_ent->port[2], base + 0x300);
- pdc_ata_setup_port(&probe_ent->port[3], base + 0x380);
-
- probe_ent->port[2].scr_addr = base + 0x600;
- probe_ent->port[3].scr_addr = base + 0x700;
+ pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL);
+ pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, NULL);
break;
default:
BUG();
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 6097d8f2a0c..8786b45f291 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -39,7 +39,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_qstor"
-#define DRV_VERSION "0.06"
+#define DRV_VERSION "0.07"
enum {
QS_MMIO_BAR = 4,
@@ -446,7 +446,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host)
if ((status & ATA_BUSY))
continue;
DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
- ap->id, qc->tf.protocol, status);
+ ap->print_id, qc->tf.protocol, status);
/* complete taskfile transaction */
pp->state = qs_state_idle;
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index dca3d3749f0..917b7ea4ef7 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -46,7 +46,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_sil"
-#define DRV_VERSION "2.0"
+#define DRV_VERSION "2.1"
enum {
SIL_MMIO_BAR = 5,
@@ -183,8 +183,10 @@ static struct scsi_host_template sil_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.suspend = ata_scsi_device_suspend,
.resume = ata_scsi_device_resume,
+#endif
};
static const struct ata_port_operations sil_ops = {
@@ -339,7 +341,7 @@ static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_re
break;
}
- return 0;
+ return NULL;
}
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
@@ -386,9 +388,15 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
goto freeze;
}
- if (unlikely(!qc || qc->tf.ctl & ATA_NIEN))
+ if (unlikely(!qc))
goto freeze;
+ if (unlikely(qc->tf.flags & ATA_TFLAG_POLLING)) {
+ /* this sometimes happens, just clear IRQ */
+ ata_chk_status(ap);
+ return;
+ }
+
/* Check whether we are expecting interrupt in this state */
switch (ap->hsm_task_state) {
case HSM_ST_FIRST:
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index e65e8d55da3..75d96159965 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -30,7 +30,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_sil24"
-#define DRV_VERSION "0.3"
+#define DRV_VERSION "0.8"
/*
* Port request block (PRB) 32 bytes
@@ -380,8 +380,10 @@ static struct scsi_host_template sil24_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
.suspend = ata_scsi_device_suspend,
.resume = ata_scsi_device_resume,
+#endif
};
static const struct ata_port_operations sil24_ops = {
@@ -647,7 +649,6 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
struct sil24_sge *sge)
{
struct scatterlist *sg;
- unsigned int idx = 0;
ata_for_each_sg(sg, qc) {
sge->addr = cpu_to_le64(sg_dma_address(sg));
@@ -656,9 +657,7 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
sge->flags = cpu_to_le32(SGE_TRM);
else
sge->flags = 0;
-
sge++;
- idx++;
}
}
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 49c9e2bd706..1879e0cd56a 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -40,9 +40,8 @@
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
-#include "libata.h"
+#include "sis.h"
-#undef DRV_NAME /* already defined in libata.h, for libata-core */
#define DRV_NAME "sata_sis"
#define DRV_VERSION "0.7"
@@ -310,7 +309,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
case 0x10:
ppi[1] = &sis_info133;
break;
-
+
case 0x30:
ppi[0] = &sis_info133;
break;
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index 4e428999420..b121195cc59 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -53,7 +53,7 @@
#endif /* CONFIG_PPC_OF */
#define DRV_NAME "sata_svw"
-#define DRV_VERSION "2.0"
+#define DRV_VERSION "2.1"
enum {
K2_FLAG_NO_ATAPI_DMA = (1 << 29),
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 0ebd77b080d..1a081c3a8c0 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -44,7 +44,7 @@
#include "sata_promise.h"
#define DRV_NAME "sata_sx4"
-#define DRV_VERSION "0.9"
+#define DRV_VERSION "0.10"
enum {
@@ -421,7 +421,7 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
- VPRINTK("ata%u: ENTER\n", ap->id);
+ VPRINTK("ata%u: ENTER\n", ap->print_id);
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -478,7 +478,7 @@ static void pdc20621_nodata_prep(struct ata_queued_cmd *qc)
unsigned int portno = ap->port_no;
unsigned int i;
- VPRINTK("ata%u: ENTER\n", ap->id);
+ VPRINTK("ata%u: ENTER\n", ap->print_id);
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -605,7 +605,7 @@ static void pdc20621_packet_start(struct ata_queued_cmd *qc)
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
- VPRINTK("ata%u: ENTER\n", ap->id);
+ VPRINTK("ata%u: ENTER\n", ap->print_id);
wmb(); /* flush PRD, pkt writes */
@@ -672,7 +672,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
/* step two - DMA from DIMM to host */
if (doing_hdma) {
- VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id,
+ VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->print_id,
readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
/* get drive status; clear intr; complete txn */
qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
@@ -683,7 +683,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
/* step one - exec ATA command */
else {
u8 seq = (u8) (port_no + 1 + 4);
- VPRINTK("ata%u: read ata, 0x%x 0x%x\n", ap->id,
+ VPRINTK("ata%u: read ata, 0x%x 0x%x\n", ap->print_id,
readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
/* submit hdma pkt */
@@ -698,7 +698,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
/* step one - DMA from host to DIMM */
if (doing_hdma) {
u8 seq = (u8) (port_no + 1);
- VPRINTK("ata%u: write hdma, 0x%x 0x%x\n", ap->id,
+ VPRINTK("ata%u: write hdma, 0x%x 0x%x\n", ap->print_id,
readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
/* submit ata pkt */
@@ -711,7 +711,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
/* step two - execute ATA command */
else {
- VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id,
+ VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->print_id,
readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
/* get drive status; clear intr; complete txn */
qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index 80131eec68f..d659ace80f4 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -36,7 +36,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_uli"
-#define DRV_VERSION "1.0"
+#define DRV_VERSION "1.1"
enum {
uli_5289 = 0,
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index baca6d79bb0..598e6a26a48 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -46,7 +46,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_via"
-#define DRV_VERSION "2.0"
+#define DRV_VERSION "2.1"
enum board_ids_enum {
vt6420,
@@ -60,7 +60,7 @@ enum {
SATA_PATA_SHARING = 0x49, /* PATA/SATA sharing func ctrl */
PATA_UDMA_TIMING = 0xB3, /* PATA timing for DMA/ cable detect */
PATA_PIO_TIMING = 0xAB, /* PATA timing register */
-
+
PORT0 = (1 << 1),
PORT1 = (1 << 0),
ALL_PORTS = PORT0 | PORT1,
@@ -151,7 +151,7 @@ static const struct ata_port_operations vt6420_sata_ops = {
static const struct ata_port_operations vt6421_pata_ops = {
.port_disable = ata_port_disable,
-
+
.set_piomode = vt6421_set_pio_mode,
.set_dmamode = vt6421_set_dma_mode,
@@ -185,7 +185,7 @@ static const struct ata_port_operations vt6421_pata_ops = {
static const struct ata_port_operations vt6421_sata_ops = {
.port_disable = ata_port_disable,
-
+
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -423,16 +423,21 @@ static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev)
{
struct ata_probe_ent *probe_ent;
struct ata_port_info *ppi[2];
- void __iomem * const *iomap;
+ void __iomem *bar5;
ppi[0] = ppi[1] = &vt6420_port_info;
probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
if (!probe_ent)
return NULL;
- iomap = pcim_iomap_table(pdev);
- probe_ent->port[0].scr_addr = svia_scr_addr(iomap[5], 0);
- probe_ent->port[1].scr_addr = svia_scr_addr(iomap[5], 1);
+ bar5 = pcim_iomap(pdev, 5, 0);
+ if (!bar5) {
+ dev_printk(KERN_ERR, &pdev->dev, "failed to iomap PCI BAR 5\n");
+ return NULL;
+ }
+
+ probe_ent->port[0].scr_addr = svia_scr_addr(bar5, 0);
+ probe_ent->port[1].scr_addr = svia_scr_addr(bar5, 1);
return probe_ent;
}
@@ -460,6 +465,13 @@ static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
probe_ent->mwdma_mask = 0x07;
probe_ent->udma_mask = 0x7f;
+ for (i = 0; i < 6; i++)
+ if (!pcim_iomap(pdev, i, 0)) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to iomap PCI BAR %d\n", i);
+ return NULL;
+ }
+
for (i = 0; i < N_PORTS; i++)
vt6421_init_addrs(probe_ent, pcim_iomap_table(pdev), i);
@@ -522,7 +534,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- rc = pcim_iomap_regions(pdev, 0x1f, DRV_NAME);
+ rc = pci_request_regions(pdev, DRV_NAME);
if (rc) {
pcim_pin_device(pdev);
return rc;
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index 2fd037bde09..170bad1b415 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -47,7 +47,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_vsc"
-#define DRV_VERSION "2.0"
+#define DRV_VERSION "2.1"
enum {
VSC_MMIO_BAR = 0,
@@ -98,10 +98,6 @@ enum {
VSC_SATA_INT_PHY_CHANGE),
};
-#define is_vsc_sata_int_err(port_idx, int_status) \
- (int_status & (VSC_SATA_INT_ERROR << (8 * port_idx)))
-
-
static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
if (sc_reg > SCR_CONTROL)
@@ -119,6 +115,28 @@ static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
}
+static void vsc_freeze(struct ata_port *ap)
+{
+ void __iomem *mask_addr;
+
+ mask_addr = ap->host->iomap[VSC_MMIO_BAR] +
+ VSC_SATA_INT_MASK_OFFSET + ap->port_no;
+
+ writeb(0, mask_addr);
+}
+
+
+static void vsc_thaw(struct ata_port *ap)
+{
+ void __iomem *mask_addr;
+
+ mask_addr = ap->host->iomap[VSC_MMIO_BAR] +
+ VSC_SATA_INT_MASK_OFFSET + ap->port_no;
+
+ writeb(0xff, mask_addr);
+}
+
+
static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl)
{
void __iomem *mask_addr;
@@ -203,6 +221,36 @@ static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
}
}
+static inline void vsc_error_intr(u8 port_status, struct ata_port *ap)
+{
+ if (port_status & (VSC_SATA_INT_PHY_CHANGE | VSC_SATA_INT_ERROR_M))
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
+}
+
+static void vsc_port_intr(u8 port_status, struct ata_port *ap)
+{
+ struct ata_queued_cmd *qc;
+ int handled = 0;
+
+ if (unlikely(port_status & VSC_SATA_INT_ERROR)) {
+ vsc_error_intr(port_status, ap);
+ return;
+ }
+
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc && likely(!(qc->tf.flags & ATA_TFLAG_POLLING)))
+ handled = ata_host_intr(ap, qc);
+
+ /* We received an interrupt during a polled command,
+ * or some other spurious condition. Interrupt reporting
+ * with this hardware is fairly reliable so it is safe to
+ * simply clear the interrupt
+ */
+ if (unlikely(!handled))
+ ata_chk_status(ap);
+}
/*
* vsc_sata_interrupt
@@ -214,59 +262,36 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance)
struct ata_host *host = dev_instance;
unsigned int i;
unsigned int handled = 0;
- u32 int_status;
-
- spin_lock(&host->lock);
+ u32 status;
- int_status = readl(host->iomap[VSC_MMIO_BAR] +
- VSC_SATA_INT_STAT_OFFSET);
+ status = readl(host->iomap[VSC_MMIO_BAR] + VSC_SATA_INT_STAT_OFFSET);
- for (i = 0; i < host->n_ports; i++) {
- if (int_status & ((u32) 0xFF << (8 * i))) {
- struct ata_port *ap;
+ if (unlikely(status == 0xffffffff || status == 0)) {
+ if (status)
+ dev_printk(KERN_ERR, host->dev,
+ ": IRQ status == 0xffffffff, "
+ "PCI fault or device removal?\n");
+ goto out;
+ }
- ap = host->ports[i];
+ spin_lock(&host->lock);
- if (is_vsc_sata_int_err(i, int_status)) {
- u32 err_status;
- printk(KERN_DEBUG "%s: ignoring interrupt(s)\n", __FUNCTION__);
- err_status = ap ? vsc_sata_scr_read(ap, SCR_ERROR) : 0;
- vsc_sata_scr_write(ap, SCR_ERROR, err_status);
- handled++;
- }
+ for (i = 0; i < host->n_ports; i++) {
+ u8 port_status = (status >> (8 * i)) & 0xff;
+ if (port_status) {
+ struct ata_port *ap = host->ports[i];
if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_queued_cmd *qc;
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
- handled += ata_host_intr(ap, qc);
- else if (is_vsc_sata_int_err(i, int_status)) {
- /*
- * On some chips (i.e. Intel 31244), an error
- * interrupt will sneak in at initialization
- * time (phy state changes). Clearing the SCR
- * error register is not required, but it prevents
- * the phy state change interrupts from recurring
- * later.
- */
- u32 err_status;
- err_status = vsc_sata_scr_read(ap, SCR_ERROR);
- printk(KERN_DEBUG "%s: clearing interrupt, "
- "status %x; sata err status %x\n",
- __FUNCTION__,
- int_status, err_status);
- vsc_sata_scr_write(ap, SCR_ERROR, err_status);
- /* Clear interrupt status */
- ata_chk_status(ap);
- handled++;
- }
- }
+ vsc_port_intr(port_status, ap);
+ handled++;
+ } else
+ dev_printk(KERN_ERR, host->dev,
+ ": interrupt from disabled port %d\n", i);
}
}
spin_unlock(&host->lock);
-
+out:
return IRQ_RETVAL(handled);
}
@@ -304,8 +329,8 @@ static const struct ata_port_operations vsc_sata_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_data_xfer,
- .freeze = ata_bmdma_freeze,
- .thaw = ata_bmdma_thaw,
+ .freeze = vsc_freeze,
+ .thaw = vsc_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = vsc_sata_interrupt,
diff --git a/drivers/ata/sis.h b/drivers/ata/sis.h
new file mode 100644
index 00000000000..231da8fc220
--- /dev/null
+++ b/drivers/ata/sis.h
@@ -0,0 +1,5 @@
+
+struct ata_port_info;
+
+/* pata_sis.c */
+extern struct ata_port_info sis_info133;
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 1417e5cd4c6..d5968128be2 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -840,48 +840,6 @@ void class_device_destroy(struct class *cls, dev_t devt)
class_device_unregister(class_dev);
}
-int class_device_rename(struct class_device *class_dev, char *new_name)
-{
- int error = 0;
- char *old_class_name = NULL, *new_class_name = NULL;
-
- class_dev = class_device_get(class_dev);
- if (!class_dev)
- return -EINVAL;
-
- pr_debug("CLASS: renaming '%s' to '%s'\n", class_dev->class_id,
- new_name);
-
-#ifdef CONFIG_SYSFS_DEPRECATED
- if (class_dev->dev)
- old_class_name = make_class_name(class_dev->class->name,
- &class_dev->kobj);
-#endif
-
- strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN);
-
- error = kobject_rename(&class_dev->kobj, new_name);
-
-#ifdef CONFIG_SYSFS_DEPRECATED
- if (class_dev->dev) {
- new_class_name = make_class_name(class_dev->class->name,
- &class_dev->kobj);
- if (new_class_name)
- sysfs_create_link(&class_dev->dev->kobj,
- &class_dev->kobj, new_class_name);
- if (old_class_name)
- sysfs_remove_link(&class_dev->dev->kobj,
- old_class_name);
- }
-#endif
- class_device_put(class_dev);
-
- kfree(old_class_name);
- kfree(new_class_name);
-
- return error;
-}
-
struct class_device * class_device_get(struct class_device *class_dev)
{
if (class_dev)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index d04fd33dcd9..89ebe368272 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -637,12 +637,41 @@ int device_add(struct device *dev)
BUS_NOTIFY_DEL_DEVICE, dev);
device_remove_groups(dev);
GroupError:
- device_remove_attrs(dev);
+ device_remove_attrs(dev);
AttrsError:
if (dev->devt_attr) {
device_remove_file(dev, dev->devt_attr);
kfree(dev->devt_attr);
}
+
+ if (dev->class) {
+ sysfs_remove_link(&dev->kobj, "subsystem");
+ /* If this is not a "fake" compatible device, remove the
+ * symlink from the class to the device. */
+ if (dev->kobj.parent != &dev->class->subsys.kset.kobj)
+ sysfs_remove_link(&dev->class->subsys.kset.kobj,
+ dev->bus_id);
+#ifdef CONFIG_SYSFS_DEPRECATED
+ if (parent) {
+ char *class_name = make_class_name(dev->class->name,
+ &dev->kobj);
+ if (class_name)
+ sysfs_remove_link(&dev->parent->kobj,
+ class_name);
+ kfree(class_name);
+ sysfs_remove_link(&dev->kobj, "device");
+ }
+#endif
+
+ down(&dev->class->sem);
+ /* notify any interfaces that the device is now gone */
+ list_for_each_entry(class_intf, &dev->class->interfaces, node)
+ if (class_intf->remove_dev)
+ class_intf->remove_dev(dev, class_intf);
+ /* remove the device from the class list */
+ list_del_init(&dev->node);
+ up(&dev->class->sem);
+ }
ueventattrError:
device_remove_file(dev, &dev->uevent_attr);
attrError:
@@ -758,6 +787,13 @@ void device_del(struct device * dev)
device_remove_attrs(dev);
bus_remove_device(dev);
+ /*
+ * Some platform devices are driven without driver attached
+ * and managed resources may have been acquired. Make sure
+ * all resources are released.
+ */
+ devres_release_all(dev);
+
/* Notify the platform of the removal, in case they
* need to do anything...
*/
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index cacb1c816e3..17ee97f3a99 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -406,22 +406,6 @@ config BLK_DEV_RAM_BLOCKSIZE
setups function - apparently needed by the rd_load_image routine
that supposes the filesystem in the image uses a 1024 blocksize.
-config BLK_DEV_INITRD
- bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support"
- depends on BROKEN || !FRV
- help
- The initial RAM filesystem is a ramfs which is loaded by the
- boot loader (loadlin or lilo) and that is mounted as root
- before the normal boot procedure. It is typically used to
- load modules needed to mount the "real" root file system,
- etc. See <file:Documentation/initrd.txt> for details.
-
- If RAM disk support (BLK_DEV_RAM) is also included, this
- also enables initial RAM disk (initrd) support and adds
- 15 Kbytes (more on some other architectures) to the kernel size.
-
- If unsure say Y.
-
config CDROM_PKTCDVD
tristate "Packet writing on CD/DVD media"
depends on !UML
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index bb022ed4a86..8d17d8df366 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -530,7 +530,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
u16 aoemajor;
hin = (struct aoe_hdr *) skb->mac.raw;
- aoemajor = be16_to_cpu(hin->major);
+ aoemajor = be16_to_cpu(get_unaligned(&hin->major));
d = aoedev_by_aoeaddr(aoemajor, hin->minor);
if (d == NULL) {
snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response "
@@ -542,7 +542,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
spin_lock_irqsave(&d->lock, flags);
- n = be32_to_cpu(hin->tag);
+ n = be32_to_cpu(get_unaligned(&hin->tag));
f = getframe(d, n);
if (f == NULL) {
calc_rttavg(d, -tsince(n));
@@ -550,9 +550,9 @@ aoecmd_ata_rsp(struct sk_buff *skb)
snprintf(ebuf, sizeof ebuf,
"%15s e%d.%d tag=%08x@%08lx\n",
"unexpected rsp",
- be16_to_cpu(hin->major),
+ be16_to_cpu(get_unaligned(&hin->major)),
hin->minor,
- be32_to_cpu(hin->tag),
+ be32_to_cpu(get_unaligned(&hin->tag)),
jiffies);
aoechr_error(ebuf);
return;
@@ -631,7 +631,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
printk(KERN_INFO
"aoe: unrecognized ata command %2.2Xh for %d.%d\n",
ahout->cmdstat,
- be16_to_cpu(hin->major),
+ be16_to_cpu(get_unaligned(&hin->major)),
hin->minor);
}
}
@@ -733,7 +733,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
* Enough people have their dip switches set backwards to
* warrant a loud message for this special case.
*/
- aoemajor = be16_to_cpu(h->major);
+ aoemajor = be16_to_cpu(get_unaligned(&h->major));
if (aoemajor == 0xfff) {
printk(KERN_ERR "aoe: Warning: shelf address is all ones. "
"Check shelf dip switches.\n");
diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
index 9626e0f5da9..aab6d91a2c2 100644
--- a/drivers/block/aoe/aoenet.c
+++ b/drivers/block/aoe/aoenet.c
@@ -8,6 +8,7 @@
#include <linux/blkdev.h>
#include <linux/netdevice.h>
#include <linux/moduleparam.h>
+#include <asm/unaligned.h>
#include "aoe.h"
#define NECODES 5
@@ -123,7 +124,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt,
skb_push(skb, ETH_HLEN); /* (1) */
h = (struct aoe_hdr *) skb->mac.raw;
- n = be32_to_cpu(h->tag);
+ n = be32_to_cpu(get_unaligned(&h->tag));
if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31))
goto exit;
@@ -133,7 +134,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt,
n = 0;
if (net_ratelimit())
printk(KERN_ERR "aoe: error packet from %d.%d; ecode=%d '%s'\n",
- be16_to_cpu(h->major), h->minor,
+ be16_to_cpu(get_unaligned(&h->major)), h->minor,
h->err, aoe_errlist[n]);
goto exit;
}
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 05dfe357527..0c716ee905d 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -1291,13 +1291,19 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
if (inq_buff == NULL)
goto mem_msg;
+ /* testing to see if 16-byte CDBs are already being used */
+ if (h->cciss_read == CCISS_READ_16) {
+ cciss_read_capacity_16(h->ctlr, drv_index, 1,
+ &total_size, &block_size);
+ goto geo_inq;
+ }
+
cciss_read_capacity(ctlr, drv_index, 1,
&total_size, &block_size);
- /* total size = last LBA + 1 */
- /* FFFFFFFF + 1 = 0, cannot have a logical volume of size 0 */
- /* so we assume this volume this must be >2TB in size */
- if (total_size == (__u32) 0) {
+ /* if read_capacity returns all F's this volume is >2TB in size */
+ /* so we switch to 16-byte CDB's for all read/write ops */
+ if (total_size == 0xFFFFFFFFULL) {
cciss_read_capacity_16(ctlr, drv_index, 1,
&total_size, &block_size);
h->cciss_read = CCISS_READ_16;
@@ -1306,6 +1312,7 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
h->cciss_read = CCISS_READ_10;
h->cciss_write = CCISS_WRITE_10;
}
+geo_inq:
cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size,
inq_buff, &h->drv[drv_index]);
@@ -1917,13 +1924,14 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
drv->raid_level = inq_buff->data_byte[8];
}
drv->block_size = block_size;
- drv->nr_blocks = total_size;
+ drv->nr_blocks = total_size + 1;
t = drv->heads * drv->sectors;
if (t > 1) {
- unsigned rem = sector_div(total_size, t);
+ sector_t real_size = total_size + 1;
+ unsigned long rem = sector_div(real_size, t);
if (rem)
- total_size++;
- drv->cylinders = total_size;
+ real_size++;
+ drv->cylinders = real_size;
}
} else { /* Get geometry failed */
printk(KERN_WARNING "cciss: reading geometry failed\n");
@@ -1953,16 +1961,16 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size,
ctlr, buf, sizeof(ReadCapdata_struct),
1, logvol, 0, NULL, TYPE_CMD);
if (return_code == IO_OK) {
- *total_size = be32_to_cpu(*(__u32 *) buf->total_size)+1;
+ *total_size = be32_to_cpu(*(__u32 *) buf->total_size);
*block_size = be32_to_cpu(*(__u32 *) buf->block_size);
} else { /* read capacity command failed */
printk(KERN_WARNING "cciss: read capacity failed\n");
*total_size = 0;
*block_size = BLOCK_SIZE;
}
- if (*total_size != (__u32) 0)
+ if (*total_size != 0)
printk(KERN_INFO " blocks= %llu block_size= %d\n",
- (unsigned long long)*total_size, *block_size);
+ (unsigned long long)*total_size+1, *block_size);
kfree(buf);
return;
}
@@ -1989,7 +1997,7 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size,
1, logvol, 0, NULL, TYPE_CMD);
}
if (return_code == IO_OK) {
- *total_size = be64_to_cpu(*(__u64 *) buf->total_size)+1;
+ *total_size = be64_to_cpu(*(__u64 *) buf->total_size);
*block_size = be32_to_cpu(*(__u32 *) buf->block_size);
} else { /* read capacity command failed */
printk(KERN_WARNING "cciss: read capacity failed\n");
@@ -1997,7 +2005,7 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size,
*block_size = BLOCK_SIZE;
}
printk(KERN_INFO " blocks= %llu block_size= %d\n",
- (unsigned long long)*total_size, *block_size);
+ (unsigned long long)*total_size+1, *block_size);
kfree(buf);
return;
}
@@ -3119,8 +3127,9 @@ static void cciss_getgeometry(int cntl_num)
}
cciss_read_capacity(cntl_num, i, 0, &total_size, &block_size);
- /* total_size = last LBA + 1 */
- if(total_size == (__u32) 0) {
+ /* If read_capacity returns all F's the logical is >2TB */
+ /* so we switch to 16-byte CDBs for all read/write ops */
+ if(total_size == 0xFFFFFFFFULL) {
cciss_read_capacity_16(cntl_num, i, 0,
&total_size, &block_size);
hba[cntl_num]->cciss_read = CCISS_READ_16;
@@ -3395,7 +3404,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
return -1;
}
-static void __devexit cciss_remove_one(struct pci_dev *pdev)
+static void cciss_remove_one(struct pci_dev *pdev)
{
ctlr_info_t *tmp_ptr;
int i, j;
@@ -3419,9 +3428,10 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
memset(flush_buf, 0, 4);
return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL,
TYPE_CMD);
- if (return_code != IO_OK) {
- printk(KERN_WARNING "Error Flushing cache on controller %d\n",
- i);
+ if (return_code == IO_OK) {
+ printk(KERN_INFO "Completed flushing cache on controller %d\n", i);
+ } else {
+ printk(KERN_WARNING "Error flushing cache on controller %d\n", i);
}
free_irq(hba[i]->intr[2], hba[i]);
@@ -3472,6 +3482,7 @@ static struct pci_driver cciss_pci_driver = {
.probe = cciss_init_one,
.remove = __devexit_p(cciss_remove_one),
.id_table = cciss_pci_device_id, /* id_table */
+ .shutdown = cciss_remove_one,
};
/*
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index dff3766f117..5872036e8ae 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -1179,8 +1179,10 @@ static int __init mm_init(void)
return -ENOMEM;
err = major_nr = register_blkdev(0, "umem");
- if (err < 0)
+ if (err < 0) {
+ pci_unregister_driver(&mm_pci_driver);
return -EIO;
+ }
for (i = 0; i < num_cards; i++) {
mm_gendisk[i] = alloc_disk(1 << MM_SHIFT);
@@ -1207,6 +1209,7 @@ static int __init mm_init(void)
return 0;
out:
+ pci_unregister_driver(&mm_pci_driver);
unregister_blkdev(major_nr, "umem");
while (i--)
put_disk(mm_gendisk[i]);
diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c
index 9256985cbe3..8919ccf8274 100644
--- a/drivers/bluetooth/bcm203x.c
+++ b/drivers/bluetooth/bcm203x.c
@@ -307,3 +307,5 @@ MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("BCM2033-MD.hex");
+MODULE_FIRMWARE("BCM2033-FW.bin");
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
index 27cceb6f565..4c766f36d88 100644
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -801,3 +801,4 @@ MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("bfubase.frm");
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 34e5555cb91..18b0f3992c5 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -63,6 +63,7 @@
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>");
MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card");
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("BT3CPCC.bin");
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index dc13ebacedf..44cd7b2ddf0 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -376,6 +376,25 @@ static int send_request(struct request *req)
return 0;
}
+static void viocd_end_request(struct request *req, int uptodate)
+{
+ int nsectors = req->hard_nr_sectors;
+
+ /*
+ * Make sure it's fully ended, and ensure that we process
+ * at least one sector.
+ */
+ if (blk_pc_request(req))
+ nsectors = (req->data_len + 511) >> 9;
+ if (!nsectors)
+ nsectors = 1;
+
+ if (end_that_request_first(req, uptodate, nsectors))
+ BUG();
+ add_disk_randomness(req->rq_disk);
+ blkdev_dequeue_request(req);
+ end_that_request_last(req, uptodate);
+}
static int rwreq;
@@ -385,11 +404,11 @@ static void do_viocd_request(request_queue_t *q)
while ((rwreq == 0) && ((req = elv_next_request(q)) != NULL)) {
if (!blk_fs_request(req))
- end_request(req, 0);
+ viocd_end_request(req, 0);
else if (send_request(req) < 0) {
printk(VIOCD_KERN_WARNING
"unable to send message to OS/400!");
- end_request(req, 0);
+ viocd_end_request(req, 0);
} else
rwreq++;
}
@@ -601,9 +620,9 @@ return_complete:
"with rc %d:0x%04X: %s\n",
req, event->xRc,
bevent->sub_result, err->msg);
- end_request(req, 0);
+ viocd_end_request(req, 0);
} else
- end_request(req, 1);
+ viocd_end_request(req, 1);
/* restart handling of incoming requests */
spin_unlock_irqrestore(&viocd_reqlock, flags);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index d0a6dc53213..3429ece4ef9 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -1026,16 +1026,17 @@ config MMTIMER
source "drivers/char/tpm/Kconfig"
config TELCLOCK
- tristate "Telecom clock driver for MPBL0010 ATCA SBC"
+ tristate "Telecom clock driver for ATCA SBC"
depends on EXPERIMENTAL && X86
default n
help
- The telecom clock device is specific to the MPBL0010 ATCA computer and
- allows direct userspace access to the configuration of the telecom clock
- configuration settings. This device is used for hardware synchronization
- across the ATCA backplane fabric. Upon loading, the driver exports a
- sysfs directory, /sys/devices/platform/telco_clock, with a number of
- files for controlling the behavior of this hardware.
+ The telecom clock device is specific to the MPCBL0010 and MPCBL0050
+ ATCA computers and allows direct userspace access to the
+ configuration of the telecom clock configuration settings. This
+ device is used for hardware synchronization across the ATCA backplane
+ fabric. Upon loading, the driver exports a sysfs directory,
+ /sys/devices/platform/telco_clock, with a number of files for
+ controlling the behavior of this hardware.
endmenu
diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile
index a0d04a23dac..627f542827c 100644
--- a/drivers/char/agp/Makefile
+++ b/drivers/char/agp/Makefile
@@ -1,7 +1,8 @@
agpgart-y := backend.o frontend.o generic.o isoch.o
+agpgart-$(CONFIG_COMPAT) += compat_ioctl.o
+
obj-$(CONFIG_AGP) += agpgart.o
-obj-$(CONFIG_COMPAT) += compat_ioctl.o
obj-$(CONFIG_AGP_ALI) += ali-agp.o
obj-$(CONFIG_AGP_ATI) += ati-agp.o
obj-$(CONFIG_AGP_AMD) += amd-k7-agp.o
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 9bd68d9f0f5..fdbca25a394 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -93,12 +93,12 @@ struct aper_size_info_fixed {
struct agp_bridge_driver {
struct module *owner;
- void *aperture_sizes;
+ const void *aperture_sizes;
int num_aperture_sizes;
enum aper_size_type size_type;
int cant_use_aperture;
int needs_scratch_page;
- struct gatt_mask *masks;
+ const struct gatt_mask *masks;
int (*fetch_size)(void);
int (*configure)(void);
void (*agp_enable)(struct agp_bridge_data *, u32);
@@ -119,7 +119,7 @@ struct agp_bridge_driver {
struct agp_bridge_data {
const struct agp_version *version;
- struct agp_bridge_driver *driver;
+ const struct agp_bridge_driver *driver;
struct vm_operations_struct *vm_ops;
void *previous_size;
void *current_size;
@@ -290,7 +290,7 @@ void agp3_generic_cleanup(void);
/* aperture sizes have been standardised since v3 */
#define AGP_GENERIC_SIZES_ENTRIES 11
-extern struct aper_size_info_16 agp3_generic_sizes[];
+extern const struct aper_size_info_16 agp3_generic_sizes[];
#define virt_to_gart(x) (phys_to_gart(virt_to_phys(x)))
#define gart_to_virt(x) (phys_to_virt(gart_to_phys(x)))
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
index 98177a93076..5b684fddcc0 100644
--- a/drivers/char/agp/ali-agp.c
+++ b/drivers/char/agp/ali-agp.c
@@ -182,7 +182,7 @@ static void m1541_destroy_page(void * addr)
/* Setup function */
-static struct aper_size_info_32 ali_generic_sizes[7] =
+static const struct aper_size_info_32 ali_generic_sizes[7] =
{
{256, 65536, 6, 10},
{128, 32768, 5, 9},
@@ -193,7 +193,7 @@ static struct aper_size_info_32 ali_generic_sizes[7] =
{4, 1024, 0, 3}
};
-static struct agp_bridge_driver ali_generic_bridge = {
+static const struct agp_bridge_driver ali_generic_bridge = {
.owner = THIS_MODULE,
.aperture_sizes = ali_generic_sizes,
.size_type = U32_APER_SIZE,
@@ -217,7 +217,7 @@ static struct agp_bridge_driver ali_generic_bridge = {
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver ali_m1541_bridge = {
+static const struct agp_bridge_driver ali_m1541_bridge = {
.owner = THIS_MODULE,
.aperture_sizes = ali_generic_sizes,
.size_type = U32_APER_SIZE,
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index 3d8d448bf39..e6c534e6284 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -344,7 +344,7 @@ static int amd_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
return 0;
}
-static struct aper_size_info_lvl2 amd_irongate_sizes[7] =
+static const struct aper_size_info_lvl2 amd_irongate_sizes[7] =
{
{2048, 524288, 0x0000000c},
{1024, 262144, 0x0000000a},
@@ -355,12 +355,12 @@ static struct aper_size_info_lvl2 amd_irongate_sizes[7] =
{32, 8192, 0x00000000}
};
-static struct gatt_mask amd_irongate_masks[] =
+static const struct gatt_mask amd_irongate_masks[] =
{
{.mask = 1, .type = 0}
};
-static struct agp_bridge_driver amd_irongate_driver = {
+static const struct agp_bridge_driver amd_irongate_driver = {
.owner = THIS_MODULE,
.aperture_sizes = amd_irongate_sizes,
.size_type = LVL2_APER_SIZE,
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 636d984ed4a..485720486d6 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -192,7 +192,7 @@ static u64 amd64_configure (struct pci_dev *hammer, u64 gatt_table)
}
-static struct aper_size_info_32 amd_8151_sizes[7] =
+static const struct aper_size_info_32 amd_8151_sizes[7] =
{
{2048, 524288, 9, 0x00000000 }, /* 0 0 0 0 0 0 */
{1024, 262144, 8, 0x00000400 }, /* 1 0 0 0 0 0 */
@@ -232,7 +232,7 @@ static void amd64_cleanup(void)
}
-static struct agp_bridge_driver amd_8151_driver = {
+static const struct agp_bridge_driver amd_8151_driver = {
.owner = THIS_MODULE,
.aperture_sizes = amd_8151_sizes,
.size_type = U32_APER_SIZE,
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
index 77c9ad68fba..780e59e588a 100644
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -24,7 +24,7 @@
#define ATI_GART_CACHE_ENTRY_CNTRL 0x10
-static struct aper_size_info_lvl2 ati_generic_sizes[7] =
+static const struct aper_size_info_lvl2 ati_generic_sizes[7] =
{
{2048, 524288, 0x0000000c},
{1024, 262144, 0x0000000a},
@@ -410,7 +410,7 @@ static int ati_free_gatt_table(struct agp_bridge_data *bridge)
return 0;
}
-static struct agp_bridge_driver ati_generic_bridge = {
+static const struct agp_bridge_driver ati_generic_bridge = {
.owner = THIS_MODULE,
.aperture_sizes = ati_generic_sizes,
.size_type = LVL2_APER_SIZE,
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c
index 658cb1a72d2..df8da726285 100644
--- a/drivers/char/agp/efficeon-agp.c
+++ b/drivers/char/agp/efficeon-agp.c
@@ -59,7 +59,7 @@ static struct _efficeon_private {
unsigned long l1_table[EFFICEON_L1_SIZE];
} efficeon_private;
-static struct gatt_mask efficeon_generic_masks[] =
+static const struct gatt_mask efficeon_generic_masks[] =
{
{.mask = 0x00000001, .type = 0}
};
@@ -70,7 +70,7 @@ static inline unsigned long efficeon_mask_memory(unsigned long addr)
return addr | 0x00000001;
}
-static struct aper_size_info_lvl2 efficeon_generic_sizes[4] =
+static const struct aper_size_info_lvl2 efficeon_generic_sizes[4] =
{
{256, 65536, 0},
{128, 32768, 32},
@@ -309,7 +309,7 @@ static int efficeon_remove_memory(struct agp_memory * mem, off_t pg_start, int t
}
-static struct agp_bridge_driver efficeon_driver = {
+static const struct agp_bridge_driver efficeon_driver = {
.owner = THIS_MODULE,
.aperture_sizes = efficeon_generic_sizes,
.size_type = LVL2_APER_SIZE,
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 7923337c3d2..f902d71947b 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -1340,7 +1340,7 @@ void agp3_generic_cleanup(void)
}
EXPORT_SYMBOL(agp3_generic_cleanup);
-struct aper_size_info_16 agp3_generic_sizes[AGP_GENERIC_SIZES_ENTRIES] =
+const struct aper_size_info_16 agp3_generic_sizes[AGP_GENERIC_SIZES_ENTRIES] =
{
{4096, 1048576, 10,0x000},
{2048, 524288, 9, 0x800},
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
index 847deabf7f9..bcdb149c817 100644
--- a/drivers/char/agp/hp-agp.c
+++ b/drivers/char/agp/hp-agp.c
@@ -419,7 +419,7 @@ hp_zx1_enable (struct agp_bridge_data *bridge, u32 mode)
agp_device_command(command, (mode & AGP8X_MODE) != 0);
}
-struct agp_bridge_driver hp_zx1_driver = {
+const struct agp_bridge_driver hp_zx1_driver = {
.owner = THIS_MODULE,
.size_type = FIXED_APER_SIZE,
.configure = hp_zx1_configure,
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index 3e7618653ab..53354bf83af 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -78,7 +78,7 @@ static struct {
} *lp_desc;
} i460;
-static struct aper_size_info_8 i460_sizes[3] =
+static const struct aper_size_info_8 i460_sizes[3] =
{
/*
* The 32GB aperture is only available with a 4M GART page size. Due to the
@@ -550,7 +550,7 @@ static unsigned long i460_mask_memory (struct agp_bridge_data *bridge,
| (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xfffff000) >> 12);
}
-struct agp_bridge_driver intel_i460_driver = {
+const struct agp_bridge_driver intel_i460_driver = {
.owner = THIS_MODULE,
.aperture_sizes = i460_sizes,
.size_type = U8_APER_SIZE,
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 06b0bb6d982..e542a628f1c 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -63,7 +63,7 @@ extern int agp_memory_reserved;
#define INTEL_I7505_AGPCTRL 0x70
#define INTEL_I7505_MCHCFG 0x50
-static struct aper_size_info_fixed intel_i810_sizes[] =
+static const struct aper_size_info_fixed intel_i810_sizes[] =
{
{64, 16384, 4},
/* The 32M mode still requires a 64k gatt */
@@ -1365,18 +1365,18 @@ static int intel_7505_configure(void)
}
/* Setup function */
-static struct gatt_mask intel_generic_masks[] =
+static const struct gatt_mask intel_generic_masks[] =
{
{.mask = 0x00000017, .type = 0}
};
-static struct aper_size_info_8 intel_815_sizes[2] =
+static const struct aper_size_info_8 intel_815_sizes[2] =
{
{64, 16384, 4, 0},
{32, 8192, 3, 8},
};
-static struct aper_size_info_8 intel_8xx_sizes[7] =
+static const struct aper_size_info_8 intel_8xx_sizes[7] =
{
{256, 65536, 6, 0},
{128, 32768, 5, 32},
@@ -1387,7 +1387,7 @@ static struct aper_size_info_8 intel_8xx_sizes[7] =
{4, 1024, 0, 63}
};
-static struct aper_size_info_16 intel_generic_sizes[7] =
+static const struct aper_size_info_16 intel_generic_sizes[7] =
{
{256, 65536, 6, 0},
{128, 32768, 5, 32},
@@ -1398,7 +1398,7 @@ static struct aper_size_info_16 intel_generic_sizes[7] =
{4, 1024, 0, 63}
};
-static struct aper_size_info_8 intel_830mp_sizes[4] =
+static const struct aper_size_info_8 intel_830mp_sizes[4] =
{
{256, 65536, 6, 0},
{128, 32768, 5, 32},
@@ -1406,7 +1406,7 @@ static struct aper_size_info_8 intel_830mp_sizes[4] =
{32, 8192, 3, 56}
};
-static struct agp_bridge_driver intel_generic_driver = {
+static const struct agp_bridge_driver intel_generic_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_generic_sizes,
.size_type = U16_APER_SIZE,
@@ -1430,7 +1430,7 @@ static struct agp_bridge_driver intel_generic_driver = {
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_810_driver = {
+static const struct agp_bridge_driver intel_810_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_i810_sizes,
.size_type = FIXED_APER_SIZE,
@@ -1455,7 +1455,7 @@ static struct agp_bridge_driver intel_810_driver = {
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_815_driver = {
+static const struct agp_bridge_driver intel_815_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_815_sizes,
.size_type = U8_APER_SIZE,
@@ -1479,7 +1479,7 @@ static struct agp_bridge_driver intel_815_driver = {
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_830_driver = {
+static const struct agp_bridge_driver intel_830_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_i830_sizes,
.size_type = FIXED_APER_SIZE,
@@ -1504,7 +1504,7 @@ static struct agp_bridge_driver intel_830_driver = {
.agp_type_to_mask_type = intel_i830_type_to_mask_type,
};
-static struct agp_bridge_driver intel_820_driver = {
+static const struct agp_bridge_driver intel_820_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_8xx_sizes,
.size_type = U8_APER_SIZE,
@@ -1528,7 +1528,7 @@ static struct agp_bridge_driver intel_820_driver = {
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_830mp_driver = {
+static const struct agp_bridge_driver intel_830mp_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_830mp_sizes,
.size_type = U8_APER_SIZE,
@@ -1552,7 +1552,7 @@ static struct agp_bridge_driver intel_830mp_driver = {
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_840_driver = {
+static const struct agp_bridge_driver intel_840_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_8xx_sizes,
.size_type = U8_APER_SIZE,
@@ -1576,7 +1576,7 @@ static struct agp_bridge_driver intel_840_driver = {
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_845_driver = {
+static const struct agp_bridge_driver intel_845_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_8xx_sizes,
.size_type = U8_APER_SIZE,
@@ -1600,7 +1600,7 @@ static struct agp_bridge_driver intel_845_driver = {
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_850_driver = {
+static const struct agp_bridge_driver intel_850_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_8xx_sizes,
.size_type = U8_APER_SIZE,
@@ -1624,7 +1624,7 @@ static struct agp_bridge_driver intel_850_driver = {
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_860_driver = {
+static const struct agp_bridge_driver intel_860_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_8xx_sizes,
.size_type = U8_APER_SIZE,
@@ -1648,7 +1648,7 @@ static struct agp_bridge_driver intel_860_driver = {
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_915_driver = {
+static const struct agp_bridge_driver intel_915_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_i830_sizes,
.size_type = FIXED_APER_SIZE,
@@ -1673,7 +1673,7 @@ static struct agp_bridge_driver intel_915_driver = {
.agp_type_to_mask_type = intel_i830_type_to_mask_type,
};
-static struct agp_bridge_driver intel_i965_driver = {
+static const struct agp_bridge_driver intel_i965_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_i830_sizes,
.size_type = FIXED_APER_SIZE,
@@ -1698,7 +1698,7 @@ static struct agp_bridge_driver intel_i965_driver = {
.agp_type_to_mask_type = intel_i830_type_to_mask_type,
};
-static struct agp_bridge_driver intel_7505_driver = {
+static const struct agp_bridge_driver intel_7505_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_8xx_sizes,
.size_type = U8_APER_SIZE,
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index 2563286b2fc..0c9dab557c9 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -272,7 +272,7 @@ static void nvidia_tlbflush(struct agp_memory *mem)
}
-static struct aper_size_info_8 nvidia_generic_sizes[5] =
+static const struct aper_size_info_8 nvidia_generic_sizes[5] =
{
{512, 131072, 7, 0},
{256, 65536, 6, 8},
@@ -283,13 +283,13 @@ static struct aper_size_info_8 nvidia_generic_sizes[5] =
};
-static struct gatt_mask nvidia_generic_masks[] =
+static const struct gatt_mask nvidia_generic_masks[] =
{
{ .mask = 1, .type = 0}
};
-static struct agp_bridge_driver nvidia_driver = {
+static const struct agp_bridge_driver nvidia_driver = {
.owner = THIS_MODULE,
.aperture_sizes = nvidia_generic_sizes,
.size_type = U8_APER_SIZE,
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
index b7b4590673a..3d83b461cca 100644
--- a/drivers/char/agp/parisc-agp.c
+++ b/drivers/char/agp/parisc-agp.c
@@ -210,7 +210,7 @@ parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode)
agp_device_command(command, (mode & AGP8X_MODE) != 0);
}
-struct agp_bridge_driver parisc_agp_driver = {
+static const struct agp_bridge_driver parisc_agp_driver = {
.owner = THIS_MODULE,
.size_type = FIXED_APER_SIZE,
.configure = parisc_agp_configure,
@@ -236,7 +236,7 @@ static int __init
agp_ioc_init(void __iomem *ioc_regs)
{
struct _parisc_agp_info *info = &parisc_agp_info;
- u64 *iova_base, *io_pdir, io_tlb_ps;
+ u64 iova_base, *io_pdir, io_tlb_ps;
int io_tlb_shift;
printk(KERN_INFO DRVPFX "IO PDIR shared with sba_iommu\n");
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
index 92d1dc45b9b..ee8f50edde1 100644
--- a/drivers/char/agp/sgi-agp.c
+++ b/drivers/char/agp/sgi-agp.c
@@ -247,7 +247,7 @@ static struct agp_bridge_data *sgi_tioca_find_bridge(struct pci_dev *pdev)
return bridge;
}
-struct agp_bridge_driver sgi_tioca_driver = {
+const struct agp_bridge_driver sgi_tioca_driver = {
.owner = THIS_MODULE,
.size_type = U16_APER_SIZE,
.configure = sgi_tioca_configure,
diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c
index 60342b70815..125f4282d95 100644
--- a/drivers/char/agp/sis-agp.c
+++ b/drivers/char/agp/sis-agp.c
@@ -108,7 +108,7 @@ static void sis_delayed_enable(struct agp_bridge_data *bridge, u32 mode)
}
}
-static struct aper_size_info_8 sis_generic_sizes[7] =
+static const struct aper_size_info_8 sis_generic_sizes[7] =
{
{256, 65536, 6, 99},
{128, 32768, 5, 83},
diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
index 9f5ae7714f8..55212a3811f 100644
--- a/drivers/char/agp/sworks-agp.c
+++ b/drivers/char/agp/sworks-agp.c
@@ -385,12 +385,12 @@ static int serverworks_remove_memory(struct agp_memory *mem, off_t pg_start,
return 0;
}
-static struct gatt_mask serverworks_masks[] =
+static const struct gatt_mask serverworks_masks[] =
{
{.mask = 1, .type = 0}
};
-static struct aper_size_info_lvl2 serverworks_sizes[7] =
+static const struct aper_size_info_lvl2 serverworks_sizes[7] =
{
{2048, 524288, 0x80000000},
{1024, 262144, 0xc0000000},
@@ -423,7 +423,7 @@ static void serverworks_agp_enable(struct agp_bridge_data *bridge, u32 mode)
agp_device_command(command, 0);
}
-static struct agp_bridge_driver sworks_driver = {
+static const struct agp_bridge_driver sworks_driver = {
.owner = THIS_MODULE,
.aperture_sizes = serverworks_sizes,
.size_type = LVL2_APER_SIZE,
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index 6c45702e542..91b062126a6 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -460,7 +460,7 @@ void null_cache_flush(void)
/* Setup function */
-static struct aper_size_info_32 uninorth_sizes[7] =
+static const struct aper_size_info_32 uninorth_sizes[7] =
{
#if 0 /* Not sure uninorth supports that high aperture sizes */
{256, 65536, 6, 64},
@@ -477,7 +477,7 @@ static struct aper_size_info_32 uninorth_sizes[7] =
* Not sure that u3 supports that high aperture sizes but it
* would strange if it did not :)
*/
-static struct aper_size_info_32 u3_sizes[8] =
+static const struct aper_size_info_32 u3_sizes[8] =
{
{512, 131072, 7, 128},
{256, 65536, 6, 64},
@@ -489,7 +489,7 @@ static struct aper_size_info_32 u3_sizes[8] =
{4, 1024, 0, 1}
};
-struct agp_bridge_driver uninorth_agp_driver = {
+const struct agp_bridge_driver uninorth_agp_driver = {
.owner = THIS_MODULE,
.aperture_sizes = (void *)uninorth_sizes,
.size_type = U32_APER_SIZE,
@@ -514,7 +514,7 @@ struct agp_bridge_driver uninorth_agp_driver = {
.cant_use_aperture = 1,
};
-struct agp_bridge_driver u3_agp_driver = {
+const struct agp_bridge_driver u3_agp_driver = {
.owner = THIS_MODULE,
.aperture_sizes = (void *)u3_sizes,
.size_type = U32_APER_SIZE,
diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
index 2e7c04370cd..a2bb4eccaab 100644
--- a/drivers/char/agp/via-agp.c
+++ b/drivers/char/agp/via-agp.c
@@ -89,7 +89,7 @@ static void via_tlbflush(struct agp_memory *mem)
}
-static struct aper_size_info_8 via_generic_sizes[9] =
+static const struct aper_size_info_8 via_generic_sizes[9] =
{
{256, 65536, 6, 0},
{128, 32768, 5, 128},
@@ -170,7 +170,7 @@ static void via_tlbflush_agp3(struct agp_memory *mem)
}
-static struct agp_bridge_driver via_agp3_driver = {
+static const struct agp_bridge_driver via_agp3_driver = {
.owner = THIS_MODULE,
.aperture_sizes = agp3_generic_sizes,
.size_type = U8_APER_SIZE,
@@ -194,7 +194,7 @@ static struct agp_bridge_driver via_agp3_driver = {
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver via_driver = {
+static const struct agp_bridge_driver via_driver = {
.owner = THIS_MODULE,
.aperture_sizes = via_generic_sizes,
.size_type = U8_APER_SIZE,
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 54df35527bc..16dc5d1d3cb 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -3501,6 +3501,7 @@ get_serial_info(struct cyclades_port *info,
tmp.irq = cinfo->irq;
tmp.flags = info->flags;
tmp.close_delay = info->close_delay;
+ tmp.closing_wait = info->closing_wait;
tmp.baud_base = info->baud;
tmp.custom_divisor = info->custom_divisor;
tmp.hub6 = 0; /*!!! */
diff --git a/drivers/char/ds1286.c b/drivers/char/ds1286.c
index 6d58b037080..59146e3365b 100644
--- a/drivers/char/ds1286.c
+++ b/drivers/char/ds1286.c
@@ -197,6 +197,7 @@ static int ds1286_ioctl(struct inode *inode, struct file *file,
hrs = alm_tm.tm_hour;
min = alm_tm.tm_min;
+ sec = alm_tm.tm_sec;
if (hrs >= 24)
hrs = 0xff;
@@ -204,9 +205,11 @@ static int ds1286_ioctl(struct inode *inode, struct file *file,
if (min >= 60)
min = 0xff;
- BIN_TO_BCD(sec);
- BIN_TO_BCD(min);
- BIN_TO_BCD(hrs);
+ if (sec != 0)
+ return -EINVAL;
+
+ min = BIN2BCD(min);
+ min = BIN2BCD(hrs);
spin_lock(&ds1286_lock);
rtc_write(hrs, RTC_HOURS_ALARM);
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 88fc24fc439..de5be30484a 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -209,7 +209,6 @@ static void digi_send_break(struct channel *ch, int msec);
static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
void epca_setup(char *, int *);
-static int get_termio(struct tty_struct *, struct termio __user *);
static int pc_write(struct tty_struct *, const unsigned char *, int);
static int pc_init(void);
static int init_PCI(void);
@@ -2362,15 +2361,6 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
switch (cmd)
{ /* Begin switch cmd */
-
-#if 0 /* Handled by calling layer properly */
- case TCGETS:
- if (copy_to_user(argp, tty->termios, sizeof(struct ktermios)))
- return -EFAULT;
- return 0;
- case TCGETA:
- return get_termio(tty, argp);
-#endif
case TCSBRK: /* SVID version: non-zero arg --> no break */
retval = tty_check_change(tty);
if (retval)
@@ -2735,13 +2725,6 @@ static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
memoff(ch);
} /* End setup_empty_event */
-/* --------------------- Begin get_termio ----------------------- */
-
-static int get_termio(struct tty_struct * tty, struct termio __user * termio)
-{ /* Begin get_termio */
- return kernel_termios_to_user_termio(termio, tty->termios);
-} /* End get_termio */
-
/* ---------------------- Begin epca_setup -------------------------- */
void epca_setup(char *str, int *ints)
{ /* Begin epca_setup */
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index cc2cd46bedc..a0a88aa23f5 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -316,7 +316,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
{
struct hvc_struct *hp;
unsigned long flags;
- int irq = NO_IRQ;
+ int irq = 0;
int rc = 0;
struct kobject *kobjp;
@@ -338,14 +338,14 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
hp->tty = tty;
/* Save for request_irq outside of spin_lock. */
irq = hp->irq;
- if (irq != NO_IRQ)
+ if (irq)
hp->irq_requested = 1;
kobjp = &hp->kobj;
spin_unlock_irqrestore(&hp->lock, flags);
/* check error, fallback to non-irq */
- if (irq != NO_IRQ)
+ if (irq)
rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, "hvc_console", hp);
/*
@@ -373,7 +373,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
{
struct hvc_struct *hp;
struct kobject *kobjp;
- int irq = NO_IRQ;
+ int irq = 0;
unsigned long flags;
if (tty_hung_up_p(filp))
@@ -407,7 +407,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
*/
tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
- if (irq != NO_IRQ)
+ if (irq)
free_irq(irq, hp);
} else {
@@ -424,7 +424,7 @@ static void hvc_hangup(struct tty_struct *tty)
{
struct hvc_struct *hp = tty->driver_data;
unsigned long flags;
- int irq = NO_IRQ;
+ int irq = 0;
int temp_open_count;
struct kobject *kobjp;
@@ -453,7 +453,7 @@ static void hvc_hangup(struct tty_struct *tty)
irq = hp->irq;
hp->irq_requested = 0;
spin_unlock_irqrestore(&hp->lock, flags);
- if (irq != NO_IRQ)
+ if (irq)
free_irq(irq, hp);
while(temp_open_count) {
--temp_open_count;
@@ -583,7 +583,7 @@ static int hvc_poll(struct hvc_struct *hp)
/* If we aren't interrupt driven and aren't throttled, we always
* request a reschedule
*/
- if (hp->irq == NO_IRQ)
+ if (hp->irq == 0)
poll_mask |= HVC_POLL_READ;
/* Read data if any */
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
index f86fa0c55d3..e46120d05b6 100644
--- a/drivers/char/ip2/i2lib.c
+++ b/drivers/char/ip2/i2lib.c
@@ -80,7 +80,7 @@ static int i2RetryFlushOutput(i2ChanStrPtr);
// Not a documented part of the library routines (careful...) but the Diagnostic
// i2diag.c finds them useful to help the throughput in certain limited
// single-threaded operations.
-static inline void iiSendPendingMail(i2eBordStrPtr);
+static void iiSendPendingMail(i2eBordStrPtr);
static void serviceOutgoingFifo(i2eBordStrPtr);
// Functions defined in ip2.c as part of interrupt handling
@@ -166,7 +166,7 @@ static void iiSendPendingMail_t(unsigned long data)
// If any outgoing mail bits are set and there is outgoing mailbox is empty,
// send the mail and clear the bits.
//******************************************************************************
-static inline void
+static void
iiSendPendingMail(i2eBordStrPtr pB)
{
if (pB->i2eOutMailWaiting && (!pB->i2eWaitingForEmptyFifo) )
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index a7b33d2f599..e22146546ad 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -2478,6 +2478,11 @@ static __devinit void default_find_bmc(void)
if (!info)
return;
+#ifdef CONFIG_PPC_MERGE
+ if (check_legacy_ioport(ipmi_defaults[i].port))
+ continue;
+#endif
+
info->addr_source = NULL;
info->si_type = ipmi_defaults[i].type;
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index 0e82968c2f3..f2e4ec4fd40 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -273,6 +273,7 @@ static ssize_t cm4040_read(struct file *filp, char __user *buf,
DEBUGP(6, dev, "BytesToRead=%lu\n", bytes_to_read);
min_bytes_to_read = min(count, bytes_to_read + 5);
+ min_bytes_to_read = min_t(size_t, min_bytes_to_read, READ_WRITE_BUFFER_SIZE);
DEBUGP(6, dev, "Min=%lu\n", min_bytes_to_read);
@@ -340,7 +341,7 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf,
return 0;
}
- if (count < 5) {
+ if ((count < 5) || (count > READ_WRITE_BUFFER_SIZE)) {
DEBUGP(2, dev, "<- cm4040_write buffersize=%Zd < 5\n", count);
return -EIO;
}
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index f24c26d2dba..e4532685668 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -1901,6 +1901,20 @@ static int init_dev(struct tty_driver *driver, int idx,
/* check whether we're reopening an existing tty */
if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
tty = devpts_get_tty(idx);
+ /*
+ * If we don't have a tty here on a slave open, it's because
+ * the master already started the close process and there's
+ * no relation between devpts file and tty anymore.
+ */
+ if (!tty && driver->subtype == PTY_TYPE_SLAVE) {
+ retval = -EIO;
+ goto end_init;
+ }
+ /*
+ * It's safe from now on because init_dev() is called with
+ * tty_mutex held and release_dev() won't change tty->count
+ * or tty->flags without having to grab tty_mutex
+ */
if (tty && driver->subtype == PTY_TYPE_MASTER)
tty = tty->link;
} else {
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index ccaa6a39cb4..d42060ede93 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -214,4 +214,7 @@ pm_good:
return clocksource_register(&clocksource_acpi_pm);
}
-module_init(init_acpi_pm_clocksource);
+/* We use fs_initcall because we want the PCI fixups to have run
+ * but we still need to load before device_initcall
+ */
+fs_initcall(init_acpi_pm_clocksource);
diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c
index 4f3925ceb36..1bde303b970 100644
--- a/drivers/clocksource/cyclone.c
+++ b/drivers/clocksource/cyclone.c
@@ -116,4 +116,4 @@ static int __init init_cyclone_clocksource(void)
return clocksource_register(&clocksource_cyclone);
}
-module_init(init_cyclone_clocksource);
+arch_initcall(init_cyclone_clocksource);
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index a44db75bc25..a905f782033 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -128,7 +128,7 @@ EXPORT_SYMBOL_GPL(cn_netlink_send);
*/
static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), void *data)
{
- struct cn_callback_entry *__cbq;
+ struct cn_callback_entry *__cbq, *__new_cbq;
struct cn_dev *dev = &cdev;
int err = -ENODEV;
@@ -148,27 +148,27 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v
} else {
struct cn_callback_data *d;
- __cbq = kzalloc(sizeof(*__cbq), GFP_ATOMIC);
- if (__cbq) {
- d = &__cbq->data;
+ err = -ENOMEM;
+ __new_cbq = kzalloc(sizeof(struct cn_callback_entry), GFP_ATOMIC);
+ if (__new_cbq) {
+ d = &__new_cbq->data;
d->callback_priv = msg;
d->callback = __cbq->data.callback;
d->ddata = data;
d->destruct_data = destruct_data;
- d->free = __cbq;
+ d->free = __new_cbq;
- INIT_WORK(&__cbq->work,
+ INIT_WORK(&__new_cbq->work,
&cn_queue_wrapper);
-
+
if (queue_work(dev->cbdev->cn_queue,
- &__cbq->work))
+ &__new_cbq->work))
err = 0;
else {
- kfree(__cbq);
+ kfree(__new_cbq);
err = -EINVAL;
}
- } else
- err = -ENOMEM;
+ }
}
break;
}
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index d60bcb9d14c..8d053f500fc 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -432,9 +432,6 @@ static void do_dbs_timer(struct work_struct *work)
/* We want all CPUs to do sampling nearly on same jiffy */
int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
- /* Permit rescheduling of this work item */
- work_release(work);
-
delay -= jiffies % delay;
if (lock_policy_rwsem_write(cpu) < 0)
@@ -473,7 +470,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
dbs_info->enable = 1;
ondemand_powersave_bias_init();
dbs_info->sample_type = DBS_NORMAL_SAMPLE;
- INIT_DELAYED_WORK_NAR(&dbs_info->work, do_dbs_timer);
+ INIT_DELAYED_WORK(&dbs_info->work, do_dbs_timer);
queue_delayed_work_on(dbs_info->cpu, kondemand_wq, &dbs_info->work,
delay);
}
diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c
index 0eb62841e9b..6d3840e629d 100644
--- a/drivers/crypto/geode-aes.c
+++ b/drivers/crypto/geode-aes.c
@@ -99,9 +99,8 @@ do_crypt(void *src, void *dst, int len, u32 flags)
static unsigned int
geode_aes_crypt(struct geode_aes_op *op)
{
-
u32 flags = 0;
- int iflags;
+ unsigned long iflags;
if (op->len == 0 || op->src == op->dst)
return 0;
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 7452399501b..f4ee1afe488 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -667,7 +667,6 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
if (item.format != HID_ITEM_FORMAT_SHORT) {
dbg("unexpected long global item");
- kfree(device->collection);
hid_free_device(device);
kfree(parser);
return NULL;
@@ -676,7 +675,6 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
if (dispatch_type[item.type](parser, &item)) {
dbg("item %u %u %u %u parsing failed\n",
item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
- kfree(device->collection);
hid_free_device(device);
kfree(parser);
return NULL;
@@ -685,14 +683,12 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
if (start == end) {
if (parser->collection_stack_ptr) {
dbg("unbalanced collection at end of report description");
- kfree(device->collection);
hid_free_device(device);
kfree(parser);
return NULL;
}
if (parser->local.delimiter_depth) {
dbg("unbalanced delimiter at end of report description");
- kfree(device->collection);
hid_free_device(device);
kfree(parser);
return NULL;
@@ -703,7 +699,6 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
}
dbg("item fetching failed at offset %d\n", (int)(end - start));
- kfree(device->collection);
hid_free_device(device);
kfree(parser);
return NULL;
@@ -880,7 +875,7 @@ static void hid_output_field(struct hid_field *field, __u8 *data)
/* make sure the unused bits in the last byte are zeros */
if (count > 0 && size > 0)
- data[(count*size-1)/8] = 0;
+ data[(offset+count*size-1)/8] = 0;
for (n = 0; n < count; n++) {
if (field->logical_minimum < 0) /* signed values */
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 89241be4ec9..83c4126b37c 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -29,6 +29,7 @@
*/
#include <linux/hid.h>
+#include <linux/hid-debug.h>
struct hid_usage_entry {
unsigned page;
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 25d180a24fc..c8434023ba6 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -2,7 +2,7 @@
* $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $
*
* Copyright (c) 2000-2001 Vojtech Pavlik
- * Copyright (c) 2006 Jiri Kosina
+ * Copyright (c) 2006-2007 Jiri Kosina
*
* HID to Linux Input mapping
*/
@@ -71,7 +71,6 @@ static const struct {
#define map_led(c) do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0)
#define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0)
-#define map_rel_clear(c) do { map_rel(c); clear_bit(c, bit); } while (0)
#define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0)
#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
@@ -296,7 +295,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
}
}
- map_key_clear(code);
+ map_key(code);
break;
@@ -347,9 +346,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
if (field->flags & HID_MAIN_ITEM_RELATIVE)
- map_rel_clear(usage->hid & 0xf);
+ map_rel(usage->hid & 0xf);
else
- map_abs_clear(usage->hid & 0xf);
+ map_abs(usage->hid & 0xf);
break;
case HID_GD_HATSWITCH:
@@ -519,7 +518,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x22f: map_key_clear(KEY_ZOOMRESET); break;
case 0x233: map_key_clear(KEY_SCROLLUP); break;
case 0x234: map_key_clear(KEY_SCROLLDOWN); break;
- case 0x238: map_rel_clear(REL_HWHEEL); break;
+ case 0x238: map_rel(REL_HWHEEL); break;
case 0x25f: map_key_clear(KEY_CANCEL); break;
case 0x279: map_key_clear(KEY_REDO); break;
@@ -532,6 +531,26 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x302: map_key_clear(KEY_PROG2); break;
case 0x303: map_key_clear(KEY_PROG3); break;
+ /* Reported on Logitech S510 wireless keyboard */
+ case 0x101f: map_key_clear(KEY_ZOOMIN); break;
+ case 0x1020: map_key_clear(KEY_ZOOMOUT); break;
+ case 0x1021: map_key_clear(KEY_ZOOMRESET); break;
+ /* this one is marked as 'Rotate' */
+ case 0x1028: map_key_clear(KEY_ANGLE); break;
+ case 0x1029: map_key_clear(KEY_SHUFFLE); break;
+ case 0x1041: map_key_clear(KEY_BATTERY); break;
+ case 0x1042: map_key_clear(KEY_WORDPROCESSOR); break;
+ case 0x1043: map_key_clear(KEY_SPREADSHEET); break;
+ case 0x1044: map_key_clear(KEY_PRESENTATION); break;
+ case 0x1045: map_key_clear(KEY_UNDO); break;
+ case 0x1046: map_key_clear(KEY_REDO); break;
+ case 0x1047: map_key_clear(KEY_PRINT); break;
+ case 0x1048: map_key_clear(KEY_SAVE); break;
+ case 0x1049: map_key_clear(KEY_PROG1); break;
+ case 0x104a: map_key_clear(KEY_PROG2); break;
+ case 0x104b: map_key_clear(KEY_PROG3); break;
+ case 0x104c: map_key_clear(KEY_PROG4); break;
+
default: goto ignore;
}
break;
@@ -647,6 +666,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
set_bit(usage->type, input->evbit);
+ if (device->quirks & HID_QUIRK_DUPLICATE_USAGES &&
+ (usage->type == EV_KEY ||
+ usage->type == EV_REL ||
+ usage->type == EV_ABS))
+ clear_bit(usage->code, bit);
+
while (usage->code <= max && test_and_set_bit(usage->code, bit))
usage->code = find_next_zero_bit(bit, max + 1, usage->code);
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 4d44a2db29d..fb19dbb31e4 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -495,6 +495,16 @@ config I2C_VERSATILE
This driver can also be built as a module. If so, the module
will be called i2c-versatile.
+config I2C_ACORN
+ bool "Acorn IOC/IOMD I2C bus support"
+ depends on I2C && ARCH_ACORN
+ default y
+ select I2C_ALGOBIT
+ help
+ Say yes if you want to support the I2C bus on Acorn platforms.
+
+ If you don't know, say Y.
+
config I2C_VIA
tristate "VIA 82C586B"
depends on I2C && PCI && EXPERIMENTAL
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 03505aa44bb..290b5401835 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
+obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
obj-$(CONFIG_I2C_VIA) += i2c-via.o
obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c
new file mode 100644
index 00000000000..09bd7f40b90
--- /dev/null
+++ b/drivers/i2c/busses/i2c-acorn.c
@@ -0,0 +1,97 @@
+/*
+ * linux/drivers/acorn/char/i2c.c
+ *
+ * Copyright (C) 2000 Russell King
+ *
+ * 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.
+ *
+ * ARM IOC/IOMD i2c driver.
+ *
+ * On Acorn machines, the following i2c devices are on the bus:
+ * - PCF8583 real time clock & static RAM
+ */
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/hardware/ioc.h>
+#include <asm/system.h>
+
+#define FORCE_ONES 0xdc
+#define SCL 0x02
+#define SDA 0x01
+
+/*
+ * We must preserve all non-i2c output bits in IOC_CONTROL.
+ * Note also that we need to preserve the value of SCL and
+ * SDA outputs as well (which may be different from the
+ * values read back from IOC_CONTROL).
+ */
+static u_int force_ones;
+
+static void ioc_setscl(void *data, int state)
+{
+ u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
+ u_int ones = force_ones;
+
+ if (state)
+ ones |= SCL;
+ else
+ ones &= ~SCL;
+
+ force_ones = ones;
+
+ ioc_writeb(ioc_control | ones, IOC_CONTROL);
+}
+
+static void ioc_setsda(void *data, int state)
+{
+ u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
+ u_int ones = force_ones;
+
+ if (state)
+ ones |= SDA;
+ else
+ ones &= ~SDA;
+
+ force_ones = ones;
+
+ ioc_writeb(ioc_control | ones, IOC_CONTROL);
+}
+
+static int ioc_getscl(void *data)
+{
+ return (ioc_readb(IOC_CONTROL) & SCL) != 0;
+}
+
+static int ioc_getsda(void *data)
+{
+ return (ioc_readb(IOC_CONTROL) & SDA) != 0;
+}
+
+static struct i2c_algo_bit_data ioc_data = {
+ .setsda = ioc_setsda,
+ .setscl = ioc_setscl,
+ .getsda = ioc_getsda,
+ .getscl = ioc_getscl,
+ .udelay = 80,
+ .timeout = 100
+};
+
+static struct i2c_adapter ioc_ops = {
+ .id = I2C_HW_B_IOC,
+ .algo_data = &ioc_data,
+};
+
+static int __init i2c_ioc_init(void)
+{
+ force_ones = FORCE_ONES | SCL | SDA;
+
+ return i2c_bit_add_bus(&ioc_ops);
+}
+
+__initcall(i2c_ioc_init);
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 49234e32fd1..5d134bb75ba 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -1023,7 +1023,7 @@ config BLK_DEV_4DRIVES
config BLK_DEV_ALI14XX
tristate "ALI M14xx support"
help
- This driver is enabled at runtime using the "ide0=ali14xx" kernel
+ This driver is enabled at runtime using the "ali14xx.probe" kernel
boot parameter. It enables support for the secondary IDE interface
of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
I/O speeds to be set as well. See the files
@@ -1033,7 +1033,7 @@ config BLK_DEV_ALI14XX
config BLK_DEV_DTC2278
tristate "DTC-2278 support"
help
- This driver is enabled at runtime using the "ide0=dtc2278" kernel
+ This driver is enabled at runtime using the "dtc2278.probe" kernel
boot parameter. It enables support for the secondary IDE interface
of the DTC-2278 card, and permits faster I/O speeds to be set as
well. See the <file:Documentation/ide.txt> and
@@ -1042,7 +1042,7 @@ config BLK_DEV_DTC2278
config BLK_DEV_HT6560B
tristate "Holtek HT6560B support"
help
- This driver is enabled at runtime using the "ide0=ht6560b" kernel
+ This driver is enabled at runtime using the "ht6560b.probe" kernel
boot parameter. It enables support for the secondary IDE interface
of the Holtek card, and permits faster I/O speeds to be set as well.
See the <file:Documentation/ide.txt> and
@@ -1051,7 +1051,7 @@ config BLK_DEV_HT6560B
config BLK_DEV_QD65XX
tristate "QDI QD65xx support"
help
- This driver is enabled at runtime using the "ide0=qd65xx" kernel
+ This driver is enabled at runtime using the "qd65xx.probe" kernel
boot parameter. It permits faster I/O speeds to be set. See the
<file:Documentation/ide.txt> and <file:drivers/ide/legacy/qd65xx.c> for
more info.
@@ -1059,7 +1059,7 @@ config BLK_DEV_QD65XX
config BLK_DEV_UMC8672
tristate "UMC-8672 support"
help
- This driver is enabled at runtime using the "ide0=umc8672" kernel
+ This driver is enabled at runtime using the "umc8672.probe" kernel
boot parameter. It enables support for the secondary IDE interface
of the UMC-8672, and permits faster I/O speeds to be set as well.
See the files <file:Documentation/ide.txt> and
diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
index 6b2d152351b..556455fbfa2 100644
--- a/drivers/ide/cris/ide-cris.c
+++ b/drivers/ide/cris/ide-cris.c
@@ -17,8 +17,6 @@
* device can't do DMA handshaking for some stupid reason. We don't need to do that.
*/
-#undef REALLY_SLOW_IO /* most systems can safely undef this */
-
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/timer.h>
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index e2cea1889c4..37aa6ddd970 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -43,8 +43,6 @@
#define IDEDISK_VERSION "1.18"
-#undef REALLY_SLOW_IO /* most systems can safely undef this */
-
//#define DEBUG
#include <linux/module.h>
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index c67b3b1e6f4..bd513f5a232 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -583,6 +583,8 @@ u8 eighty_ninty_three (ide_drive_t *drive)
if(!(drive->id->hw_config & 0x4000))
return 0;
#endif /* CONFIG_IDEDMA_IVB */
+ if (!(drive->id->hw_config & 0x2000))
+ return 0;
return 1;
}
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index 8afce4ceea3..68719314df3 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -345,16 +345,16 @@ static int ide_scan_pio_blacklist (char *model)
/**
* ide_get_best_pio_mode - get PIO mode from drive
- * @driver: drive to consider
+ * @drive: drive to consider
* @mode_wanted: preferred mode
- * @max_mode: highest allowed
- * @d: pio data
+ * @max_mode: highest allowed mode
+ * @d: PIO data
*
* This routine returns the recommended PIO settings for a given drive,
* based on the drive->id information and the ide_pio_blacklist[].
- * This is used by most chipset support modules when "auto-tuning".
*
- * Drive PIO mode auto selection
+ * Drive PIO mode is auto-selected if 255 is passed as mode_wanted.
+ * This is used by most chipset support modules when "auto-tuning".
*/
u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d)
@@ -367,6 +367,7 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p
if (mode_wanted != 255) {
pio_mode = mode_wanted;
+ use_iordy = (pio_mode > 2);
} else if (!drive->id) {
pio_mode = 0;
} else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
@@ -396,19 +397,12 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p
}
}
-#if 0
- if (drive->id->major_rev_num & 0x0004) printk("ATA-2 ");
-#endif
-
/*
* Conservative "downgrade" for all pre-ATA2 drives
*/
if (pio_mode && pio_mode < 4) {
pio_mode--;
overridden = 1;
-#if 0
- use_iordy = (pio_mode > 2);
-#endif
if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
cycle_time = 0; /* use standard timing */
}
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 8afbd6cb94b..8f15c23aa70 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -31,8 +31,6 @@
* valid after probe time even with noprobe
*/
-#undef REALLY_SLOW_IO /* most systems can safely undef this */
-
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index b3c0818c5c6..dfbd7445852 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -126,8 +126,6 @@
#define REVISION "Revision: 7.00alpha2"
#define VERSION "Id: ide.c 7.00a2 20020906"
-#undef REALLY_SLOW_IO /* most systems can safely undef this */
-
#define _IDE_C /* Tell ide.h it's really us */
#include <linux/module.h>
@@ -1486,23 +1484,23 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m
}
#ifdef CONFIG_BLK_DEV_ALI14XX
-static int __initdata probe_ali14xx;
+extern int probe_ali14xx;
extern int ali14xx_init(void);
#endif
#ifdef CONFIG_BLK_DEV_UMC8672
-static int __initdata probe_umc8672;
+extern int probe_umc8672;
extern int umc8672_init(void);
#endif
#ifdef CONFIG_BLK_DEV_DTC2278
-static int __initdata probe_dtc2278;
+extern int probe_dtc2278;
extern int dtc2278_init(void);
#endif
#ifdef CONFIG_BLK_DEV_HT6560B
-static int __initdata probe_ht6560b;
+extern int probe_ht6560b;
extern int ht6560b_init(void);
#endif
#ifdef CONFIG_BLK_DEV_QD65XX
-static int __initdata probe_qd65xx;
+extern int probe_qd65xx;
extern int qd65xx_init(void);
#endif
@@ -1580,7 +1578,7 @@ static int __init ide_setup(char *s)
*/
if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
const char *hd_words[] = {
- "none", "noprobe", "nowerr", "cdrom", "serialize",
+ "none", "noprobe", "nowerr", "cdrom", "minus5",
"autotune", "noautotune", "minus8", "swapdata", "bswap",
"noflush", "remap", "remap63", "scsi", NULL };
unit = s[2] - 'a';
@@ -1608,9 +1606,6 @@ static int __init ide_setup(char *s)
drive->ready_stat = 0;
hwif->noprobe = 0;
goto done;
- case -5: /* "serialize" */
- printk(" -- USE \"ide%d=serialize\" INSTEAD", hw);
- goto do_serialize;
case -6: /* "autotune" */
drive->autotune = IDE_TUNE_AUTO;
goto obsolete_option;
@@ -1671,7 +1666,7 @@ static int __init ide_setup(char *s)
* (-8, -9, -10) are reserved to ease the hardcoding.
*/
static const char *ide_words[] = {
- "noprobe", "serialize", "autotune", "noautotune",
+ "noprobe", "serialize", "minus3", "minus4",
"reset", "dma", "ata66", "minus8", "minus9",
"minus10", "four", "qd65xx", "ht6560b", "cmd640_vlb",
"dtc2278", "umc8672", "ali14xx", NULL };
@@ -1742,12 +1737,17 @@ static int __init ide_setup(char *s)
hwif->chipset = mate->chipset = ide_4drives;
mate->irq = hwif->irq;
memcpy(mate->io_ports, hwif->io_ports, sizeof(hwif->io_ports));
- goto do_serialize;
+ hwif->mate = mate;
+ mate->mate = hwif;
+ hwif->serialized = mate->serialized = 1;
+ goto obsolete_option;
}
#endif /* CONFIG_BLK_DEV_4DRIVES */
case -10: /* minus10 */
case -9: /* minus9 */
case -8: /* minus8 */
+ case -4:
+ case -3:
goto bad_option;
case -7: /* ata66 */
#ifdef CONFIG_BLK_DEV_IDEPCI
@@ -1762,16 +1762,7 @@ static int __init ide_setup(char *s)
case -5: /* "reset" */
hwif->reset = 1;
goto obsolete_option;
- case -4: /* "noautotune" */
- hwif->drives[0].autotune = IDE_TUNE_NOAUTO;
- hwif->drives[1].autotune = IDE_TUNE_NOAUTO;
- goto obsolete_option;
- case -3: /* "autotune" */
- hwif->drives[0].autotune = IDE_TUNE_AUTO;
- hwif->drives[1].autotune = IDE_TUNE_AUTO;
- goto obsolete_option;
case -2: /* "serialize" */
- do_serialize:
hwif->mate = &ide_hwifs[hw^1];
hwif->mate->mate = hwif;
hwif->serialized = hwif->mate->serialized = 1;
@@ -1840,8 +1831,8 @@ static void __init probe_for_hwifs (void)
#endif /* CONFIG_BLK_DEV_CMD640 */
#ifdef CONFIG_BLK_DEV_IDE_PMAC
{
- extern void pmac_ide_probe(void);
- pmac_ide_probe();
+ extern int pmac_ide_probe(void);
+ (void)pmac_ide_probe();
}
#endif /* CONFIG_BLK_DEV_IDE_PMAC */
#ifdef CONFIG_BLK_DEV_GAYLE
diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c
index 9c544467cb7..91961aa0304 100644
--- a/drivers/ide/legacy/ali14xx.c
+++ b/drivers/ide/legacy/ali14xx.c
@@ -37,8 +37,6 @@
* mode 4 for a while now with no trouble.) -Derek
*/
-#undef REALLY_SLOW_IO /* most systems can safely undef this */
-
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -230,9 +228,17 @@ static int __init ali14xx_probe(void)
return 0;
}
+int probe_ali14xx = 0;
+
+module_param_named(probe, probe_ali14xx, bool, 0);
+MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets");
+
/* Can be called directly from ide.c. */
int __init ali14xx_init(void)
{
+ if (probe_ali14xx == 0)
+ goto out;
+
/* auto-detect IDE controller port */
if (findPort()) {
if (ali14xx_probe())
@@ -240,6 +246,7 @@ int __init ali14xx_init(void)
return 0;
}
printk(KERN_ERR "ali14xx: not found.\n");
+out:
return -ENODEV;
}
diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c
index 3b1d33baaa2..0219ffa64db 100644
--- a/drivers/ide/legacy/dtc2278.c
+++ b/drivers/ide/legacy/dtc2278.c
@@ -4,8 +4,6 @@
* Copyright (C) 1996 Linus Torvalds & author (see below)
*/
-#undef REALLY_SLOW_IO /* most systems can safely undef this */
-
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -94,7 +92,7 @@ static void tune_dtc2278 (ide_drive_t *drive, u8 pio)
HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
}
-static int __init probe_dtc2278(void)
+static int __init dtc2278_probe(void)
{
unsigned long flags;
ide_hwif_t *hwif, *mate;
@@ -145,10 +143,18 @@ static int __init probe_dtc2278(void)
return 0;
}
+int probe_dtc2278 = 0;
+
+module_param_named(probe, probe_dtc2278, bool, 0);
+MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets");
+
/* Can be called directly from ide.c. */
int __init dtc2278_init(void)
{
- if (probe_dtc2278()) {
+ if (probe_dtc2278 == 0)
+ return -ENODEV;
+
+ if (dtc2278_probe()) {
printk(KERN_ERR "dtc2278: ide interfaces already in use!\n");
return -EBUSY;
}
diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
index 19ccd006f20..a2832643c52 100644
--- a/drivers/ide/legacy/ht6560b.c
+++ b/drivers/ide/legacy/ht6560b.c
@@ -36,8 +36,6 @@
#define HT6560B_VERSION "v0.07"
-#undef REALLY_SLOW_IO /* most systems can safely undef this */
-
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -303,12 +301,20 @@ static void tune_ht6560b (ide_drive_t *drive, u8 pio)
#endif
}
+int probe_ht6560b = 0;
+
+module_param_named(probe, probe_ht6560b, bool, 0);
+MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
+
/* Can be called directly from ide.c. */
int __init ht6560b_init(void)
{
ide_hwif_t *hwif, *mate;
int t;
+ if (probe_ht6560b == 0)
+ return -ENODEV;
+
hwif = &ide_hwifs[0];
mate = &ide_hwifs[1];
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index a5023cdbdc5..b08c37c9f95 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -359,14 +359,17 @@ void ide_release(struct pcmcia_device *link)
static struct pcmcia_device_id ide_ids[] = {
PCMCIA_DEVICE_FUNC_ID(4),
PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */
+ PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000), /* I-O Data CFA */
+ PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001), /* Mitsubishi CFA */
PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
- PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),
+ PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), /* SanDisk CFA */
PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */
PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */
PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */
PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001),
- PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar */
+ PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0100), /* Viking CFA */
+ PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar, Viking CFA */
PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0),
PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74),
PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9),
diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
index d3c3bc2640e..2fb8f50f129 100644
--- a/drivers/ide/legacy/qd65xx.c
+++ b/drivers/ide/legacy/qd65xx.c
@@ -16,8 +16,8 @@
* Please set local bus speed using kernel parameter idebus
* for example, "idebus=33" stands for 33Mhz VLbus
* To activate controller support, use "ide0=qd65xx"
- * To enable tuning, use "ide0=autotune"
- * To enable second channel tuning (qd6580 only), use "ide1=autotune"
+ * To enable tuning, use "hda=autotune hdb=autotune"
+ * To enable 2nd channel tuning (qd6580 only), use "hdc=autotune hdd=autotune"
*/
/*
@@ -25,8 +25,6 @@
* Samuel Thibault <samuel.thibault@fnac.net>
*/
-#undef REALLY_SLOW_IO /* most systems can safely undef this */
-
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -490,9 +488,17 @@ static int __init qd_probe(int base)
return 1;
}
+int probe_qd65xx = 0;
+
+module_param_named(probe, probe_qd65xx, bool, 0);
+MODULE_PARM_DESC(probe, "probe for QD65xx chipsets");
+
/* Can be called directly from ide.c. */
int __init qd65xx_init(void)
{
+ if (probe_qd65xx == 0)
+ return -ENODEV;
+
if (qd_probe(0x30))
qd_probe(0xb0);
if (ide_hwifs[0].chipset != ide_qd65xx &&
diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c
index 6e2c58c5f6a..ca797445557 100644
--- a/drivers/ide/legacy/umc8672.c
+++ b/drivers/ide/legacy/umc8672.c
@@ -165,12 +165,21 @@ static int __init umc8672_probe(void)
return 0;
}
+int probe_umc8672 = 0;
+
+module_param_named(probe, probe_umc8672, bool, 0);
+MODULE_PARM_DESC(probe, "probe for UMC8672 chipset");
+
/* Can be called directly from ide.c. */
int __init umc8672_init(void)
{
- if (umc8672_probe())
- return -ENODEV;
- return 0;
+ if (probe_umc8672 == 0)
+ goto out;
+
+ if (umc8672_probe() == 0)
+ return 0;;
+out:
+ return -ENODEV;;
}
#ifdef MODULE
diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
index 0a59d5ef159..b2dc028dc8c 100644
--- a/drivers/ide/mips/au1xxx-ide.c
+++ b/drivers/ide/mips/au1xxx-ide.c
@@ -29,8 +29,6 @@
* Note: for more information, please refer "AMD Alchemy Au1200/Au1550 IDE
* Interface and Linux Device Driver" Application Note.
*/
-#undef REALLY_SLOW_IO /* most systems can safely undef this */
-
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index 4debd18d52f..83e0aa65a43 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/alim15x3.c Version 0.17 2003/01/02
+ * linux/drivers/ide/pci/alim15x3.c Version 0.21 2007/02/03
*
* Copyright (C) 1998-2000 Michel Aubry, Maintainer
* Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
@@ -9,6 +9,7 @@
* May be copied or modified under the terms of the GNU General Public License
* Copyright (C) 2002 Alan Cox <alan@redhat.com>
* ALi (now ULi M5228) support by Clear Zhang <Clear.Zhang@ali.com.tw>
+ * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
*
* (U)DMA capable version of ali 1533/1543(C), 1535(D)
*
@@ -280,15 +281,17 @@ static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
/**
- * ali15x3_tune_drive - set up a drive
+ * ali15x3_tune_pio - set up chipset for PIO mode
* @drive: drive to tune
- * @pio: unused
+ * @pio: desired mode
*
- * Select the best PIO timing for the drive in question. Then
- * program the controller for this drive set up
+ * Select the best PIO mode for the drive in question.
+ * Then program the controller for this mode.
+ *
+ * Returns the PIO mode programmed.
*/
-static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio)
+static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio)
{
ide_pio_data_t d;
ide_hwif_t *hwif = HWIF(drive);
@@ -356,6 +359,22 @@ static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio)
* { 20, 50, 30 } PIO Mode 5 with IORDY (nonstandard)
*/
+ return pio;
+}
+
+/**
+ * ali15x3_tune_drive - set up drive for PIO mode
+ * @drive: drive to tune
+ * @pio: desired mode
+ *
+ * Program the controller with the best PIO timing for the given drive.
+ * Then set up the drive itself.
+ */
+
+static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ pio = ali15x3_tune_pio(drive, pio);
+ (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
/**
@@ -430,7 +449,7 @@ static u8 ali15x3_ratemask (ide_drive_t *drive)
}
/**
- * ali15x3_tune_chipset - set up chiset for new speed
+ * ali15x3_tune_chipset - set up chipset/drive for new speed
* @drive: drive to configure for
* @xferspeed: desired speed
*
@@ -461,7 +480,7 @@ static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed)
pci_write_config_byte(dev, m5229_udma, tmpbyte);
if (speed < XFER_SW_DMA_0)
- ali15x3_tune_drive(drive, speed);
+ (void) ali15x3_tune_pio(drive, speed - XFER_PIO_0);
} else {
pci_read_config_byte(dev, m5229_udma, &tmpbyte);
tmpbyte &= (0x0f << ((1-unit) << 2));
diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
index 61b5f9c0b2f..dc43f009aca 100644
--- a/drivers/ide/pci/cmd640.c
+++ b/drivers/ide/pci/cmd640.c
@@ -98,7 +98,6 @@
* (patch courtesy of Zoltan Hidvegi)
*/
-#undef REALLY_SLOW_IO /* most systems can safely undef this */
#define CMD640_PREFETCH_MASKS 1
//#define CMD640_DUMP_REGS
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index 49df27513da..b0d4825c56a 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -1,6 +1,6 @@
/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
*
- * linux/drivers/ide/pci/cmd64x.c Version 1.30 Sept 10, 2002
+ * linux/drivers/ide/pci/cmd64x.c Version 1.41 Feb 3, 2007
*
* cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
* Note, this driver is not used at all on other systems because
@@ -12,6 +12,7 @@
* Copyright (C) 1998 David S. Miller (davem@redhat.com)
*
* Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
*/
#include <linux/module.h>
@@ -262,43 +263,25 @@ static void program_drive_counts (ide_drive_t *drive, int setup_count, int activ
}
/*
- * Attempts to set the interface PIO mode.
- * The preferred method of selecting PIO modes (e.g. mode 4) is
- * "echo 'piomode:4' > /proc/ide/hdx/settings". Special cases are
- * 8: prefetch off, 9: prefetch on, 255: auto-select best mode.
- * Called with 255 at boot time.
+ * This routine selects drive's best PIO mode, calculates setup/active/recovery
+ * counts, and then writes them into the chipset registers.
*/
-
-static void cmd64x_tuneproc (ide_drive_t *drive, u8 mode_wanted)
+static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted)
{
int setup_time, active_time, recovery_time;
int clock_time, pio_mode, cycle_time;
u8 recovery_count2, cycle_count;
int setup_count, active_count, recovery_count;
int bus_speed = system_bus_clock();
- /*byte b;*/
ide_pio_data_t d;
- switch (mode_wanted) {
- case 8: /* set prefetch off */
- case 9: /* set prefetch on */
- mode_wanted &= 1;
- /*set_prefetch_mode(index, mode_wanted);*/
- cmdprintk("%s: %sabled cmd640 prefetch\n",
- drive->name, mode_wanted ? "en" : "dis");
- return;
- }
-
- mode_wanted = ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
- pio_mode = d.pio_mode;
+ pio_mode = ide_get_best_pio_mode(drive, mode_wanted, 5, &d);
cycle_time = d.cycle_time;
/*
* I copied all this complicated stuff from cmd640.c and made a few
* minor changes. For now I am just going to pray that it is correct.
*/
- if (pio_mode > 5)
- pio_mode = 5;
setup_time = ide_pio_timings[pio_mode].setup_time;
active_time = ide_pio_timings[pio_mode].active_time;
recovery_time = cycle_time - (setup_time + active_time);
@@ -320,22 +303,33 @@ static void cmd64x_tuneproc (ide_drive_t *drive, u8 mode_wanted)
if (active_count > 16)
active_count = 16; /* maximum allowed by cmd646 */
- /*
- * In a perfect world, we might set the drive pio mode here
- * (using WIN_SETFEATURE) before continuing.
- *
- * But we do not, because:
- * 1) this is the wrong place to do it
- * (proper is do_special() in ide.c)
- * 2) in practice this is rarely, if ever, necessary
- */
program_drive_counts (drive, setup_count, active_count, recovery_count);
- cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, "
+ cmdprintk("%s: PIO mode wanted %d, selected %d (%dns)%s, "
"clocks=%d/%d/%d\n",
- drive->name, pio_mode, mode_wanted, cycle_time,
+ drive->name, mode_wanted, pio_mode, cycle_time,
d.overridden ? " (overriding vendor mode)" : "",
setup_count, active_count, recovery_count);
+
+ return pio_mode;
+}
+
+/*
+ * Attempts to set drive's PIO mode.
+ * Special cases are 8: prefetch off, 9: prefetch on (both never worked),
+ * and 255: auto-select best mode (used at boot time).
+ */
+static void cmd64x_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ /*
+ * Filter out the prefetch control values
+ * to prevent PIO5 from being programmed
+ */
+ if (pio == 8 || pio == 9)
+ return;
+
+ pio = cmd64x_tune_pio(drive, pio);
+ (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
static u8 cmd64x_ratemask (ide_drive_t *drive)
@@ -387,22 +381,6 @@ static u8 cmd64x_ratemask (ide_drive_t *drive)
return mode;
}
-static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, u8 set_speed)
-{
- u8 speed = 0x00;
- u8 set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL);
-
- cmd64x_tuneproc(drive, set_pio);
- speed = XFER_PIO_0 + set_pio;
- if (set_speed)
- (void) ide_config_drive_speed(drive, speed);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive, u8 set_speed)
-{
- config_cmd64x_chipset_for_pio(drive, set_speed);
-}
-
static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
{
ide_hwif_t *hwif = HWIF(drive);
@@ -414,7 +392,7 @@ static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
u8 speed = ide_rate_filter(cmd64x_ratemask(drive), xferspeed);
- if (speed > XFER_PIO_4) {
+ if (speed >= XFER_SW_DMA_0) {
(void) pci_read_config_byte(dev, pciD, &regD);
(void) pci_read_config_byte(dev, pciU, &regU);
regD &= ~(unit ? 0x40 : 0x20);
@@ -438,17 +416,20 @@ static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
case XFER_SW_DMA_2: regD |= (unit ? 0x40 : 0x10); break;
case XFER_SW_DMA_1: regD |= (unit ? 0x80 : 0x20); break;
case XFER_SW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break;
- case XFER_PIO_4: cmd64x_tuneproc(drive, 4); break;
- case XFER_PIO_3: cmd64x_tuneproc(drive, 3); break;
- case XFER_PIO_2: cmd64x_tuneproc(drive, 2); break;
- case XFER_PIO_1: cmd64x_tuneproc(drive, 1); break;
- case XFER_PIO_0: cmd64x_tuneproc(drive, 0); break;
+ case XFER_PIO_5:
+ case XFER_PIO_4:
+ case XFER_PIO_3:
+ case XFER_PIO_2:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ (void) cmd64x_tune_pio(drive, speed - XFER_PIO_0);
+ break;
default:
return 1;
}
- if (speed > XFER_PIO_4) {
+ if (speed >= XFER_SW_DMA_0) {
(void) pci_write_config_byte(dev, pciU, regU);
regD |= (unit ? 0x40 : 0x20);
(void) pci_write_config_byte(dev, pciD, regD);
@@ -461,8 +442,6 @@ static int config_chipset_for_dma (ide_drive_t *drive)
{
u8 speed = ide_dma_speed(drive, cmd64x_ratemask(drive));
- config_chipset_for_pio(drive, !speed);
-
if (!speed)
return 0;
@@ -478,7 +457,7 @@ static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- config_chipset_for_pio(drive, 1);
+ cmd64x_tune_drive(drive, 255);
return -1;
}
@@ -679,14 +658,13 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
class_rev &= 0xff;
- hwif->tuneproc = &cmd64x_tuneproc;
+ hwif->tuneproc = &cmd64x_tune_drive;
hwif->speedproc = &cmd64x_tune_chipset;
- if (!hwif->dma_base) {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+
+ if (!hwif->dma_base)
return;
- }
hwif->atapi_dma = 1;
diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c
index e2672fc65d3..d4b753e7011 100644
--- a/drivers/ide/pci/delkin_cb.c
+++ b/drivers/ide/pci/delkin_cb.c
@@ -122,7 +122,7 @@ static struct pci_driver driver = {
static int
delkin_cb_init (void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
index b408c6c517e..f2c5a141ca1 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/pci/generic.c
@@ -21,8 +21,6 @@
* are deemed to be part of the source code.
*/
-#undef REALLY_SLOW_IO /* most systems can safely undef this */
-
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c
index 9ca60dd2185..aede7eee924 100644
--- a/drivers/ide/pci/opti621.c
+++ b/drivers/ide/pci/opti621.c
@@ -57,7 +57,7 @@
* There is a 25/33MHz switch in configuration
* register, but driver is written for use at any frequency which get
* (use idebus=xx to select PCI bus speed).
- * Use ide0=autotune for automatical tune of the PIO modes.
+ * Use hda=autotune and hdb=autotune for automatical tune of the PIO modes.
* If you get strange results, do not use this and set PIO manually
* by hdparm.
*
@@ -87,7 +87,6 @@
* 0.5 doesn't work.
*/
-#undef REALLY_SLOW_IO /* most systems can safely undef this */
#define OPTI621_DEBUG /* define for debug messages */
#include <linux/types.h>
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index 569822f4cf5..061d300ab8b 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -1,10 +1,10 @@
/*
- * linux/drivers/ide/pci/piix.c Version 0.46 December 3, 2006
+ * linux/drivers/ide/pci/piix.c Version 0.47 February 8, 2007
*
* Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
* Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2003 Red Hat Inc <alan@redhat.com>
- * Copyright (C) 2006 MontaVista Software, Inc. <source@mvista.com>
+ * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
*
* May be copied or modified under the terms of the GNU General Public License
*
@@ -205,14 +205,13 @@ static u8 piix_dma_2_pio (u8 xfer_rate) {
}
/**
- * piix_tune_drive - tune a drive attached to a PIIX
+ * piix_tune_pio - tune PIIX for PIO mode
* @drive: drive to tune
* @pio: desired PIO mode
*
- * Set the interface PIO mode based upon the settings done by AMI BIOS
- * (might be useful if drive is not registered in CMOS for any reason).
+ * Set the interface PIO mode based upon the settings done by AMI BIOS.
*/
-static void piix_tune_drive (ide_drive_t *drive, u8 pio)
+static void piix_tune_pio (ide_drive_t *drive, u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -233,8 +232,6 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
{ 2, 1 },
{ 2, 3 }, };
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-
/*
* Master vs slave is synchronized above us but the slave register is
* shared by the two hwifs so the corner case of two slave timeouts in
@@ -253,19 +250,20 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
master_data |= 0x4000;
master_data &= ~0x0070;
if (pio > 1) {
- /* enable PPE, IE and TIME */
- master_data = master_data | (control << 4);
+ /* Set PPE, IE and TIME */
+ master_data |= control << 4;
}
pci_read_config_byte(dev, slave_port, &slave_data);
- slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
- slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
+ slave_data &= hwif->channel ? 0x0f : 0xf0;
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) <<
+ (hwif->channel ? 4 : 0);
} else {
master_data &= ~0x3307;
if (pio > 1) {
/* enable PPE, IE and TIME */
- master_data = master_data | control;
+ master_data |= control;
}
- master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+ master_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
}
pci_write_config_word(dev, master_port, master_data);
if (is_slave)
@@ -274,6 +272,21 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
}
/**
+ * piix_tune_drive - tune a drive attached to PIIX
+ * @drive: drive to tune
+ * @pio: desired PIO mode
+ *
+ * Set the drive's PIO mode (might be useful if drive is not registered
+ * in CMOS for any reason).
+ */
+static void piix_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ piix_tune_pio(drive, pio);
+ (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
+}
+
+/**
* piix_tune_chipset - tune a PIIX interface
* @drive: IDE drive to tune
* @xferspeed: speed to configure
@@ -348,8 +361,8 @@ static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed)
pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
}
- piix_tune_drive(drive, piix_dma_2_pio(speed));
- return (ide_config_drive_speed(drive, speed));
+ piix_tune_pio(drive, piix_dma_2_pio(speed));
+ return ide_config_drive_speed(drive, speed);
}
/**
@@ -392,9 +405,7 @@ static int piix_config_drive_xfer_rate (ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- /* Find best PIO mode. */
- piix_tune_chipset(drive, XFER_PIO_0 +
- ide_get_best_pio_mode(drive, 255, 4, NULL));
+ piix_tune_drive(drive, 255);
return -1;
}
diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c
index c1855311052..f8c95469014 100644
--- a/drivers/ide/pci/rz1000.c
+++ b/drivers/ide/pci/rz1000.c
@@ -15,8 +15,6 @@
* Dunno if this fixes both ports, or only the primary port (?).
*/
-#undef REALLY_SLOW_IO /* most systems can safely undef this */
-
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 7b4c189a9d9..71eccdf5f81 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -26,6 +26,11 @@
* If you have strange problems with nVidia chipset systems please
* see the SI support documentation and update your system BIOS
* if neccessary
+ *
+ * The Dell DRAC4 has some interesting features including effectively hot
+ * unplugging/replugging the virtual CD interface when the DRAC is reset.
+ * This often causes drivers/ide/siimage to panic but is ok with the rather
+ * smarter code in libata.
*/
#include <linux/types.h>
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index ae7eb58d961..852ccb36da1 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -1,8 +1,8 @@
/*
- * linux/drivers/ide/pci/slc90e66.c Version 0.13 December 30, 2006
+ * linux/drivers/ide/pci/slc90e66.c Version 0.14 February 8, 2007
*
* Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2006 MontaVista Software, Inc. <source@mvista.com>
+ * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
*
* This is a look-alike variation of the ICH0 PIIX4 Ultra-66,
* but this keeps the ISA-Bridge and slots alive.
@@ -57,11 +57,7 @@ static u8 slc90e66_dma_2_pio (u8 xfer_rate) {
}
}
-/*
- * Based on settings done by AMI BIOS
- * (might be useful if drive is not registered in CMOS for any reason).
- */
-static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
+static void slc90e66_tune_pio (ide_drive_t *drive, u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -80,7 +76,6 @@ static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
{ 2, 1 },
{ 2, 3 }, };
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
spin_lock_irqsave(&ide_lock, flags);
pci_read_config_word(dev, master_port, &master_data);
@@ -94,19 +89,20 @@ static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
master_data |= 0x4000;
master_data &= ~0x0070;
if (pio > 1) {
- /* enable PPE, IE and TIME */
- master_data = master_data | (control << 4);
+ /* Set PPE, IE and TIME */
+ master_data |= control << 4;
}
pci_read_config_byte(dev, slave_port, &slave_data);
- slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
- slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
+ slave_data &= hwif->channel ? 0x0f : 0xf0;
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) <<
+ (hwif->channel ? 4 : 0);
} else {
master_data &= ~0x3307;
if (pio > 1) {
/* enable PPE, IE and TIME */
- master_data = master_data | control;
+ master_data |= control;
}
- master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+ master_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
}
pci_write_config_word(dev, master_port, master_data);
if (is_slave)
@@ -114,6 +110,13 @@ static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
spin_unlock_irqrestore(&ide_lock, flags);
}
+static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ slc90e66_tune_pio(drive, pio);
+ (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
+}
+
static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
{
ide_hwif_t *hwif = HWIF(drive);
@@ -162,8 +165,8 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
}
- slc90e66_tune_drive(drive, slc90e66_dma_2_pio(speed));
- return (ide_config_drive_speed(drive, speed));
+ slc90e66_tune_pio(drive, slc90e66_dma_2_pio(speed));
+ return ide_config_drive_speed(drive, speed);
}
static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
@@ -185,8 +188,7 @@ static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- (void)slc90e66_tune_chipset(drive, XFER_PIO_0 +
- ide_get_best_pio_mode(drive, 255, 4, NULL));
+ slc90e66_tune_drive(drive, 255);
return -1;
}
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 395d35253d5..071a030ec26 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -48,7 +48,7 @@
#include <asm/mediabay.h>
#endif
-#include "ide-timing.h"
+#include "../ide-timing.h"
#undef IDE_PMAC_DEBUG
@@ -1551,19 +1551,34 @@ static struct pci_driver pmac_ide_pci_driver = {
};
MODULE_DEVICE_TABLE(pci, pmac_ide_pci_match);
-void __init
-pmac_ide_probe(void)
+int __init pmac_ide_probe(void)
{
+ int error;
+
if (!machine_is(powermac))
- return;
+ return -ENODEV;
#ifdef CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST
- pci_register_driver(&pmac_ide_pci_driver);
- macio_register_driver(&pmac_ide_macio_driver);
+ error = pci_register_driver(&pmac_ide_pci_driver);
+ if (error)
+ goto out;
+ error = macio_register_driver(&pmac_ide_macio_driver);
+ if (error) {
+ pci_unregister_driver(&pmac_ide_pci_driver);
+ goto out;
+ }
#else
- macio_register_driver(&pmac_ide_macio_driver);
- pci_register_driver(&pmac_ide_pci_driver);
+ error = macio_register_driver(&pmac_ide_macio_driver);
+ if (error)
+ goto out;
+ error = pci_register_driver(&pmac_ide_pci_driver);
+ if (error) {
+ macio_unregister_driver(&pmac_ide_macio_driver);
+ goto out;
+ }
#endif
+out:
+ return error;
}
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
@@ -1983,7 +1998,7 @@ static void pmac_ide_dma_host_off(ide_drive_t *drive)
{
}
-static int pmac_ide_dma_host_on(ide_drive_t *drive)
+static void pmac_ide_dma_host_on(ide_drive_t *drive)
{
}
diff --git a/drivers/ide/ppc/scc_pata.c b/drivers/ide/ppc/scc_pata.c
index de64b022478..f84bf791f72 100644
--- a/drivers/ide/ppc/scc_pata.c
+++ b/drivers/ide/ppc/scc_pata.c
@@ -509,6 +509,32 @@ static int scc_ide_dma_end(ide_drive_t * drive)
return __ide_dma_end(drive);
}
+/* returns 1 if dma irq issued, 0 otherwise */
+static int scc_dma_test_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 dma_stat = hwif->INB(hwif->dma_status);
+
+ /* return 1 if INTR asserted */
+ if ((dma_stat & 4) == 4)
+ return 1;
+
+ /* Workaround for PTERADD: emulate DMA_INTR when
+ * - IDE_STATUS[ERR] = 1
+ * - INT_STATUS[INTRQ] = 1
+ * - DMA_STATUS[IORACTA] = 1
+ */
+ if (in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT &&
+ in_be32((void __iomem *)(hwif->dma_base + 0x014)) & INTSTS_INTRQ &&
+ dma_stat & 1)
+ return 1;
+
+ if (!drive->waiting_for_dma)
+ printk(KERN_WARNING "%s: (%s) called while not waiting\n",
+ drive->name, __FUNCTION__);
+ return 0;
+}
+
/**
* setup_mmio_scc - map CTRL/BMID region
* @dev: PCI device we are configuring
@@ -712,6 +738,7 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif)
hwif->speedproc = scc_tune_chipset;
hwif->tuneproc = scc_tuneproc;
hwif->ide_dma_check = scc_config_drive_for_dma;
+ hwif->ide_dma_test_irq = scc_dma_test_irq;
hwif->drives[0].autotune = IDE_TUNE_AUTO;
hwif->drives[1].autotune = IDE_TUNE_AUTO;
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index d446998b12a..842cd0b53e9 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -88,7 +88,6 @@ struct cm_port {
struct cm_device {
struct list_head list;
struct ib_device *device;
- __be64 ca_guid;
struct cm_port port[0];
};
@@ -739,8 +738,8 @@ retest:
ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT,
- &cm_id_priv->av.port->cm_dev->ca_guid,
- sizeof cm_id_priv->av.port->cm_dev->ca_guid,
+ &cm_id_priv->id.device->node_guid,
+ sizeof cm_id_priv->id.device->node_guid,
NULL, 0);
break;
case IB_CM_REQ_RCVD:
@@ -883,7 +882,7 @@ static void cm_format_req(struct cm_req_msg *req_msg,
req_msg->local_comm_id = cm_id_priv->id.local_id;
req_msg->service_id = param->service_id;
- req_msg->local_ca_guid = cm_id_priv->av.port->cm_dev->ca_guid;
+ req_msg->local_ca_guid = cm_id_priv->id.device->node_guid;
cm_req_set_local_qpn(req_msg, cpu_to_be32(param->qp_num));
cm_req_set_resp_res(req_msg, param->responder_resources);
cm_req_set_init_depth(req_msg, param->initiator_depth);
@@ -1442,7 +1441,7 @@ static void cm_format_rep(struct cm_rep_msg *rep_msg,
cm_rep_set_flow_ctrl(rep_msg, param->flow_control);
cm_rep_set_rnr_retry_count(rep_msg, param->rnr_retry_count);
cm_rep_set_srq(rep_msg, param->srq);
- rep_msg->local_ca_guid = cm_id_priv->av.port->cm_dev->ca_guid;
+ rep_msg->local_ca_guid = cm_id_priv->id.device->node_guid;
if (param->private_data && param->private_data_len)
memcpy(rep_msg->private_data, param->private_data,
@@ -3385,7 +3384,6 @@ static void cm_add_one(struct ib_device *device)
return;
cm_dev->device = device;
- cm_dev->ca_guid = device->node_guid;
set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
for (i = 1; i <= device->phys_port_cnt; i++) {
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index f8d69b3fa30..fde92ce4515 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -77,7 +77,6 @@ static int next_port;
struct cma_device {
struct list_head list;
struct ib_device *device;
- __be64 node_guid;
struct completion comp;
atomic_t refcount;
struct list_head id_list;
@@ -1492,11 +1491,13 @@ static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
ib_addr_get_dgid(addr, &path_rec.dgid);
path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr));
path_rec.numb_path = 1;
+ path_rec.reversible = 1;
id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device,
id_priv->id.port_num, &path_rec,
IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
- IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH,
+ IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH |
+ IB_SA_PATH_REC_REVERSIBLE,
timeout_ms, GFP_KERNEL,
cma_query_handler, work, &id_priv->query);
@@ -1820,7 +1821,7 @@ static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv,
struct rdma_bind_list *bind_list;
int port, ret;
- bind_list = kmalloc(sizeof *bind_list, GFP_KERNEL);
+ bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
if (!bind_list)
return -ENOMEM;
@@ -2672,7 +2673,6 @@ static void cma_add_one(struct ib_device *device)
return;
cma_dev->device = device;
- cma_dev->node_guid = device->node_guid;
init_completion(&cma_dev->comp);
atomic_set(&cma_dev->refcount, 1);
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index b516b93b855..c859134c1da 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -266,7 +266,7 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id,
mutex_lock(&ctx->file->mut);
if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST) {
if (!ctx->backlog) {
- ret = -EDQUOT;
+ ret = -ENOMEM;
kfree(uevent);
goto out;
}
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index df1efbc1088..4fd75afa6a3 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -622,8 +622,10 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
obj->umem.virt_base = cmd.hca_va;
pd = idr_read_pd(cmd.pd_handle, file->ucontext);
- if (!pd)
+ if (!pd) {
+ ret = -EINVAL;
goto err_release;
+ }
mr = pd->device->reg_user_mr(pd, &obj->umem, cmd.access_flags, &udata);
if (IS_ERR(mr)) {
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 8b5dd3649bb..ccdf93d30b0 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -167,7 +167,7 @@ int ib_init_ah_from_wc(struct ib_device *device, u8 port_num, struct ib_wc *wc,
ah_attr->grh.sgid_index = (u8) gid_index;
flow_class = be32_to_cpu(grh->version_tclass_flow);
ah_attr->grh.flow_label = flow_class & 0xFFFFF;
- ah_attr->grh.hop_limit = grh->hop_limit;
+ ah_attr->grh.hop_limit = 0xFF;
ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF;
}
return 0;
diff --git a/drivers/infiniband/hw/cxgb3/Makefile b/drivers/infiniband/hw/cxgb3/Makefile
index 0e110f32f12..36b98989b15 100644
--- a/drivers/infiniband/hw/cxgb3/Makefile
+++ b/drivers/infiniband/hw/cxgb3/Makefile
@@ -8,5 +8,4 @@ iw_cxgb3-y := iwch_cm.o iwch_ev.o iwch_cq.o iwch_qp.o iwch_mem.o \
ifdef CONFIG_INFINIBAND_CXGB3_DEBUG
EXTRA_CFLAGS += -DDEBUG
-iw_cxgb3-y += cxio_dbg.o
endif
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index 114ac3b775d..818cf1aee8c 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -36,6 +36,7 @@
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include "cxio_resource.h"
#include "cxio_hal.h"
@@ -45,7 +46,7 @@
static LIST_HEAD(rdev_list);
static cxio_hal_ev_callback_func_t cxio_ev_cb = NULL;
-static inline struct cxio_rdev *cxio_hal_find_rdev_by_name(char *dev_name)
+static struct cxio_rdev *cxio_hal_find_rdev_by_name(char *dev_name)
{
struct cxio_rdev *rdev;
@@ -55,8 +56,7 @@ static inline struct cxio_rdev *cxio_hal_find_rdev_by_name(char *dev_name)
return NULL;
}
-static inline struct cxio_rdev *cxio_hal_find_rdev_by_t3cdev(struct t3cdev
- *tdev)
+static struct cxio_rdev *cxio_hal_find_rdev_by_t3cdev(struct t3cdev *tdev)
{
struct cxio_rdev *rdev;
@@ -118,7 +118,7 @@ int cxio_hal_cq_op(struct cxio_rdev *rdev_p, struct t3_cq *cq,
return 0;
}
-static inline int cxio_hal_clear_cq_ctx(struct cxio_rdev *rdev_p, u32 cqid)
+static int cxio_hal_clear_cq_ctx(struct cxio_rdev *rdev_p, u32 cqid)
{
struct rdma_cq_setup setup;
setup.id = cqid;
@@ -130,7 +130,7 @@ static inline int cxio_hal_clear_cq_ctx(struct cxio_rdev *rdev_p, u32 cqid)
return (rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_SETUP, &setup));
}
-int cxio_hal_clear_qp_ctx(struct cxio_rdev *rdev_p, u32 qpid)
+static int cxio_hal_clear_qp_ctx(struct cxio_rdev *rdev_p, u32 qpid)
{
u64 sge_cmd;
struct t3_modify_qp_wr *wqe;
@@ -425,7 +425,7 @@ void cxio_flush_hw_cq(struct t3_cq *cq)
}
}
-static inline int cqe_completes_wr(struct t3_cqe *cqe, struct t3_wq *wq)
+static int cqe_completes_wr(struct t3_cqe *cqe, struct t3_wq *wq)
{
if (CQE_OPCODE(*cqe) == T3_TERMINATE)
return 0;
@@ -760,17 +760,6 @@ ret:
return err;
}
-/* IN : stag key, pdid, pbl_size
- * Out: stag index, actaul pbl_size, and pbl_addr allocated.
- */
-int cxio_allocate_stag(struct cxio_rdev *rdev_p, u32 * stag, u32 pdid,
- enum tpt_mem_perm perm, u32 * pbl_size, u32 * pbl_addr)
-{
- *stag = T3_STAG_UNSET;
- return (__cxio_tpt_op(rdev_p, 0, stag, 0, pdid, TPT_NON_SHARED_MR,
- perm, 0, 0ULL, 0, 0, NULL, pbl_size, pbl_addr));
-}
-
int cxio_register_phys_mem(struct cxio_rdev *rdev_p, u32 *stag, u32 pdid,
enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len,
u8 page_size, __be64 *pbl, u32 *pbl_size,
@@ -1029,7 +1018,7 @@ void __exit cxio_hal_exit(void)
cxio_hal_destroy_rhdl_resource();
}
-static inline void flush_completed_wrs(struct t3_wq *wq, struct t3_cq *cq)
+static void flush_completed_wrs(struct t3_wq *wq, struct t3_cq *cq)
{
struct t3_swsq *sqp;
__u32 ptr = wq->sq_rptr;
@@ -1058,9 +1047,8 @@ static inline void flush_completed_wrs(struct t3_wq *wq, struct t3_cq *cq)
break;
}
-static inline void create_read_req_cqe(struct t3_wq *wq,
- struct t3_cqe *hw_cqe,
- struct t3_cqe *read_cqe)
+static void create_read_req_cqe(struct t3_wq *wq, struct t3_cqe *hw_cqe,
+ struct t3_cqe *read_cqe)
{
read_cqe->u.scqe.wrid_hi = wq->oldest_read->sq_wptr;
read_cqe->len = wq->oldest_read->read_len;
@@ -1073,7 +1061,7 @@ static inline void create_read_req_cqe(struct t3_wq *wq,
/*
* Return a ptr to the next read wr in the SWSQ or NULL.
*/
-static inline void advance_oldest_read(struct t3_wq *wq)
+static void advance_oldest_read(struct t3_wq *wq)
{
u32 rptr = wq->oldest_read - wq->sq + 1;
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h
index 8ab04a7c6f6..99543d63470 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h
@@ -143,7 +143,6 @@ int cxio_rdev_open(struct cxio_rdev *rdev);
void cxio_rdev_close(struct cxio_rdev *rdev);
int cxio_hal_cq_op(struct cxio_rdev *rdev, struct t3_cq *cq,
enum t3_cq_opcode op, u32 credit);
-int cxio_hal_clear_qp_ctx(struct cxio_rdev *rdev, u32 qpid);
int cxio_create_cq(struct cxio_rdev *rdev, struct t3_cq *cq);
int cxio_destroy_cq(struct cxio_rdev *rdev, struct t3_cq *cq);
int cxio_resize_cq(struct cxio_rdev *rdev, struct t3_cq *cq);
@@ -154,8 +153,6 @@ int cxio_create_qp(struct cxio_rdev *rdev, u32 kernel_domain, struct t3_wq *wq,
int cxio_destroy_qp(struct cxio_rdev *rdev, struct t3_wq *wq,
struct cxio_ucontext *uctx);
int cxio_peek_cq(struct t3_wq *wr, struct t3_cq *cq, int opcode);
-int cxio_allocate_stag(struct cxio_rdev *rdev, u32 * stag, u32 pdid,
- enum tpt_mem_perm perm, u32 * pbl_size, u32 * pbl_addr);
int cxio_register_phys_mem(struct cxio_rdev *rdev, u32 * stag, u32 pdid,
enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len,
u8 page_size, __be64 *pbl, u32 *pbl_size,
@@ -171,8 +168,6 @@ int cxio_deallocate_window(struct cxio_rdev *rdev, u32 stag);
int cxio_rdma_init(struct cxio_rdev *rdev, struct t3_rdma_init_attr *attr);
void cxio_register_ev_cb(cxio_hal_ev_callback_func_t ev_cb);
void cxio_unregister_ev_cb(cxio_hal_ev_callback_func_t ev_cb);
-u32 cxio_hal_get_rhdl(void);
-void cxio_hal_put_rhdl(u32 rhdl);
u32 cxio_hal_get_pdid(struct cxio_hal_resource *rscp);
void cxio_hal_put_pdid(struct cxio_hal_resource *rscp, u32 pdid);
int __init cxio_hal_init(void);
diff --git a/drivers/infiniband/hw/cxgb3/cxio_resource.c b/drivers/infiniband/hw/cxgb3/cxio_resource.c
index 65bf577311a..d3095ae5bc2 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_resource.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_resource.c
@@ -179,7 +179,7 @@ tpt_err:
/*
* returns 0 if no resource available
*/
-static inline u32 cxio_hal_get_resource(struct kfifo *fifo)
+static u32 cxio_hal_get_resource(struct kfifo *fifo)
{
u32 entry;
if (kfifo_get(fifo, (unsigned char *) &entry, sizeof(u32)))
@@ -188,21 +188,11 @@ static inline u32 cxio_hal_get_resource(struct kfifo *fifo)
return 0; /* fifo emptry */
}
-static inline void cxio_hal_put_resource(struct kfifo *fifo, u32 entry)
+static void cxio_hal_put_resource(struct kfifo *fifo, u32 entry)
{
BUG_ON(kfifo_put(fifo, (unsigned char *) &entry, sizeof(u32)) == 0);
}
-u32 cxio_hal_get_rhdl(void)
-{
- return cxio_hal_get_resource(rhdl_fifo);
-}
-
-void cxio_hal_put_rhdl(u32 rhdl)
-{
- cxio_hal_put_resource(rhdl_fifo, rhdl);
-}
-
u32 cxio_hal_get_stag(struct cxio_hal_resource *rscp)
{
return cxio_hal_get_resource(rscp->tpt_fifo);
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index e5442e34b78..d0ed1d35ca3 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -209,8 +209,7 @@ static enum iwch_ep_state state_read(struct iwch_ep_common *epc)
return state;
}
-static inline void __state_set(struct iwch_ep_common *epc,
- enum iwch_ep_state new)
+static void __state_set(struct iwch_ep_common *epc, enum iwch_ep_state new)
{
epc->state = new;
}
@@ -306,8 +305,7 @@ static int status2errno(int status)
*/
static struct sk_buff *get_skb(struct sk_buff *skb, int len, gfp_t gfp)
{
- if (skb) {
- BUG_ON(skb_cloned(skb));
+ if (skb && !skb_is_nonlinear(skb) && !skb_cloned(skb)) {
skb_trim(skb, 0);
skb_get(skb);
} else {
@@ -1416,6 +1414,7 @@ static int peer_close(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
wake_up(&ep->com.waitq);
break;
case FPDU_MODE:
+ start_ep_timer(ep);
__state_set(&ep->com, CLOSING);
attrs.next_state = IWCH_QP_STATE_CLOSING;
iwch_modify_qp(ep->com.qp->rhp, ep->com.qp,
@@ -1426,7 +1425,6 @@ static int peer_close(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
disconnect = 0;
break;
case CLOSING:
- start_ep_timer(ep);
__state_set(&ep->com, MORIBUND);
disconnect = 0;
break;
@@ -1459,7 +1457,7 @@ static int peer_close(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
/*
* Returns whether an ABORT_REQ_RSS message is a negative advice.
*/
-static inline int is_neg_adv_abort(unsigned int status)
+static int is_neg_adv_abort(unsigned int status)
{
return status == CPL_ERR_RTX_NEG_ADVICE ||
status == CPL_ERR_PERSIST_NEG_ADVICE;
@@ -1488,8 +1486,10 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
case CONNECTING:
break;
case MPA_REQ_WAIT:
+ stop_ep_timer(ep);
break;
case MPA_REQ_SENT:
+ stop_ep_timer(ep);
connect_reply_upcall(ep, -ECONNRESET);
break;
case MPA_REP_SENT:
@@ -1508,9 +1508,10 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
get_ep(&ep->com);
break;
case MORIBUND:
+ case CLOSING:
stop_ep_timer(ep);
+ /*FALLTHROUGH*/
case FPDU_MODE:
- case CLOSING:
if (ep->com.cm_id && ep->com.qp) {
attrs.next_state = IWCH_QP_STATE_ERROR;
ret = iwch_modify_qp(ep->com.qp->rhp,
@@ -1571,7 +1572,6 @@ static int close_con_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
spin_lock_irqsave(&ep->com.lock, flags);
switch (ep->com.state) {
case CLOSING:
- start_ep_timer(ep);
__state_set(&ep->com, MORIBUND);
break;
case MORIBUND:
@@ -1587,6 +1587,8 @@ static int close_con_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
__state_set(&ep->com, DEAD);
release = 1;
break;
+ case ABORTING:
+ break;
case DEAD:
default:
BUG_ON(1);
@@ -1635,6 +1637,7 @@ static int ec_status(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
printk(KERN_ERR MOD "%s BAD CLOSE - Aborting tid %u\n",
__FUNCTION__, ep->hwtid);
+ stop_ep_timer(ep);
attrs.next_state = IWCH_QP_STATE_ERROR;
iwch_modify_qp(ep->com.qp->rhp,
ep->com.qp, IWCH_QP_ATTR_NEXT_STATE,
@@ -1659,6 +1662,7 @@ static void ep_timeout(unsigned long arg)
break;
case MPA_REQ_WAIT:
break;
+ case CLOSING:
case MORIBUND:
if (ep->com.cm_id && ep->com.qp) {
attrs.next_state = IWCH_QP_STATE_ERROR;
@@ -1687,12 +1691,11 @@ int iwch_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
return -ECONNRESET;
}
BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD);
- state_set(&ep->com, CLOSING);
if (mpa_rev == 0)
abort_connection(ep, NULL, GFP_KERNEL);
else {
err = send_mpa_reject(ep, pdata, pdata_len);
- err = send_halfclose(ep, GFP_KERNEL);
+ err = iwch_ep_disconnect(ep, 0, GFP_KERNEL);
}
return 0;
}
@@ -1957,11 +1960,11 @@ int iwch_ep_disconnect(struct iwch_ep *ep, int abrupt, gfp_t gfp)
case MPA_REQ_RCVD:
case MPA_REP_SENT:
case FPDU_MODE:
+ start_ep_timer(ep);
ep->com.state = CLOSING;
close = 1;
break;
case CLOSING:
- start_ep_timer(ep);
ep->com.state = MORIBUND;
close = 1;
break;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_ev.c b/drivers/infiniband/hw/cxgb3/iwch_ev.c
index 54362afbf72..b40676662a8 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_ev.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_ev.c
@@ -47,12 +47,6 @@ static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp,
struct iwch_qp_attributes attrs;
struct iwch_qp *qhp;
- printk(KERN_ERR "%s - AE qpid 0x%x opcode %d status 0x%x "
- "type %d wrid.hi 0x%x wrid.lo 0x%x \n", __FUNCTION__,
- CQE_QPID(rsp_msg->cqe), CQE_OPCODE(rsp_msg->cqe),
- CQE_STATUS(rsp_msg->cqe), CQE_TYPE(rsp_msg->cqe),
- CQE_WRID_HI(rsp_msg->cqe), CQE_WRID_LOW(rsp_msg->cqe));
-
spin_lock(&rnicp->lock);
qhp = get_qhp(rnicp, CQE_QPID(rsp_msg->cqe));
@@ -73,6 +67,12 @@ static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp,
return;
}
+ printk(KERN_ERR "%s - AE qpid 0x%x opcode %d status 0x%x "
+ "type %d wrid.hi 0x%x wrid.lo 0x%x \n", __FUNCTION__,
+ CQE_QPID(rsp_msg->cqe), CQE_OPCODE(rsp_msg->cqe),
+ CQE_STATUS(rsp_msg->cqe), CQE_TYPE(rsp_msg->cqe),
+ CQE_WRID_HI(rsp_msg->cqe), CQE_WRID_LOW(rsp_msg->cqe));
+
atomic_inc(&qhp->refcnt);
spin_unlock(&rnicp->lock);
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index 2aef122f995..f2774ae906b 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -331,6 +331,7 @@ static int iwch_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
int ret = 0;
struct iwch_mm_entry *mm;
struct iwch_ucontext *ucontext;
+ u64 addr;
PDBG("%s pgoff 0x%lx key 0x%x len %d\n", __FUNCTION__, vma->vm_pgoff,
key, len);
@@ -345,10 +346,11 @@ static int iwch_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
mm = remove_mmap(ucontext, key, len);
if (!mm)
return -EINVAL;
+ addr = mm->addr;
kfree(mm);
- if ((mm->addr >= rdev_p->rnic_info.udbell_physbase) &&
- (mm->addr < (rdev_p->rnic_info.udbell_physbase +
+ if ((addr >= rdev_p->rnic_info.udbell_physbase) &&
+ (addr < (rdev_p->rnic_info.udbell_physbase +
rdev_p->rnic_info.udbell_len))) {
/*
@@ -362,7 +364,7 @@ static int iwch_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND;
vma->vm_flags &= ~VM_MAYREAD;
ret = io_remap_pfn_range(vma, vma->vm_start,
- mm->addr >> PAGE_SHIFT,
+ addr >> PAGE_SHIFT,
len, vma->vm_page_prot);
} else {
@@ -370,7 +372,7 @@ static int iwch_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
* Map WQ or CQ contig dma memory...
*/
ret = remap_pfn_range(vma, vma->vm_start,
- mm->addr >> PAGE_SHIFT,
+ addr >> PAGE_SHIFT,
len, vma->vm_page_prot);
}
@@ -463,9 +465,6 @@ static struct ib_mr *iwch_register_phys_mem(struct ib_pd *pd,
php = to_iwch_pd(pd);
rhp = php->rhp;
- acc = iwch_convert_access(acc);
-
-
mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
if (!mhp)
return ERR_PTR(-ENOMEM);
@@ -491,12 +490,7 @@ static struct ib_mr *iwch_register_phys_mem(struct ib_pd *pd,
mhp->attr.pdid = php->pdid;
mhp->attr.zbva = 0;
- /* NOTE: TPT perms are backwards from BIND WR perms! */
- mhp->attr.perms = (acc & 0x1) << 3;
- mhp->attr.perms |= (acc & 0x2) << 1;
- mhp->attr.perms |= (acc & 0x4) >> 1;
- mhp->attr.perms |= (acc & 0x8) >> 3;
-
+ mhp->attr.perms = iwch_ib_to_tpt_access(acc);
mhp->attr.va_fbo = *iova_start;
mhp->attr.page_size = shift - 12;
@@ -525,7 +519,6 @@ static int iwch_reregister_phys_mem(struct ib_mr *mr,
struct iwch_mr mh, *mhp;
struct iwch_pd *php;
struct iwch_dev *rhp;
- int new_acc;
__be64 *page_list = NULL;
int shift = 0;
u64 total_size;
@@ -546,14 +539,12 @@ static int iwch_reregister_phys_mem(struct ib_mr *mr,
if (rhp != php->rhp)
return -EINVAL;
- new_acc = mhp->attr.perms;
-
memcpy(&mh, mhp, sizeof *mhp);
if (mr_rereg_mask & IB_MR_REREG_PD)
php = to_iwch_pd(pd);
if (mr_rereg_mask & IB_MR_REREG_ACCESS)
- mh.attr.perms = iwch_convert_access(acc);
+ mh.attr.perms = iwch_ib_to_tpt_access(acc);
if (mr_rereg_mask & IB_MR_REREG_TRANS)
ret = build_phys_page_list(buffer_list, num_phys_buf,
iova_start,
@@ -568,7 +559,7 @@ static int iwch_reregister_phys_mem(struct ib_mr *mr,
if (mr_rereg_mask & IB_MR_REREG_PD)
mhp->attr.pdid = php->pdid;
if (mr_rereg_mask & IB_MR_REREG_ACCESS)
- mhp->attr.perms = acc;
+ mhp->attr.perms = iwch_ib_to_tpt_access(acc);
if (mr_rereg_mask & IB_MR_REREG_TRANS) {
mhp->attr.zbva = 0;
mhp->attr.va_fbo = *iova_start;
@@ -613,8 +604,6 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
goto err;
}
- acc = iwch_convert_access(acc);
-
i = n = 0;
list_for_each_entry(chunk, &region->chunk_list, list)
@@ -630,10 +619,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
mhp->rhp = rhp;
mhp->attr.pdid = php->pdid;
mhp->attr.zbva = 0;
- mhp->attr.perms = (acc & 0x1) << 3;
- mhp->attr.perms |= (acc & 0x2) << 1;
- mhp->attr.perms |= (acc & 0x4) >> 1;
- mhp->attr.perms |= (acc & 0x8) >> 3;
+ mhp->attr.perms = iwch_ib_to_tpt_access(acc);
mhp->attr.va_fbo = region->virt_base;
mhp->attr.page_size = shift - 12;
mhp->attr.len = (u32) region->length;
@@ -736,10 +722,8 @@ static int iwch_destroy_qp(struct ib_qp *ib_qp)
qhp = to_iwch_qp(ib_qp);
rhp = qhp->rhp;
- if (qhp->attr.state == IWCH_QP_STATE_RTS) {
- attrs.next_state = IWCH_QP_STATE_ERROR;
- iwch_modify_qp(rhp, qhp, IWCH_QP_ATTR_NEXT_STATE, &attrs, 0);
- }
+ attrs.next_state = IWCH_QP_STATE_ERROR;
+ iwch_modify_qp(rhp, qhp, IWCH_QP_ATTR_NEXT_STATE, &attrs, 0);
wait_event(qhp->wait, !qhp->ep);
remove_handle(rhp, &rhp->qpidr, qhp->wq.qpid);
@@ -948,7 +932,7 @@ void iwch_qp_rem_ref(struct ib_qp *qp)
wake_up(&(to_iwch_qp(qp)->wait));
}
-struct ib_qp *iwch_get_qp(struct ib_device *dev, int qpn)
+static struct ib_qp *iwch_get_qp(struct ib_device *dev, int qpn)
{
PDBG("%s ib_dev %p qpn 0x%x\n", __FUNCTION__, dev, qpn);
return (struct ib_qp *)get_qhp(to_iwch_dev(dev), qpn);
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h
index 2af3e93b607..93bcc56756b 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.h
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h
@@ -178,7 +178,6 @@ static inline struct iwch_qp *to_iwch_qp(struct ib_qp *ibqp)
void iwch_qp_add_ref(struct ib_qp *qp);
void iwch_qp_rem_ref(struct ib_qp *qp);
-struct ib_qp *iwch_get_qp(struct ib_device *dev, int qpn);
struct iwch_ucontext {
struct ib_ucontext ibucontext;
@@ -287,27 +286,20 @@ static inline int iwch_convert_state(enum ib_qp_state ib_state)
}
}
-enum iwch_mem_perms {
- IWCH_MEM_ACCESS_LOCAL_READ = 1 << 0,
- IWCH_MEM_ACCESS_LOCAL_WRITE = 1 << 1,
- IWCH_MEM_ACCESS_REMOTE_READ = 1 << 2,
- IWCH_MEM_ACCESS_REMOTE_WRITE = 1 << 3,
- IWCH_MEM_ACCESS_ATOMICS = 1 << 4,
- IWCH_MEM_ACCESS_BINDING = 1 << 5,
- IWCH_MEM_ACCESS_LOCAL =
- (IWCH_MEM_ACCESS_LOCAL_READ | IWCH_MEM_ACCESS_LOCAL_WRITE),
- IWCH_MEM_ACCESS_REMOTE =
- (IWCH_MEM_ACCESS_REMOTE_WRITE | IWCH_MEM_ACCESS_REMOTE_READ)
- /* cannot go beyond 1 << 31 */
-} __attribute__ ((packed));
-
-static inline u32 iwch_convert_access(int acc)
+static inline u32 iwch_ib_to_tpt_access(int acc)
{
- return (acc & IB_ACCESS_REMOTE_WRITE ? IWCH_MEM_ACCESS_REMOTE_WRITE : 0)
- | (acc & IB_ACCESS_REMOTE_READ ? IWCH_MEM_ACCESS_REMOTE_READ : 0) |
- (acc & IB_ACCESS_LOCAL_WRITE ? IWCH_MEM_ACCESS_LOCAL_WRITE : 0) |
- (acc & IB_ACCESS_MW_BIND ? IWCH_MEM_ACCESS_BINDING : 0) |
- IWCH_MEM_ACCESS_LOCAL_READ;
+ return (acc & IB_ACCESS_REMOTE_WRITE ? TPT_REMOTE_WRITE : 0) |
+ (acc & IB_ACCESS_REMOTE_READ ? TPT_REMOTE_READ : 0) |
+ (acc & IB_ACCESS_LOCAL_WRITE ? TPT_LOCAL_WRITE : 0) |
+ TPT_LOCAL_READ;
+}
+
+static inline u32 iwch_ib_to_mwbind_access(int acc)
+{
+ return (acc & IB_ACCESS_REMOTE_WRITE ? T3_MEM_ACCESS_REM_WRITE : 0) |
+ (acc & IB_ACCESS_REMOTE_READ ? T3_MEM_ACCESS_REM_READ : 0) |
+ (acc & IB_ACCESS_LOCAL_WRITE ? T3_MEM_ACCESS_LOCAL_WRITE : 0) |
+ T3_MEM_ACCESS_LOCAL_READ;
}
enum iwch_mmid_state {
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index 4dda2f6da2d..0a472c9b44d 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -36,8 +36,8 @@
#define NO_SUPPORT -1
-static inline int iwch_build_rdma_send(union t3_wr *wqe, struct ib_send_wr *wr,
- u8 * flit_cnt)
+static int iwch_build_rdma_send(union t3_wr *wqe, struct ib_send_wr *wr,
+ u8 * flit_cnt)
{
int i;
u32 plen;
@@ -96,8 +96,8 @@ static inline int iwch_build_rdma_send(union t3_wr *wqe, struct ib_send_wr *wr,
return 0;
}
-static inline int iwch_build_rdma_write(union t3_wr *wqe, struct ib_send_wr *wr,
- u8 *flit_cnt)
+static int iwch_build_rdma_write(union t3_wr *wqe, struct ib_send_wr *wr,
+ u8 *flit_cnt)
{
int i;
u32 plen;
@@ -137,8 +137,8 @@ static inline int iwch_build_rdma_write(union t3_wr *wqe, struct ib_send_wr *wr,
return 0;
}
-static inline int iwch_build_rdma_read(union t3_wr *wqe, struct ib_send_wr *wr,
- u8 *flit_cnt)
+static int iwch_build_rdma_read(union t3_wr *wqe, struct ib_send_wr *wr,
+ u8 *flit_cnt)
{
if (wr->num_sge > 1)
return -EINVAL;
@@ -158,9 +158,8 @@ static inline int iwch_build_rdma_read(union t3_wr *wqe, struct ib_send_wr *wr,
/*
* TBD: this is going to be moved to firmware. Missing pdid/qpid check for now.
*/
-static inline int iwch_sgl2pbl_map(struct iwch_dev *rhp,
- struct ib_sge *sg_list, u32 num_sgle,
- u32 * pbl_addr, u8 * page_size)
+static int iwch_sgl2pbl_map(struct iwch_dev *rhp, struct ib_sge *sg_list,
+ u32 num_sgle, u32 * pbl_addr, u8 * page_size)
{
int i;
struct iwch_mr *mhp;
@@ -206,9 +205,8 @@ static inline int iwch_sgl2pbl_map(struct iwch_dev *rhp,
return 0;
}
-static inline int iwch_build_rdma_recv(struct iwch_dev *rhp,
- union t3_wr *wqe,
- struct ib_recv_wr *wr)
+static int iwch_build_rdma_recv(struct iwch_dev *rhp, union t3_wr *wqe,
+ struct ib_recv_wr *wr)
{
int i, err = 0;
u32 pbl_addr[4];
@@ -441,7 +439,7 @@ int iwch_bind_mw(struct ib_qp *qp,
wqe->bind.type = T3_VA_BASED_TO;
/* TBD: check perms */
- wqe->bind.perms = iwch_convert_access(mw_bind->mw_access_flags);
+ wqe->bind.perms = iwch_ib_to_mwbind_access(mw_bind->mw_access_flags);
wqe->bind.mr_stag = cpu_to_be32(mw_bind->mr->lkey);
wqe->bind.mw_stag = cpu_to_be32(mw->rkey);
wqe->bind.mw_len = cpu_to_be32(mw_bind->length);
@@ -473,8 +471,7 @@ int iwch_bind_mw(struct ib_qp *qp,
return err;
}
-static inline void build_term_codes(int t3err, u8 *layer_type, u8 *ecode,
- int tagged)
+static void build_term_codes(int t3err, u8 *layer_type, u8 *ecode, int tagged)
{
switch (t3err) {
case TPT_ERR_STAG:
@@ -672,7 +669,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
spin_lock_irqsave(&qhp->lock, *flag);
}
-static inline void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
+static void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
{
if (t3b_device(qhp->rhp))
cxio_set_wq_in_error(&qhp->wq);
@@ -684,7 +681,7 @@ static inline void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
/*
* Return non zero if at least one RECV was pre-posted.
*/
-static inline int rqes_posted(struct iwch_qp *qhp)
+static int rqes_posted(struct iwch_qp *qhp)
{
return fw_riwrh_opcode((struct fw_riwrh *)qhp->wq.queue) == T3_WR_RCV;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 40404c9e281..82ded44c6ce 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -52,6 +52,8 @@ struct ehca_mw;
struct ehca_pd;
struct ehca_av;
+#include <linux/wait.h>
+
#include <rdma/ib_verbs.h>
#include <rdma/ib_user_verbs.h>
@@ -153,7 +155,9 @@ struct ehca_cq {
spinlock_t cb_lock;
struct hlist_head qp_hashtab[QP_HASHTAB_LEN];
struct list_head entry;
- u32 nr_callbacks;
+ u32 nr_callbacks; /* #events assigned to cpu by scaling code */
+ u32 nr_events; /* #events seen */
+ wait_queue_head_t wait_completion;
spinlock_t task_lock;
u32 ownpid;
/* mmap counter for resources mapped into user space */
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index 6ebfa27e4e1..e2cdc1a16fe 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -146,6 +146,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
spin_lock_init(&my_cq->spinlock);
spin_lock_init(&my_cq->cb_lock);
spin_lock_init(&my_cq->task_lock);
+ init_waitqueue_head(&my_cq->wait_completion);
my_cq->ownpid = current->tgid;
cq = &my_cq->ib_cq;
@@ -302,6 +303,16 @@ create_cq_exit1:
return cq;
}
+static int get_cq_nr_events(struct ehca_cq *my_cq)
+{
+ int ret;
+ unsigned long flags;
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ ret = my_cq->nr_events;
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+ return ret;
+}
+
int ehca_destroy_cq(struct ib_cq *cq)
{
u64 h_ret;
@@ -329,10 +340,11 @@ int ehca_destroy_cq(struct ib_cq *cq)
}
spin_lock_irqsave(&ehca_cq_idr_lock, flags);
- while (my_cq->nr_callbacks) {
+ while (my_cq->nr_events) {
spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
- yield();
+ wait_event(my_cq->wait_completion, !get_cq_nr_events(my_cq));
spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ /* recheck nr_events to assure no cqe has just arrived */
}
idr_remove(&ehca_cq_idr, my_cq->token);
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index 3ec53c687d0..20f36bf8b2b 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -404,10 +404,11 @@ static inline void process_eqe(struct ehca_shca *shca, struct ehca_eqe *eqe)
u32 token;
unsigned long flags;
struct ehca_cq *cq;
+
eqe_value = eqe->entry;
ehca_dbg(&shca->ib_device, "eqe_value=%lx", eqe_value);
if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, eqe_value)) {
- ehca_dbg(&shca->ib_device, "... completion event");
+ ehca_dbg(&shca->ib_device, "Got completion event");
token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe_value);
spin_lock_irqsave(&ehca_cq_idr_lock, flags);
cq = idr_find(&ehca_cq_idr, token);
@@ -419,16 +420,20 @@ static inline void process_eqe(struct ehca_shca *shca, struct ehca_eqe *eqe)
return;
}
reset_eq_pending(cq);
- if (ehca_scaling_code) {
+ cq->nr_events++;
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+ if (ehca_scaling_code)
queue_comp_task(cq);
- spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
- } else {
- spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+ else {
comp_event_callback(cq);
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ cq->nr_events--;
+ if (!cq->nr_events)
+ wake_up(&cq->wait_completion);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
}
} else {
- ehca_dbg(&shca->ib_device,
- "Got non completion event");
+ ehca_dbg(&shca->ib_device, "Got non completion event");
parse_identifier(shca, eqe_value);
}
}
@@ -478,6 +483,7 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq)
"token=%x", token);
continue;
}
+ eqe_cache[eqe_cnt].cq->nr_events++;
spin_unlock(&ehca_cq_idr_lock);
} else
eqe_cache[eqe_cnt].cq = NULL;
@@ -504,12 +510,18 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq)
/* call completion handler for cached eqes */
for (i = 0; i < eqe_cnt; i++)
if (eq->eqe_cache[i].cq) {
- if (ehca_scaling_code) {
- spin_lock(&ehca_cq_idr_lock);
+ if (ehca_scaling_code)
queue_comp_task(eq->eqe_cache[i].cq);
- spin_unlock(&ehca_cq_idr_lock);
- } else
- comp_event_callback(eq->eqe_cache[i].cq);
+ else {
+ struct ehca_cq *cq = eq->eqe_cache[i].cq;
+ comp_event_callback(cq);
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ cq->nr_events--;
+ if (!cq->nr_events)
+ wake_up(&cq->wait_completion);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock,
+ flags);
+ }
} else {
ehca_dbg(&shca->ib_device, "Got non completion event");
parse_identifier(shca, eq->eqe_cache[i].eqe->entry);
@@ -523,7 +535,6 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq)
if (!eqe)
break;
process_eqe(shca, eqe);
- eqe_cnt++;
} while (1);
unlock_irq_spinlock:
@@ -567,8 +578,7 @@ static void __queue_comp_task(struct ehca_cq *__cq,
list_add_tail(&__cq->entry, &cct->cq_list);
cct->cq_jobs++;
wake_up(&cct->wait_queue);
- }
- else
+ } else
__cq->nr_callbacks++;
spin_unlock(&__cq->task_lock);
@@ -577,18 +587,21 @@ static void __queue_comp_task(struct ehca_cq *__cq,
static void queue_comp_task(struct ehca_cq *__cq)
{
- int cpu;
int cpu_id;
struct ehca_cpu_comp_task *cct;
+ int cq_jobs;
+ unsigned long flags;
- cpu = get_cpu();
cpu_id = find_next_online_cpu(pool);
BUG_ON(!cpu_online(cpu_id));
cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id);
BUG_ON(!cct);
- if (cct->cq_jobs > 0) {
+ spin_lock_irqsave(&cct->task_lock, flags);
+ cq_jobs = cct->cq_jobs;
+ spin_unlock_irqrestore(&cct->task_lock, flags);
+ if (cq_jobs > 0) {
cpu_id = find_next_online_cpu(pool);
cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id);
BUG_ON(!cct);
@@ -608,11 +621,17 @@ static void run_comp_task(struct ehca_cpu_comp_task* cct)
cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
spin_unlock_irqrestore(&cct->task_lock, flags);
comp_event_callback(cq);
- spin_lock_irqsave(&cct->task_lock, flags);
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ cq->nr_events--;
+ if (!cq->nr_events)
+ wake_up(&cq->wait_completion);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+ spin_lock_irqsave(&cct->task_lock, flags);
spin_lock(&cq->task_lock);
cq->nr_callbacks--;
- if (cq->nr_callbacks == 0) {
+ if (!cq->nr_callbacks) {
list_del_init(cct->cq_list.next);
cct->cq_jobs--;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index c1835121a82..059da9628bb 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -52,7 +52,7 @@
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");
-MODULE_VERSION("SVNEHCA_0021");
+MODULE_VERSION("SVNEHCA_0022");
int ehca_open_aqp1 = 0;
int ehca_debug_level = 0;
@@ -810,7 +810,7 @@ int __init ehca_module_init(void)
int ret;
printk(KERN_INFO "eHCA Infiniband Device Driver "
- "(Rel.: SVNEHCA_0021)\n");
+ "(Rel.: SVNEHCA_0022)\n");
idr_init(&ehca_qp_idr);
idr_init(&ehca_cq_idr);
spin_lock_init(&ehca_qp_idr_lock);
diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c
index 6037dd3f87d..8e4846b5c64 100644
--- a/drivers/infiniband/hw/mthca/mthca_mr.c
+++ b/drivers/infiniband/hw/mthca/mthca_mr.c
@@ -310,8 +310,9 @@ int mthca_write_mtt_size(struct mthca_dev *dev)
return mthca_is_memfree(dev) ? (PAGE_SIZE / sizeof (u64)) : 0x7ffffff;
}
-void mthca_tavor_write_mtt_seg(struct mthca_dev *dev, struct mthca_mtt *mtt,
- int start_index, u64 *buffer_list, int list_len)
+static void mthca_tavor_write_mtt_seg(struct mthca_dev *dev,
+ struct mthca_mtt *mtt, int start_index,
+ u64 *buffer_list, int list_len)
{
u64 __iomem *mtts;
int i;
@@ -323,8 +324,9 @@ void mthca_tavor_write_mtt_seg(struct mthca_dev *dev, struct mthca_mtt *mtt,
mtts + i);
}
-void mthca_arbel_write_mtt_seg(struct mthca_dev *dev, struct mthca_mtt *mtt,
- int start_index, u64 *buffer_list, int list_len)
+static void mthca_arbel_write_mtt_seg(struct mthca_dev *dev,
+ struct mthca_mtt *mtt, int start_index,
+ u64 *buffer_list, int list_len)
{
__be64 *mtts;
dma_addr_t dma_handle;
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 71dc84bd425..1c6b63aca26 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -1088,21 +1088,21 @@ static void mthca_unmap_memfree(struct mthca_dev *dev,
static int mthca_alloc_memfree(struct mthca_dev *dev,
struct mthca_qp *qp)
{
- int ret = 0;
-
if (mthca_is_memfree(dev)) {
qp->rq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_RQ,
qp->qpn, &qp->rq.db);
if (qp->rq.db_index < 0)
- return ret;
+ return -ENOMEM;
qp->sq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_SQ,
qp->qpn, &qp->sq.db);
- if (qp->sq.db_index < 0)
+ if (qp->sq.db_index < 0) {
mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
+ return -ENOMEM;
+ }
}
- return ret;
+ return 0;
}
static void mthca_free_memfree(struct mthca_dev *dev,
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 2594db2030b..fd558267d1c 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -219,7 +219,6 @@ struct ipoib_dev_priv {
union ib_gid local_gid;
u16 local_lid;
- u8 local_rate;
unsigned int admin_mtu;
unsigned int mcast_mtu;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 4d59682f7d4..3484e8ba24a 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -65,14 +65,14 @@ struct ipoib_cm_id {
static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id,
struct ib_cm_event *event);
-static void ipoib_cm_dma_unmap_rx(struct ipoib_dev_priv *priv,
+static void ipoib_cm_dma_unmap_rx(struct ipoib_dev_priv *priv, int frags,
u64 mapping[IPOIB_CM_RX_SG])
{
int i;
ib_dma_unmap_single(priv->ca, mapping[0], IPOIB_CM_HEAD_SIZE, DMA_FROM_DEVICE);
- for (i = 0; i < IPOIB_CM_RX_SG - 1; ++i)
+ for (i = 0; i < frags; ++i)
ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE);
}
@@ -90,7 +90,8 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id)
ret = ib_post_srq_recv(priv->cm.srq, &priv->cm.rx_wr, &bad_wr);
if (unlikely(ret)) {
ipoib_warn(priv, "post srq failed for buf %d (%d)\n", id, ret);
- ipoib_cm_dma_unmap_rx(priv, priv->cm.srq_ring[id].mapping);
+ ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
+ priv->cm.srq_ring[id].mapping);
dev_kfree_skb_any(priv->cm.srq_ring[id].skb);
priv->cm.srq_ring[id].skb = NULL;
}
@@ -98,8 +99,8 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id)
return ret;
}
-static int ipoib_cm_alloc_rx_skb(struct net_device *dev, int id,
- u64 mapping[IPOIB_CM_RX_SG])
+static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, int frags,
+ u64 mapping[IPOIB_CM_RX_SG])
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct sk_buff *skb;
@@ -107,7 +108,7 @@ static int ipoib_cm_alloc_rx_skb(struct net_device *dev, int id,
skb = dev_alloc_skb(IPOIB_CM_HEAD_SIZE + 12);
if (unlikely(!skb))
- return -ENOMEM;
+ return NULL;
/*
* IPoIB adds a 4 byte header. So we need 12 more bytes to align the
@@ -119,10 +120,10 @@ static int ipoib_cm_alloc_rx_skb(struct net_device *dev, int id,
DMA_FROM_DEVICE);
if (unlikely(ib_dma_mapping_error(priv->ca, mapping[0]))) {
dev_kfree_skb_any(skb);
- return -EIO;
+ return NULL;
}
- for (i = 0; i < IPOIB_CM_RX_SG - 1; i++) {
+ for (i = 0; i < frags; i++) {
struct page *page = alloc_page(GFP_ATOMIC);
if (!page)
@@ -136,7 +137,7 @@ static int ipoib_cm_alloc_rx_skb(struct net_device *dev, int id,
}
priv->cm.srq_ring[id].skb = skb;
- return 0;
+ return skb;
partial_error:
@@ -146,7 +147,7 @@ partial_error:
ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
- return -ENOMEM;
+ return NULL;
}
static struct ib_qp *ipoib_cm_create_rx_qp(struct net_device *dev,
@@ -309,7 +310,7 @@ static int ipoib_cm_rx_handler(struct ib_cm_id *cm_id,
}
/* Adjust length of skb with fragments to match received data */
static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
- unsigned int length)
+ unsigned int length, struct sk_buff *toskb)
{
int i, num_frags;
unsigned int size;
@@ -326,7 +327,7 @@ static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
if (length == 0) {
/* don't need this page */
- __free_page(frag->page);
+ skb_fill_page_desc(toskb, i, frag->page, 0, PAGE_SIZE);
--skb_shinfo(skb)->nr_frags;
} else {
size = min(length, (unsigned) PAGE_SIZE);
@@ -344,10 +345,11 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
unsigned int wr_id = wc->wr_id & ~IPOIB_CM_OP_SRQ;
- struct sk_buff *skb;
+ struct sk_buff *skb, *newskb;
struct ipoib_cm_rx *p;
unsigned long flags;
u64 mapping[IPOIB_CM_RX_SG];
+ int frags;
ipoib_dbg_data(priv, "cm recv completion: id %d, op %d, status: %d\n",
wr_id, wc->opcode, wc->status);
@@ -383,7 +385,11 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
}
}
- if (unlikely(ipoib_cm_alloc_rx_skb(dev, wr_id, mapping))) {
+ frags = PAGE_ALIGN(wc->byte_len - min(wc->byte_len,
+ (unsigned)IPOIB_CM_HEAD_SIZE)) / PAGE_SIZE;
+
+ newskb = ipoib_cm_alloc_rx_skb(dev, wr_id, frags, mapping);
+ if (unlikely(!newskb)) {
/*
* If we can't allocate a new RX buffer, dump
* this packet and reuse the old buffer.
@@ -393,13 +399,13 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
goto repost;
}
- ipoib_cm_dma_unmap_rx(priv, priv->cm.srq_ring[wr_id].mapping);
- memcpy(priv->cm.srq_ring[wr_id].mapping, mapping, sizeof mapping);
+ ipoib_cm_dma_unmap_rx(priv, frags, priv->cm.srq_ring[wr_id].mapping);
+ memcpy(priv->cm.srq_ring[wr_id].mapping, mapping, (frags + 1) * sizeof *mapping);
ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n",
wc->byte_len, wc->slid);
- skb_put_frags(skb, IPOIB_CM_HEAD_SIZE, wc->byte_len);
+ skb_put_frags(skb, IPOIB_CM_HEAD_SIZE, wc->byte_len, newskb);
skb->protocol = ((struct ipoib_header *) skb->data)->proto;
skb->mac.raw = skb->data;
@@ -1193,7 +1199,8 @@ int ipoib_cm_dev_init(struct net_device *dev)
priv->cm.rx_wr.num_sge = IPOIB_CM_RX_SG;
for (i = 0; i < ipoib_recvq_size; ++i) {
- if (ipoib_cm_alloc_rx_skb(dev, i, priv->cm.srq_ring[i].mapping)) {
+ if (!ipoib_cm_alloc_rx_skb(dev, i, IPOIB_CM_RX_SG - 1,
+ priv->cm.srq_ring[i].mapping)) {
ipoib_warn(priv, "failed to allocate receive buffer %d\n", i);
ipoib_cm_dev_cleanup(dev);
return -ENOMEM;
@@ -1228,7 +1235,8 @@ void ipoib_cm_dev_cleanup(struct net_device *dev)
return;
for (i = 0; i < ipoib_recvq_size; ++i)
if (priv->cm.srq_ring[i].skb) {
- ipoib_cm_dma_unmap_rx(priv, priv->cm.srq_ring[i].mapping);
+ ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
+ priv->cm.srq_ring[i].mapping);
dev_kfree_skb_any(priv->cm.srq_ring[i].skb);
priv->cm.srq_ring[i].skb = NULL;
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 18d27fd352a..f9dbc6f6814 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -385,7 +385,7 @@ static void path_rec_completion(int status,
struct sk_buff *skb;
unsigned long flags;
- if (pathrec)
+ if (!status)
ipoib_dbg(priv, "PathRec LID 0x%04x for GID " IPOIB_GID_FMT "\n",
be16_to_cpu(pathrec->dlid), IPOIB_GID_ARG(pathrec->dgid));
else
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index b303ce6bc21..56c87a81bb6 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -407,6 +407,10 @@ static int ipoib_mcast_join_complete(int status,
queue_delayed_work(ipoib_workqueue,
&priv->mcast_task, 0);
mutex_unlock(&mcast_mutex);
+
+ if (mcast == priv->broadcast)
+ netif_carrier_on(dev);
+
return 0;
}
@@ -527,11 +531,9 @@ void ipoib_mcast_join_task(struct work_struct *work)
{
struct ib_port_attr attr;
- if (!ib_query_port(priv->ca, priv->port, &attr)) {
- priv->local_lid = attr.lid;
- priv->local_rate = attr.active_speed *
- ib_width_enum_to_int(attr.active_width);
- } else
+ if (!ib_query_port(priv->ca, priv->port, &attr))
+ priv->local_lid = attr.lid;
+ else
ipoib_warn(priv, "ib_query_port failed\n");
}
@@ -596,7 +598,6 @@ void ipoib_mcast_join_task(struct work_struct *work)
ipoib_dbg_mcast(priv, "successfully joined all multicast groups\n");
clear_bit(IPOIB_MCAST_RUN, &priv->flags);
- netif_carrier_on(dev);
}
int ipoib_mcast_start_thread(struct net_device *dev)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index 3cb551b8875..7f3ec205e35 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -259,12 +259,13 @@ void ipoib_event(struct ib_event_handler *handler,
struct ipoib_dev_priv *priv =
container_of(handler, struct ipoib_dev_priv, event_handler);
- if (record->event == IB_EVENT_PORT_ERR ||
- record->event == IB_EVENT_PKEY_CHANGE ||
- record->event == IB_EVENT_PORT_ACTIVE ||
- record->event == IB_EVENT_LID_CHANGE ||
- record->event == IB_EVENT_SM_CHANGE ||
- record->event == IB_EVENT_CLIENT_REREGISTER) {
+ if ((record->event == IB_EVENT_PORT_ERR ||
+ record->event == IB_EVENT_PKEY_CHANGE ||
+ record->event == IB_EVENT_PORT_ACTIVE ||
+ record->event == IB_EVENT_LID_CHANGE ||
+ record->event == IB_EVENT_SM_CHANGE ||
+ record->event == IB_EVENT_CLIENT_REREGISTER) &&
+ record->element.port_num == priv->port) {
ipoib_dbg(priv, "Port state change event\n");
queue_work(ipoib_workqueue, &priv->flush_task);
}
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 64509689fa6..f17e9c7d4b3 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -215,14 +215,16 @@ config KEYBOARD_AAED2000
module will be called aaed2000_kbd.
config KEYBOARD_GPIO
- tristate "Buttons on CPU GPIOs (PXA)"
- depends on (ARCH_SA1100 || ARCH_PXA || ARCH_S3C2410)
+ tristate "GPIO Buttons"
+ depends on GENERIC_GPIO
help
This driver implements support for buttons connected
- directly to GPIO pins of SA1100, PXA or S3C24xx CPUs.
+ to GPIO pins of various CPUs (and some other chips).
Say Y here if your device has buttons connected
- directly to GPIO pins of the CPU.
+ directly to such GPIO pins. Your board-specific
+ setup logic must also provide a platform device,
+ with configuration data saying which GPIOs are used.
To compile this driver as a module, choose M here: the
module will be called gpio-keys.
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index fa03a00b4c6..ccf6df387b6 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -23,11 +23,9 @@
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/irq.h>
+#include <linux/gpio_keys.h>
#include <asm/gpio.h>
-#include <asm/arch/hardware.h>
-
-#include <asm/hardware/gpio_keys.h>
static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
{
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index ec195a36e8f..db9cca3b65e 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -553,7 +553,8 @@ static int __devinit i8042_check_aux(void)
*/
param = 0x5a;
- if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0x5a) {
+ retval = i8042_command(&param, I8042_CMD_AUX_LOOP);
+ if (retval || param != 0x5a) {
/*
* External connection test - filters out AT-soldered PS/2 i8042's
@@ -567,7 +568,12 @@ static int __devinit i8042_check_aux(void)
(param && param != 0xfa && param != 0xff))
return -1;
- aux_loop_broken = 1;
+/*
+ * If AUX_LOOP completed without error but returned unexpected data
+ * mark it as broken
+ */
+ if (!retval)
+ aux_loop_broken = 1;
}
/*
diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig
index 8b6c9a431ff..c921d6c522f 100644
--- a/drivers/isdn/capi/Kconfig
+++ b/drivers/isdn/capi/Kconfig
@@ -2,13 +2,25 @@
# Config.in for the CAPI subsystem
#
config ISDN_DRV_AVMB1_VERBOSE_REASON
- bool "Verbose reason code reporting (kernel size +=7K)"
+ bool "Verbose reason code reporting"
depends on ISDN_CAPI
+ default y
help
- If you say Y here, the AVM B1 driver will give verbose reasons for
+ If you say Y here, the CAPI drivers will give verbose reasons for
disconnecting. This will increase the size of the kernel by 7 KB. If
unsure, say Y.
+config CAPI_TRACE
+ bool "CAPI trace support"
+ depends on ISDN_CAPI
+ default y
+ help
+ If you say Y here, the kernelcapi driver can make verbose traces
+ of CAPI messages. This feature can be enabled/disabled via IOCTL for
+ every controler (default disabled).
+ This will increase the size of the kernelcapi module by 20 KB.
+ If unsure, say Y.
+
config ISDN_CAPI_MIDDLEWARE
bool "CAPI2.0 Middleware support (EXPERIMENTAL)"
depends on ISDN_CAPI && EXPERIMENTAL
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index 2a49cea0a22..23b6f7bc16b 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -990,6 +990,7 @@ static void handle_plci(_cmsg * cmsg)
capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
capidrv_plci *plcip;
isdn_ctrl cmd;
+ _cdebbuf *cdb;
if (!card) {
printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
@@ -1122,8 +1123,15 @@ static void handle_plci(_cmsg * cmsg)
break;
}
}
- printk(KERN_ERR "capidrv-%d: %s\n",
- card->contrnr, capi_cmsg2str(cmsg));
+ cdb = capi_cmsg2str(cmsg);
+ if (cdb) {
+ printk(KERN_WARNING "capidrv-%d: %s\n",
+ card->contrnr, cdb->buf);
+ cdebbuf_free(cdb);
+ } else
+ printk(KERN_WARNING "capidrv-%d: CAPI_INFO_IND InfoNumber %x not handled\n",
+ card->contrnr, cmsg->InfoNumber);
+
break;
case CAPI_CONNECT_ACTIVE_CONF: /* plci */
@@ -1371,10 +1379,18 @@ static _cmsg s_cmsg;
static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
{
capi_message2cmsg(&s_cmsg, skb->data);
- if (debugmode > 3)
- printk(KERN_DEBUG "capidrv_signal: applid=%d %s\n",
- ap->applid, capi_cmsg2str(&s_cmsg));
-
+ if (debugmode > 3) {
+ _cdebbuf *cdb = capi_cmsg2str(&s_cmsg);
+
+ if (cdb) {
+ printk(KERN_DEBUG "%s: applid=%d %s\n", __FUNCTION__,
+ ap->applid, cdb->buf);
+ cdebbuf_free(cdb);
+ } else
+ printk(KERN_DEBUG "%s: applid=%d %s not traced\n",
+ __FUNCTION__, ap->applid,
+ capi_cmd2str(s_cmsg.Command, s_cmsg.Subcommand));
+ }
if (s_cmsg.Command == CAPI_DATA_B3
&& s_cmsg.Subcommand == CAPI_IND) {
handle_data(&s_cmsg, skb);
diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c
index c1b21552fc0..ad1e2702c2d 100644
--- a/drivers/isdn/capi/capiutil.c
+++ b/drivers/isdn/capi/capiutil.c
@@ -648,6 +648,9 @@ char *capi_cmd2str(u8 cmd, u8 subcmd)
/*-------------------------------------------------------*/
+
+#ifdef CONFIG_CAPI_TRACE
+
/*-------------------------------------------------------*/
static char *pnames[] =
@@ -703,44 +706,77 @@ static char *pnames[] =
};
-static char buf[8192];
-static char *p = NULL;
#include <stdarg.h>
/*-------------------------------------------------------*/
-static void bufprint(char *fmt,...)
+static _cdebbuf *bufprint(_cdebbuf *cdb, char *fmt,...)
{
va_list f;
+ size_t n,r;
+
+ if (!cdb)
+ return NULL;
va_start(f, fmt);
- vsprintf(p, fmt, f);
+ r = cdb->size - cdb->pos;
+ n = vsnprintf(cdb->p, r, fmt, f);
va_end(f);
- p += strlen(p);
+ if (n >= r) {
+ /* truncated, need bigger buffer */
+ size_t ns = 2 * cdb->size;
+ u_char *nb;
+
+ while ((ns - cdb->pos) <= n)
+ ns *= 2;
+ nb = kmalloc(ns, GFP_ATOMIC);
+ if (!nb) {
+ cdebbuf_free(cdb);
+ return NULL;
+ }
+ memcpy(nb, cdb->buf, cdb->pos);
+ kfree(cdb->buf);
+ nb[cdb->pos] = 0;
+ cdb->buf = nb;
+ cdb->p = cdb->buf + cdb->pos;
+ cdb->size = ns;
+ va_start(f, fmt);
+ r = cdb->size - cdb->pos;
+ n = vsnprintf(cdb->p, r, fmt, f);
+ va_end(f);
+ }
+ cdb->p += n;
+ cdb->pos += n;
+ return cdb;
}
-static void printstructlen(u8 * m, unsigned len)
+static _cdebbuf *printstructlen(_cdebbuf *cdb, u8 * m, unsigned len)
{
unsigned hex = 0;
+
+ if (!cdb)
+ return NULL;
for (; len; len--, m++)
if (isalnum(*m) || *m == ' ') {
if (hex)
- bufprint(">");
- bufprint("%c", *m);
+ cdb = bufprint(cdb, ">");
+ cdb = bufprint(cdb, "%c", *m);
hex = 0;
} else {
if (!hex)
- bufprint("<%02x", *m);
+ cdb = bufprint(cdb, "<%02x", *m);
else
- bufprint(" %02x", *m);
+ cdb = bufprint(cdb, " %02x", *m);
hex = 1;
}
if (hex)
- bufprint(">");
+ cdb = bufprint(cdb, ">");
+ return cdb;
}
-static void printstruct(u8 * m)
+static _cdebbuf *printstruct(_cdebbuf *cdb, u8 * m)
{
unsigned len;
+
if (m[0] != 0xff) {
len = m[0];
m += 1;
@@ -748,42 +784,45 @@ static void printstruct(u8 * m)
len = ((u16 *) (m + 1))[0];
m += 3;
}
- printstructlen(m, len);
+ cdb = printstructlen(cdb, m, len);
+ return cdb;
}
/*-------------------------------------------------------*/
#define NAME (pnames[cmsg->par[cmsg->p]])
-static void protocol_message_2_pars(_cmsg * cmsg, int level)
+static _cdebbuf *protocol_message_2_pars(_cdebbuf *cdb, _cmsg *cmsg, int level)
{
for (; TYP != _CEND; cmsg->p++) {
int slen = 29 + 3 - level;
int i;
- bufprint(" ");
+ if (!cdb)
+ return NULL;
+ cdb = bufprint(cdb, " ");
for (i = 0; i < level - 1; i++)
- bufprint(" ");
+ cdb = bufprint(cdb, " ");
switch (TYP) {
case _CBYTE:
- bufprint("%-*s = 0x%x\n", slen, NAME, *(u8 *) (cmsg->m + cmsg->l));
+ cdb = bufprint(cdb, "%-*s = 0x%x\n", slen, NAME, *(u8 *) (cmsg->m + cmsg->l));
cmsg->l++;
break;
case _CWORD:
- bufprint("%-*s = 0x%x\n", slen, NAME, *(u16 *) (cmsg->m + cmsg->l));
+ cdb = bufprint(cdb, "%-*s = 0x%x\n", slen, NAME, *(u16 *) (cmsg->m + cmsg->l));
cmsg->l += 2;
break;
case _CDWORD:
- bufprint("%-*s = 0x%lx\n", slen, NAME, *(u32 *) (cmsg->m + cmsg->l));
+ cdb = bufprint(cdb, "%-*s = 0x%lx\n", slen, NAME, *(u32 *) (cmsg->m + cmsg->l));
cmsg->l += 4;
break;
case _CSTRUCT:
- bufprint("%-*s = ", slen, NAME);
+ cdb = bufprint(cdb, "%-*s = ", slen, NAME);
if (cmsg->m[cmsg->l] == '\0')
- bufprint("default");
+ cdb = bufprint(cdb, "default");
else
- printstruct(cmsg->m + cmsg->l);
- bufprint("\n");
+ cdb = printstruct(cdb, cmsg->m + cmsg->l);
+ cdb = bufprint(cdb, "\n");
if (cmsg->m[cmsg->l] != 0xff)
cmsg->l += 1 + cmsg->m[cmsg->l];
else
@@ -794,61 +833,184 @@ static void protocol_message_2_pars(_cmsg * cmsg, int level)
case _CMSTRUCT:
/*----- Metastruktur 0 -----*/
if (cmsg->m[cmsg->l] == '\0') {
- bufprint("%-*s = default\n", slen, NAME);
+ cdb = bufprint(cdb, "%-*s = default\n", slen, NAME);
cmsg->l++;
jumpcstruct(cmsg);
} else {
char *name = NAME;
unsigned _l = cmsg->l;
- bufprint("%-*s\n", slen, name);
+ cdb = bufprint(cdb, "%-*s\n", slen, name);
cmsg->l = (cmsg->m + _l)[0] == 255 ? cmsg->l + 3 : cmsg->l + 1;
cmsg->p++;
- protocol_message_2_pars(cmsg, level + 1);
+ cdb = protocol_message_2_pars(cdb, cmsg, level + 1);
}
break;
}
}
+ return cdb;
}
/*-------------------------------------------------------*/
-char *capi_message2str(u8 * msg)
+
+static _cdebbuf *g_debbuf;
+static u_long g_debbuf_lock;
+static _cmsg *g_cmsg;
+
+_cdebbuf *cdebbuf_alloc(void)
{
+ _cdebbuf *cdb;
+
+ if (likely(!test_and_set_bit(1, &g_debbuf_lock))) {
+ cdb = g_debbuf;
+ goto init;
+ } else
+ cdb = kmalloc(sizeof(_cdebbuf), GFP_ATOMIC);
+ if (!cdb)
+ return NULL;
+ cdb->buf = kmalloc(CDEBUG_SIZE, GFP_ATOMIC);
+ if (!cdb->buf) {
+ kfree(cdb);
+ return NULL;
+ }
+ cdb->size = CDEBUG_SIZE;
+init:
+ cdb->buf[0] = 0;
+ cdb->p = cdb->buf;
+ cdb->pos = 0;
+ return cdb;
+}
- _cmsg cmsg;
- p = buf;
- p[0] = 0;
+void cdebbuf_free(_cdebbuf *cdb)
+{
+ if (likely(cdb == g_debbuf)) {
+ test_and_clear_bit(1, &g_debbuf_lock);
+ return;
+ }
+ if (likely(cdb))
+ kfree(cdb->buf);
+ kfree(cdb);
+}
- cmsg.m = msg;
- cmsg.l = 8;
- cmsg.p = 0;
- byteTRcpy(cmsg.m + 4, &cmsg.Command);
- byteTRcpy(cmsg.m + 5, &cmsg.Subcommand);
- cmsg.par = cpars[command_2_index(cmsg.Command, cmsg.Subcommand)];
- bufprint("%-26s ID=%03d #0x%04x LEN=%04d\n",
- mnames[command_2_index(cmsg.Command, cmsg.Subcommand)],
+_cdebbuf *capi_message2str(u8 * msg)
+{
+ _cdebbuf *cdb;
+ _cmsg *cmsg;
+
+ cdb = cdebbuf_alloc();
+ if (unlikely(!cdb))
+ return NULL;
+ if (likely(cdb == g_debbuf))
+ cmsg = g_cmsg;
+ else
+ cmsg = kmalloc(sizeof(_cmsg), GFP_ATOMIC);
+ if (unlikely(!cmsg)) {
+ cdebbuf_free(cdb);
+ return NULL;
+ }
+ cmsg->m = msg;
+ cmsg->l = 8;
+ cmsg->p = 0;
+ byteTRcpy(cmsg->m + 4, &cmsg->Command);
+ byteTRcpy(cmsg->m + 5, &cmsg->Subcommand);
+ cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)];
+
+ cdb = bufprint(cdb, "%-26s ID=%03d #0x%04x LEN=%04d\n",
+ mnames[command_2_index(cmsg->Command, cmsg->Subcommand)],
((unsigned short *) msg)[1],
((unsigned short *) msg)[3],
((unsigned short *) msg)[0]);
- protocol_message_2_pars(&cmsg, 1);
- return buf;
+ cdb = protocol_message_2_pars(cdb, cmsg, 1);
+ if (unlikely(cmsg != g_cmsg))
+ kfree(cmsg);
+ return cdb;
}
-char *capi_cmsg2str(_cmsg * cmsg)
+_cdebbuf *capi_cmsg2str(_cmsg * cmsg)
{
- p = buf;
- p[0] = 0;
+ _cdebbuf *cdb;
+
+ cdb = cdebbuf_alloc();
+ if (!cdb)
+ return NULL;
cmsg->l = 8;
cmsg->p = 0;
- bufprint("%s ID=%03d #0x%04x LEN=%04d\n",
+ cdb = bufprint(cdb, "%s ID=%03d #0x%04x LEN=%04d\n",
mnames[command_2_index(cmsg->Command, cmsg->Subcommand)],
((u16 *) cmsg->m)[1],
((u16 *) cmsg->m)[3],
((u16 *) cmsg->m)[0]);
- protocol_message_2_pars(cmsg, 1);
- return buf;
+ cdb = protocol_message_2_pars(cdb, cmsg, 1);
+ return cdb;
}
+int __init cdebug_init(void)
+{
+ g_cmsg= kmalloc(sizeof(_cmsg), GFP_KERNEL);
+ if (!g_cmsg)
+ return ENOMEM;
+ g_debbuf = kmalloc(sizeof(_cdebbuf), GFP_KERNEL);
+ if (!g_debbuf) {
+ kfree(g_cmsg);
+ return ENOMEM;
+ }
+ g_debbuf->buf = kmalloc(CDEBUG_GSIZE, GFP_KERNEL);
+ if (!g_debbuf->buf) {
+ kfree(g_cmsg);
+ kfree(g_debbuf);
+ return ENOMEM;;
+ }
+ g_debbuf->size = CDEBUG_GSIZE;
+ g_debbuf->buf[0] = 0;
+ g_debbuf->p = g_debbuf->buf;
+ g_debbuf->pos = 0;
+ return 0;
+}
+
+void __exit cdebug_exit(void)
+{
+ if (g_debbuf)
+ kfree(g_debbuf->buf);
+ kfree(g_debbuf);
+ kfree(g_cmsg);
+}
+
+#else /* !CONFIG_CAPI_TRACE */
+
+static _cdebbuf g_debbuf = {"CONFIG_CAPI_TRACE not enabled", NULL, 0, 0};
+
+_cdebbuf *capi_message2str(u8 * msg)
+{
+ return &g_debbuf;
+}
+
+_cdebbuf *capi_cmsg2str(_cmsg * cmsg)
+{
+ return &g_debbuf;
+}
+
+_cdebbuf *cdebbuf_alloc(void)
+{
+ return &g_debbuf;
+}
+
+void cdebbuf_free(_cdebbuf *cdb)
+{
+}
+
+int __init cdebug_init(void)
+{
+ return 0;
+}
+
+void __exit cdebug_exit(void)
+{
+}
+
+#endif
+
+EXPORT_SYMBOL(cdebbuf_alloc);
+EXPORT_SYMBOL(cdebbuf_free);
EXPORT_SYMBOL(capi_cmsg2message);
EXPORT_SYMBOL(capi_message2cmsg);
EXPORT_SYMBOL(capi_cmsg_header);
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
index 783a2552631..3ed34f7a1c4 100644
--- a/drivers/isdn/capi/kcapi.c
+++ b/drivers/isdn/capi/kcapi.c
@@ -276,10 +276,17 @@ void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *s
int showctl = 0;
u8 cmd, subcmd;
unsigned long flags;
+ _cdebbuf *cdb;
if (card->cardstate != CARD_RUNNING) {
- printk(KERN_INFO "kcapi: controller %d not active, got: %s",
- card->cnr, capi_message2str(skb->data));
+ cdb = capi_message2str(skb->data);
+ if (cdb) {
+ printk(KERN_INFO "kcapi: controller [%03d] not active, got: %s",
+ card->cnr, cdb->buf);
+ cdebbuf_free(cdb);
+ } else
+ printk(KERN_INFO "kcapi: controller [%03d] not active, cannot trace\n",
+ card->cnr);
goto error;
}
@@ -295,15 +302,21 @@ void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *s
showctl |= (card->traceflag & 1);
if (showctl & 2) {
if (showctl & 1) {
- printk(KERN_DEBUG "kcapi: got [0x%lx] id#%d %s len=%u\n",
- (unsigned long) card->cnr,
- CAPIMSG_APPID(skb->data),
+ printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u\n",
+ card->cnr, CAPIMSG_APPID(skb->data),
capi_cmd2str(cmd, subcmd),
CAPIMSG_LEN(skb->data));
} else {
- printk(KERN_DEBUG "kcapi: got [0x%lx] %s\n",
- (unsigned long) card->cnr,
- capi_message2str(skb->data));
+ cdb = capi_message2str(skb->data);
+ if (cdb) {
+ printk(KERN_DEBUG "kcapi: got [%03d] %s\n",
+ card->cnr, cdb->buf);
+ cdebbuf_free(cdb);
+ } else
+ printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u, cannot trace\n",
+ card->cnr, CAPIMSG_APPID(skb->data),
+ capi_cmd2str(cmd, subcmd),
+ CAPIMSG_LEN(skb->data));
}
}
@@ -312,8 +325,15 @@ void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *s
ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
if ((!ap) || (ap->release_in_progress)) {
read_unlock_irqrestore(&application_lock, flags);
- printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n",
- CAPIMSG_APPID(skb->data), capi_message2str(skb->data));
+ cdb = capi_message2str(skb->data);
+ if (cdb) {
+ printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n",
+ CAPIMSG_APPID(skb->data), cdb->buf);
+ cdebbuf_free(cdb);
+ } else
+ printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s) cannot trace\n",
+ CAPIMSG_APPID(skb->data),
+ capi_cmd2str(cmd, subcmd));
goto error;
}
skb_queue_tail(&ap->recv_queue, skb);
@@ -332,7 +352,7 @@ void capi_ctr_ready(struct capi_ctr * card)
{
card->cardstate = CARD_RUNNING;
- printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n",
+ printk(KERN_NOTICE "kcapi: card [%03d] \"%s\" ready.\n",
card->cnr, card->name);
notify_push(KCI_CONTRUP, card->cnr, 0, 0);
@@ -364,7 +384,7 @@ void capi_ctr_reseted(struct capi_ctr * card)
capi_ctr_put(card);
}
- printk(KERN_NOTICE "kcapi: card %d down.\n", card->cnr);
+ printk(KERN_NOTICE "kcapi: card [%03d] down.\n", card->cnr);
notify_push(KCI_CONTRDOWN, card->cnr, 0, 0);
}
@@ -374,7 +394,7 @@ EXPORT_SYMBOL(capi_ctr_reseted);
void capi_ctr_suspend_output(struct capi_ctr *card)
{
if (!card->blocked) {
- printk(KERN_DEBUG "kcapi: card %d suspend\n", card->cnr);
+ printk(KERN_DEBUG "kcapi: card [%03d] suspend\n", card->cnr);
card->blocked = 1;
}
}
@@ -384,7 +404,7 @@ EXPORT_SYMBOL(capi_ctr_suspend_output);
void capi_ctr_resume_output(struct capi_ctr *card)
{
if (card->blocked) {
- printk(KERN_DEBUG "kcapi: card %d resume\n", card->cnr);
+ printk(KERN_DEBUG "kcapi: card [%03d] resume\n", card->cnr);
card->blocked = 0;
}
}
@@ -432,7 +452,7 @@ attach_capi_ctr(struct capi_ctr *card)
}
ncards++;
- printk(KERN_NOTICE "kcapi: Controller %d: %s attached\n",
+ printk(KERN_NOTICE "kcapi: Controller [%03d]: %s attached\n",
card->cnr, card->name);
return 0;
}
@@ -451,7 +471,7 @@ int detach_capi_ctr(struct capi_ctr *card)
card->procent = NULL;
}
capi_cards[card->cnr - 1] = NULL;
- printk(KERN_NOTICE "kcapi: Controller %d: %s unregistered\n",
+ printk(KERN_NOTICE "kcapi: Controller [%03d]: %s unregistered\n",
card->cnr, card->name);
return 0;
@@ -623,17 +643,25 @@ u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
showctl |= (card->traceflag & 1);
if (showctl & 2) {
if (showctl & 1) {
- printk(KERN_DEBUG "kcapi: put [%#x] id#%d %s len=%u\n",
+ printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u\n",
CAPIMSG_CONTROLLER(skb->data),
CAPIMSG_APPID(skb->data),
capi_cmd2str(cmd, subcmd),
CAPIMSG_LEN(skb->data));
} else {
- printk(KERN_DEBUG "kcapi: put [%#x] %s\n",
- CAPIMSG_CONTROLLER(skb->data),
- capi_message2str(skb->data));
+ _cdebbuf *cdb = capi_message2str(skb->data);
+ if (cdb) {
+ printk(KERN_DEBUG "kcapi: put [%03d] %s\n",
+ CAPIMSG_CONTROLLER(skb->data),
+ cdb->buf);
+ cdebbuf_free(cdb);
+ } else
+ printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u cannot trace\n",
+ CAPIMSG_CONTROLLER(skb->data),
+ CAPIMSG_APPID(skb->data),
+ capi_cmd2str(cmd, subcmd),
+ CAPIMSG_LEN(skb->data));
}
-
}
return card->send_message(card, skb);
}
@@ -894,7 +922,7 @@ int capi20_manufacturer(unsigned int cmd, void __user *data)
return -ESRCH;
card->traceflag = fdef.flag;
- printk(KERN_INFO "kcapi: contr %d set trace=%d\n",
+ printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n",
card->cnr, card->traceflag);
return 0;
}
@@ -967,7 +995,11 @@ static int __init kcapi_init(void)
{
char *p;
char rev[32];
+ int ret;
+ ret = cdebug_init();
+ if (ret)
+ return ret;
kcapi_proc_init();
if ((p = strchr(revision, ':')) != 0 && p[1]) {
@@ -988,6 +1020,7 @@ static void __exit kcapi_exit(void)
/* make sure all notifiers are finished */
flush_scheduled_work();
+ cdebug_exit();
}
module_init(kcapi_init);
diff --git a/drivers/isdn/gigaset/Makefile b/drivers/isdn/gigaset/Makefile
index 5158be0b7ab..e9d3189f56b 100644
--- a/drivers/isdn/gigaset/Makefile
+++ b/drivers/isdn/gigaset/Makefile
@@ -1,8 +1,9 @@
gigaset-y := common.o interface.o proc.o ev-layer.o i4l.o asyncdata.o
usb_gigaset-y := usb-gigaset.o
-bas_gigaset-y := bas-gigaset.o isocdata.o
ser_gigaset-y := ser-gigaset.o
+bas_gigaset-y := bas-gigaset.o isocdata.o
-obj-$(CONFIG_GIGASET_M105) += usb_gigaset.o gigaset.o
-obj-$(CONFIG_GIGASET_BASE) += bas_gigaset.o gigaset.o
-obj-$(CONFIG_GIGASET_M101) += ser_gigaset.o gigaset.o
+obj-$(CONFIG_ISDN_DRV_GIGASET) += gigaset.o
+obj-$(CONFIG_GIGASET_M105) += usb_gigaset.o
+obj-$(CONFIG_GIGASET_BASE) += bas_gigaset.o
+obj-$(CONFIG_GIGASET_M101) += ser_gigaset.o
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c
index f2f108fcec4..00a3be5b862 100644
--- a/drivers/isdn/gigaset/asyncdata.c
+++ b/drivers/isdn/gigaset/asyncdata.c
@@ -13,11 +13,6 @@
* =====================================================================
*/
-/* not set by Kbuild when building both ser_gigaset and usb_gigaset */
-#ifndef KBUILD_MODNAME
-#define KBUILD_MODNAME "asy_gigaset"
-#endif
-
#include "gigaset.h"
#include <linux/crc-ccitt.h>
#include <linux/bitrev.h>
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 04574a9d443..0d122bf889d 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -14,6 +14,7 @@
#include "vmx.h"
#include <linux/kvm.h>
+#include <linux/kvm_para.h>
#define CR0_PE_MASK (1ULL << 0)
#define CR0_TS_MASK (1ULL << 3)
@@ -237,6 +238,9 @@ struct kvm_vcpu {
unsigned long cr0;
unsigned long cr2;
unsigned long cr3;
+ gpa_t para_state_gpa;
+ struct page *para_state_page;
+ gpa_t hypercall_gpa;
unsigned long cr4;
unsigned long cr8;
u64 pdptrs[4]; /* pae */
@@ -305,6 +309,7 @@ struct kvm {
int busy;
unsigned long rmap_overflow;
struct list_head vm_list;
+ struct file *filp;
};
struct kvm_stat {
@@ -339,7 +344,7 @@ struct kvm_arch_ops {
int (*vcpu_create)(struct kvm_vcpu *vcpu);
void (*vcpu_free)(struct kvm_vcpu *vcpu);
- struct kvm_vcpu *(*vcpu_load)(struct kvm_vcpu *vcpu);
+ void (*vcpu_load)(struct kvm_vcpu *vcpu);
void (*vcpu_put)(struct kvm_vcpu *vcpu);
void (*vcpu_decache)(struct kvm_vcpu *vcpu);
@@ -382,6 +387,8 @@ struct kvm_arch_ops {
int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
int (*vcpu_setup)(struct kvm_vcpu *vcpu);
void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
+ void (*patch_hypercall)(struct kvm_vcpu *vcpu,
+ unsigned char *hypercall_addr);
};
extern struct kvm_stat kvm_stat;
@@ -476,6 +483,8 @@ void kvm_mmu_post_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes);
int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva);
void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
+int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run);
+
static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
u32 error_code)
{
@@ -523,7 +532,7 @@ static inline struct kvm_mmu_page *page_header(hpa_t shadow_page)
{
struct page *page = pfn_to_page(shadow_page >> PAGE_SHIFT);
- return (struct kvm_mmu_page *)page->private;
+ return (struct kvm_mmu_page *)page_private(page);
}
static inline u16 read_fs(void)
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index af866147ff2..a163bca3897 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -20,6 +20,7 @@
#include <linux/kvm.h>
#include <linux/module.h>
#include <linux/errno.h>
+#include <linux/magic.h>
#include <asm/processor.h>
#include <linux/percpu.h>
#include <linux/gfp.h>
@@ -36,6 +37,9 @@
#include <asm/desc.h>
#include <linux/sysdev.h>
#include <linux/cpu.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
#include "x86_emulate.h"
#include "segment_descriptor.h"
@@ -72,6 +76,8 @@ static struct kvm_stats_debugfs_item {
static struct dentry *debugfs_dir;
+struct vfsmount *kvmfs_mnt;
+
#define MAX_IO_MSRS 256
#define CR0_RESEVED_BITS 0xffffffff1ffaffc0ULL
@@ -90,6 +96,58 @@ struct segment_descriptor_64 {
#endif
+static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,
+ unsigned long arg);
+
+static struct inode *kvmfs_inode(struct file_operations *fops)
+{
+ int error = -ENOMEM;
+ struct inode *inode = new_inode(kvmfs_mnt->mnt_sb);
+
+ if (!inode)
+ goto eexit_1;
+
+ inode->i_fop = fops;
+
+ /*
+ * Mark the inode dirty from the very beginning,
+ * that way it will never be moved to the dirty
+ * list because mark_inode_dirty() will think
+ * that it already _is_ on the dirty list.
+ */
+ inode->i_state = I_DIRTY;
+ inode->i_mode = S_IRUSR | S_IWUSR;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ return inode;
+
+eexit_1:
+ return ERR_PTR(error);
+}
+
+static struct file *kvmfs_file(struct inode *inode, void *private_data)
+{
+ struct file *file = get_empty_filp();
+
+ if (!file)
+ return ERR_PTR(-ENFILE);
+
+ file->f_path.mnt = mntget(kvmfs_mnt);
+ file->f_path.dentry = d_alloc_anon(inode);
+ if (!file->f_path.dentry)
+ return ERR_PTR(-ENOMEM);
+ file->f_mapping = inode->i_mapping;
+
+ file->f_pos = 0;
+ file->f_flags = O_RDWR;
+ file->f_op = inode->i_fop;
+ file->f_mode = FMODE_READ | FMODE_WRITE;
+ file->f_version = 0;
+ file->private_data = private_data;
+ return file;
+}
+
unsigned long segment_base(u16 selector)
{
struct descriptor_table gdt;
@@ -126,10 +184,8 @@ static inline int valid_vcpu(int n)
return likely(n >= 0 && n < KVM_MAX_VCPUS);
}
-int kvm_read_guest(struct kvm_vcpu *vcpu,
- gva_t addr,
- unsigned long size,
- void *dest)
+int kvm_read_guest(struct kvm_vcpu *vcpu, gva_t addr, unsigned long size,
+ void *dest)
{
unsigned char *host_buf = dest;
unsigned long req_size = size;
@@ -161,10 +217,8 @@ int kvm_read_guest(struct kvm_vcpu *vcpu,
}
EXPORT_SYMBOL_GPL(kvm_read_guest);
-int kvm_write_guest(struct kvm_vcpu *vcpu,
- gva_t addr,
- unsigned long size,
- void *data)
+int kvm_write_guest(struct kvm_vcpu *vcpu, gva_t addr, unsigned long size,
+ void *data)
{
unsigned char *host_buf = data;
unsigned long req_size = size;
@@ -174,12 +228,15 @@ int kvm_write_guest(struct kvm_vcpu *vcpu,
unsigned now;
unsigned offset;
hva_t guest_buf;
+ gfn_t gfn;
paddr = gva_to_hpa(vcpu, addr);
if (is_error_hpa(paddr))
break;
+ gfn = vcpu->mmu.gva_to_gpa(vcpu, addr) >> PAGE_SHIFT;
+ mark_page_dirty(vcpu->kvm, gfn);
guest_buf = (hva_t)kmap_atomic(
pfn_to_page(paddr >> PAGE_SHIFT), KM_USER0);
offset = addr & ~PAGE_MASK;
@@ -195,24 +252,30 @@ int kvm_write_guest(struct kvm_vcpu *vcpu,
}
EXPORT_SYMBOL_GPL(kvm_write_guest);
-static int vcpu_slot(struct kvm_vcpu *vcpu)
+/*
+ * Switches to specified vcpu, until a matching vcpu_put()
+ */
+static void vcpu_load(struct kvm_vcpu *vcpu)
{
- return vcpu - vcpu->kvm->vcpus;
+ mutex_lock(&vcpu->mutex);
+ kvm_arch_ops->vcpu_load(vcpu);
}
/*
- * Switches to specified vcpu, until a matching vcpu_put()
+ * Switches to specified vcpu, until a matching vcpu_put(). Will return NULL
+ * if the slot is not populated.
*/
-static struct kvm_vcpu *vcpu_load(struct kvm *kvm, int vcpu_slot)
+static struct kvm_vcpu *vcpu_load_slot(struct kvm *kvm, int slot)
{
- struct kvm_vcpu *vcpu = &kvm->vcpus[vcpu_slot];
+ struct kvm_vcpu *vcpu = &kvm->vcpus[slot];
mutex_lock(&vcpu->mutex);
- if (unlikely(!vcpu->vmcs)) {
+ if (!vcpu->vmcs) {
mutex_unlock(&vcpu->mutex);
return NULL;
}
- return kvm_arch_ops->vcpu_load(vcpu);
+ kvm_arch_ops->vcpu_load(vcpu);
+ return vcpu;
}
static void vcpu_put(struct kvm_vcpu *vcpu)
@@ -221,13 +284,13 @@ static void vcpu_put(struct kvm_vcpu *vcpu)
mutex_unlock(&vcpu->mutex);
}
-static int kvm_dev_open(struct inode *inode, struct file *filp)
+static struct kvm *kvm_create_vm(void)
{
struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
int i;
if (!kvm)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
spin_lock_init(&kvm->lock);
INIT_LIST_HEAD(&kvm->active_mmu_pages);
@@ -243,7 +306,11 @@ static int kvm_dev_open(struct inode *inode, struct file *filp)
list_add(&kvm->vm_list, &vm_list);
spin_unlock(&kvm_lock);
}
- filp->private_data = kvm;
+ return kvm;
+}
+
+static int kvm_dev_open(struct inode *inode, struct file *filp)
+{
return 0;
}
@@ -281,9 +348,10 @@ static void kvm_free_physmem(struct kvm *kvm)
static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
{
- if (!vcpu_load(vcpu->kvm, vcpu_slot(vcpu)))
+ if (!vcpu->vmcs)
return;
+ vcpu_load(vcpu);
kvm_mmu_destroy(vcpu);
vcpu_put(vcpu);
kvm_arch_ops->vcpu_free(vcpu);
@@ -299,14 +367,24 @@ static void kvm_free_vcpus(struct kvm *kvm)
static int kvm_dev_release(struct inode *inode, struct file *filp)
{
- struct kvm *kvm = filp->private_data;
+ return 0;
+}
+static void kvm_destroy_vm(struct kvm *kvm)
+{
spin_lock(&kvm_lock);
list_del(&kvm->vm_list);
spin_unlock(&kvm_lock);
kvm_free_vcpus(kvm);
kvm_free_physmem(kvm);
kfree(kvm);
+}
+
+static int kvm_vm_release(struct inode *inode, struct file *filp)
+{
+ struct kvm *kvm = filp->private_data;
+
+ kvm_destroy_vm(kvm);
return 0;
}
@@ -457,7 +535,7 @@ EXPORT_SYMBOL_GPL(set_cr4);
void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
{
if (is_long_mode(vcpu)) {
- if ( cr3 & CR3_L_MODE_RESEVED_BITS) {
+ if (cr3 & CR3_L_MODE_RESEVED_BITS) {
printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
inject_gp(vcpu);
return;
@@ -533,55 +611,11 @@ void fx_init(struct kvm_vcpu *vcpu)
}
EXPORT_SYMBOL_GPL(fx_init);
-/*
- * Creates some virtual cpus. Good luck creating more than one.
- */
-static int kvm_dev_ioctl_create_vcpu(struct kvm *kvm, int n)
+static void do_remove_write_access(struct kvm_vcpu *vcpu, int slot)
{
- int r;
- struct kvm_vcpu *vcpu;
-
- r = -EINVAL;
- if (!valid_vcpu(n))
- goto out;
-
- vcpu = &kvm->vcpus[n];
-
- mutex_lock(&vcpu->mutex);
-
- if (vcpu->vmcs) {
- mutex_unlock(&vcpu->mutex);
- return -EEXIST;
- }
-
- vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf,
- FX_IMAGE_ALIGN);
- vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE;
-
- r = kvm_arch_ops->vcpu_create(vcpu);
- if (r < 0)
- goto out_free_vcpus;
-
- r = kvm_mmu_create(vcpu);
- if (r < 0)
- goto out_free_vcpus;
-
- kvm_arch_ops->vcpu_load(vcpu);
- r = kvm_mmu_setup(vcpu);
- if (r >= 0)
- r = kvm_arch_ops->vcpu_setup(vcpu);
- vcpu_put(vcpu);
-
- if (r < 0)
- goto out_free_vcpus;
-
- return 0;
-
-out_free_vcpus:
- kvm_free_vcpu(vcpu);
- mutex_unlock(&vcpu->mutex);
-out:
- return r;
+ spin_lock(&vcpu->kvm->lock);
+ kvm_mmu_slot_remove_write_access(vcpu, slot);
+ spin_unlock(&vcpu->kvm->lock);
}
/*
@@ -590,8 +624,8 @@ out:
*
* Discontiguous memory is allowed, mostly for framebuffers.
*/
-static int kvm_dev_ioctl_set_memory_region(struct kvm *kvm,
- struct kvm_memory_region *mem)
+static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
+ struct kvm_memory_region *mem)
{
int r;
gfn_t base_gfn;
@@ -674,7 +708,7 @@ raced:
| __GFP_ZERO);
if (!new.phys_mem[i])
goto out_free;
- new.phys_mem[i]->private = 0;
+ set_page_private(new.phys_mem[i],0);
}
}
@@ -711,9 +745,11 @@ raced:
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
struct kvm_vcpu *vcpu;
- vcpu = vcpu_load(kvm, i);
+ vcpu = vcpu_load_slot(kvm, i);
if (!vcpu)
continue;
+ if (new.flags & KVM_MEM_LOG_DIRTY_PAGES)
+ do_remove_write_access(vcpu, mem->slot);
kvm_mmu_reset_context(vcpu);
vcpu_put(vcpu);
}
@@ -729,18 +765,11 @@ out:
return r;
}
-static void do_remove_write_access(struct kvm_vcpu *vcpu, int slot)
-{
- spin_lock(&vcpu->kvm->lock);
- kvm_mmu_slot_remove_write_access(vcpu, slot);
- spin_unlock(&vcpu->kvm->lock);
-}
-
/*
* Get (and clear) the dirty memory log for a memory slot.
*/
-static int kvm_dev_ioctl_get_dirty_log(struct kvm *kvm,
- struct kvm_dirty_log *log)
+static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
+ struct kvm_dirty_log *log)
{
struct kvm_memory_slot *memslot;
int r, i;
@@ -765,21 +794,21 @@ static int kvm_dev_ioctl_get_dirty_log(struct kvm *kvm,
if (!memslot->dirty_bitmap)
goto out;
- n = ALIGN(memslot->npages, 8) / 8;
+ n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
- for (i = 0; !any && i < n; ++i)
+ for (i = 0; !any && i < n/sizeof(long); ++i)
any = memslot->dirty_bitmap[i];
r = -EFAULT;
if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
goto out;
-
if (any) {
cleared = 0;
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- struct kvm_vcpu *vcpu = vcpu_load(kvm, i);
+ struct kvm_vcpu *vcpu;
+ vcpu = vcpu_load_slot(kvm, i);
if (!vcpu)
continue;
if (!cleared) {
@@ -903,8 +932,9 @@ static int emulator_read_emulated(unsigned long addr,
return X86EMUL_CONTINUE;
else {
gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
+
if (gpa == UNMAPPED_GVA)
- return vcpu_printf(vcpu, "not present\n"), X86EMUL_PROPAGATE_FAULT;
+ return X86EMUL_PROPAGATE_FAULT;
vcpu->mmio_needed = 1;
vcpu->mmio_phys_addr = gpa;
vcpu->mmio_size = bytes;
@@ -928,6 +958,7 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
return 0;
page = gfn_to_page(m, gpa >> PAGE_SHIFT);
kvm_mmu_pre_write(vcpu, gpa, bytes);
+ mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT);
virt = kmap_atomic(page, KM_USER0);
memcpy(virt + offset_in_page(gpa), &val, bytes);
kunmap_atomic(virt, KM_USER0);
@@ -1142,6 +1173,42 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
}
EXPORT_SYMBOL_GPL(emulate_instruction);
+int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ unsigned long nr, a0, a1, a2, a3, a4, a5, ret;
+
+ kvm_arch_ops->decache_regs(vcpu);
+ ret = -KVM_EINVAL;
+#ifdef CONFIG_X86_64
+ if (is_long_mode(vcpu)) {
+ nr = vcpu->regs[VCPU_REGS_RAX];
+ a0 = vcpu->regs[VCPU_REGS_RDI];
+ a1 = vcpu->regs[VCPU_REGS_RSI];
+ a2 = vcpu->regs[VCPU_REGS_RDX];
+ a3 = vcpu->regs[VCPU_REGS_RCX];
+ a4 = vcpu->regs[VCPU_REGS_R8];
+ a5 = vcpu->regs[VCPU_REGS_R9];
+ } else
+#endif
+ {
+ nr = vcpu->regs[VCPU_REGS_RBX] & -1u;
+ a0 = vcpu->regs[VCPU_REGS_RAX] & -1u;
+ a1 = vcpu->regs[VCPU_REGS_RCX] & -1u;
+ a2 = vcpu->regs[VCPU_REGS_RDX] & -1u;
+ a3 = vcpu->regs[VCPU_REGS_RSI] & -1u;
+ a4 = vcpu->regs[VCPU_REGS_RDI] & -1u;
+ a5 = vcpu->regs[VCPU_REGS_RBP] & -1u;
+ }
+ switch (nr) {
+ default:
+ ;
+ }
+ vcpu->regs[VCPU_REGS_RAX] = ret;
+ kvm_arch_ops->cache_regs(vcpu);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(kvm_hypercall);
+
static u64 mk_cr_64(u64 curr_cr, u32 new_val)
{
return (curr_cr & ~((1ULL << 32) - 1)) | new_val;
@@ -1208,6 +1275,75 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
}
}
+/*
+ * Register the para guest with the host:
+ */
+static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa)
+{
+ struct kvm_vcpu_para_state *para_state;
+ hpa_t para_state_hpa, hypercall_hpa;
+ struct page *para_state_page;
+ unsigned char *hypercall;
+ gpa_t hypercall_gpa;
+
+ printk(KERN_DEBUG "kvm: guest trying to enter paravirtual mode\n");
+ printk(KERN_DEBUG ".... para_state_gpa: %08Lx\n", para_state_gpa);
+
+ /*
+ * Needs to be page aligned:
+ */
+ if (para_state_gpa != PAGE_ALIGN(para_state_gpa))
+ goto err_gp;
+
+ para_state_hpa = gpa_to_hpa(vcpu, para_state_gpa);
+ printk(KERN_DEBUG ".... para_state_hpa: %08Lx\n", para_state_hpa);
+ if (is_error_hpa(para_state_hpa))
+ goto err_gp;
+
+ mark_page_dirty(vcpu->kvm, para_state_gpa >> PAGE_SHIFT);
+ para_state_page = pfn_to_page(para_state_hpa >> PAGE_SHIFT);
+ para_state = kmap_atomic(para_state_page, KM_USER0);
+
+ printk(KERN_DEBUG ".... guest version: %d\n", para_state->guest_version);
+ printk(KERN_DEBUG ".... size: %d\n", para_state->size);
+
+ para_state->host_version = KVM_PARA_API_VERSION;
+ /*
+ * We cannot support guests that try to register themselves
+ * with a newer API version than the host supports:
+ */
+ if (para_state->guest_version > KVM_PARA_API_VERSION) {
+ para_state->ret = -KVM_EINVAL;
+ goto err_kunmap_skip;
+ }
+
+ hypercall_gpa = para_state->hypercall_gpa;
+ hypercall_hpa = gpa_to_hpa(vcpu, hypercall_gpa);
+ printk(KERN_DEBUG ".... hypercall_hpa: %08Lx\n", hypercall_hpa);
+ if (is_error_hpa(hypercall_hpa)) {
+ para_state->ret = -KVM_EINVAL;
+ goto err_kunmap_skip;
+ }
+
+ printk(KERN_DEBUG "kvm: para guest successfully registered.\n");
+ vcpu->para_state_page = para_state_page;
+ vcpu->para_state_gpa = para_state_gpa;
+ vcpu->hypercall_gpa = hypercall_gpa;
+
+ mark_page_dirty(vcpu->kvm, hypercall_gpa >> PAGE_SHIFT);
+ hypercall = kmap_atomic(pfn_to_page(hypercall_hpa >> PAGE_SHIFT),
+ KM_USER1) + (hypercall_hpa & ~PAGE_MASK);
+ kvm_arch_ops->patch_hypercall(vcpu, hypercall);
+ kunmap_atomic(hypercall, KM_USER1);
+
+ para_state->ret = 0;
+err_kunmap_skip:
+ kunmap_atomic(para_state, KM_USER0);
+ return 0;
+err_gp:
+ return 1;
+}
+
int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
{
u64 data;
@@ -1316,6 +1452,12 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
case MSR_IA32_MISC_ENABLE:
vcpu->ia32_misc_enable_msr = data;
break;
+ /*
+ * This is the 'probe whether the host is KVM' logic:
+ */
+ case MSR_KVM_API_MAGIC:
+ return vcpu_register_para(vcpu, data);
+
default:
printk(KERN_ERR "kvm: unhandled wrmsr: 0x%x\n", msr);
return 1;
@@ -1338,8 +1480,7 @@ void kvm_resched(struct kvm_vcpu *vcpu)
{
vcpu_put(vcpu);
cond_resched();
- /* Cannot fail - no vcpu unplug yet. */
- vcpu_load(vcpu->kvm, vcpu_slot(vcpu));
+ vcpu_load(vcpu);
}
EXPORT_SYMBOL_GPL(kvm_resched);
@@ -1361,17 +1502,11 @@ void save_msrs(struct vmx_msr_entry *e, int n)
}
EXPORT_SYMBOL_GPL(save_msrs);
-static int kvm_dev_ioctl_run(struct kvm *kvm, struct kvm_run *kvm_run)
+static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
- struct kvm_vcpu *vcpu;
int r;
- if (!valid_vcpu(kvm_run->vcpu))
- return -EINVAL;
-
- vcpu = vcpu_load(kvm, kvm_run->vcpu);
- if (!vcpu)
- return -ENOENT;
+ vcpu_load(vcpu);
/* re-sync apic's tpr */
vcpu->cr8 = kvm_run->cr8;
@@ -1394,16 +1529,10 @@ static int kvm_dev_ioctl_run(struct kvm *kvm, struct kvm_run *kvm_run)
return r;
}
-static int kvm_dev_ioctl_get_regs(struct kvm *kvm, struct kvm_regs *regs)
+static int kvm_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu,
+ struct kvm_regs *regs)
{
- struct kvm_vcpu *vcpu;
-
- if (!valid_vcpu(regs->vcpu))
- return -EINVAL;
-
- vcpu = vcpu_load(kvm, regs->vcpu);
- if (!vcpu)
- return -ENOENT;
+ vcpu_load(vcpu);
kvm_arch_ops->cache_regs(vcpu);
@@ -1440,16 +1569,10 @@ static int kvm_dev_ioctl_get_regs(struct kvm *kvm, struct kvm_regs *regs)
return 0;
}
-static int kvm_dev_ioctl_set_regs(struct kvm *kvm, struct kvm_regs *regs)
+static int kvm_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu,
+ struct kvm_regs *regs)
{
- struct kvm_vcpu *vcpu;
-
- if (!valid_vcpu(regs->vcpu))
- return -EINVAL;
-
- vcpu = vcpu_load(kvm, regs->vcpu);
- if (!vcpu)
- return -ENOENT;
+ vcpu_load(vcpu);
vcpu->regs[VCPU_REGS_RAX] = regs->rax;
vcpu->regs[VCPU_REGS_RBX] = regs->rbx;
@@ -1486,16 +1609,12 @@ static void get_segment(struct kvm_vcpu *vcpu,
return kvm_arch_ops->get_segment(vcpu, var, seg);
}
-static int kvm_dev_ioctl_get_sregs(struct kvm *kvm, struct kvm_sregs *sregs)
+static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
{
- struct kvm_vcpu *vcpu;
struct descriptor_table dt;
- if (!valid_vcpu(sregs->vcpu))
- return -EINVAL;
- vcpu = vcpu_load(kvm, sregs->vcpu);
- if (!vcpu)
- return -ENOENT;
+ vcpu_load(vcpu);
get_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
get_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
@@ -1537,18 +1656,14 @@ static void set_segment(struct kvm_vcpu *vcpu,
return kvm_arch_ops->set_segment(vcpu, var, seg);
}
-static int kvm_dev_ioctl_set_sregs(struct kvm *kvm, struct kvm_sregs *sregs)
+static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
{
- struct kvm_vcpu *vcpu;
int mmu_reset_needed = 0;
int i;
struct descriptor_table dt;
- if (!valid_vcpu(sregs->vcpu))
- return -EINVAL;
- vcpu = vcpu_load(kvm, sregs->vcpu);
- if (!vcpu)
- return -ENOENT;
+ vcpu_load(vcpu);
set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
set_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
@@ -1654,20 +1769,14 @@ static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
*
* @return number of msrs set successfully.
*/
-static int __msr_io(struct kvm *kvm, struct kvm_msrs *msrs,
+static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs,
struct kvm_msr_entry *entries,
int (*do_msr)(struct kvm_vcpu *vcpu,
unsigned index, u64 *data))
{
- struct kvm_vcpu *vcpu;
int i;
- if (!valid_vcpu(msrs->vcpu))
- return -EINVAL;
-
- vcpu = vcpu_load(kvm, msrs->vcpu);
- if (!vcpu)
- return -ENOENT;
+ vcpu_load(vcpu);
for (i = 0; i < msrs->nmsrs; ++i)
if (do_msr(vcpu, entries[i].index, &entries[i].data))
@@ -1683,7 +1792,7 @@ static int __msr_io(struct kvm *kvm, struct kvm_msrs *msrs,
*
* @return number of msrs set successfully.
*/
-static int msr_io(struct kvm *kvm, struct kvm_msrs __user *user_msrs,
+static int msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs __user *user_msrs,
int (*do_msr)(struct kvm_vcpu *vcpu,
unsigned index, u64 *data),
int writeback)
@@ -1711,7 +1820,7 @@ static int msr_io(struct kvm *kvm, struct kvm_msrs __user *user_msrs,
if (copy_from_user(entries, user_msrs->entries, size))
goto out_free;
- r = n = __msr_io(kvm, &msrs, entries, do_msr);
+ r = n = __msr_io(vcpu, &msrs, entries, do_msr);
if (r < 0)
goto out_free;
@@ -1730,38 +1839,31 @@ out:
/*
* Translate a guest virtual address to a guest physical address.
*/
-static int kvm_dev_ioctl_translate(struct kvm *kvm, struct kvm_translation *tr)
+static int kvm_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
+ struct kvm_translation *tr)
{
unsigned long vaddr = tr->linear_address;
- struct kvm_vcpu *vcpu;
gpa_t gpa;
- vcpu = vcpu_load(kvm, tr->vcpu);
- if (!vcpu)
- return -ENOENT;
- spin_lock(&kvm->lock);
+ vcpu_load(vcpu);
+ spin_lock(&vcpu->kvm->lock);
gpa = vcpu->mmu.gva_to_gpa(vcpu, vaddr);
tr->physical_address = gpa;
tr->valid = gpa != UNMAPPED_GVA;
tr->writeable = 1;
tr->usermode = 0;
- spin_unlock(&kvm->lock);
+ spin_unlock(&vcpu->kvm->lock);
vcpu_put(vcpu);
return 0;
}
-static int kvm_dev_ioctl_interrupt(struct kvm *kvm, struct kvm_interrupt *irq)
+static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
+ struct kvm_interrupt *irq)
{
- struct kvm_vcpu *vcpu;
-
- if (!valid_vcpu(irq->vcpu))
- return -EINVAL;
if (irq->irq < 0 || irq->irq >= 256)
return -EINVAL;
- vcpu = vcpu_load(kvm, irq->vcpu);
- if (!vcpu)
- return -ENOENT;
+ vcpu_load(vcpu);
set_bit(irq->irq, vcpu->irq_pending);
set_bit(irq->irq / BITS_PER_LONG, &vcpu->irq_summary);
@@ -1771,17 +1873,12 @@ static int kvm_dev_ioctl_interrupt(struct kvm *kvm, struct kvm_interrupt *irq)
return 0;
}
-static int kvm_dev_ioctl_debug_guest(struct kvm *kvm,
- struct kvm_debug_guest *dbg)
+static int kvm_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
+ struct kvm_debug_guest *dbg)
{
- struct kvm_vcpu *vcpu;
int r;
- if (!valid_vcpu(dbg->vcpu))
- return -EINVAL;
- vcpu = vcpu_load(kvm, dbg->vcpu);
- if (!vcpu)
- return -ENOENT;
+ vcpu_load(vcpu);
r = kvm_arch_ops->set_guest_debug(vcpu, dbg);
@@ -1790,30 +1887,129 @@ static int kvm_dev_ioctl_debug_guest(struct kvm *kvm,
return r;
}
-static long kvm_dev_ioctl(struct file *filp,
- unsigned int ioctl, unsigned long arg)
+static int kvm_vcpu_release(struct inode *inode, struct file *filp)
{
- struct kvm *kvm = filp->private_data;
+ struct kvm_vcpu *vcpu = filp->private_data;
+
+ fput(vcpu->kvm->filp);
+ return 0;
+}
+
+static struct file_operations kvm_vcpu_fops = {
+ .release = kvm_vcpu_release,
+ .unlocked_ioctl = kvm_vcpu_ioctl,
+ .compat_ioctl = kvm_vcpu_ioctl,
+};
+
+/*
+ * Allocates an inode for the vcpu.
+ */
+static int create_vcpu_fd(struct kvm_vcpu *vcpu)
+{
+ int fd, r;
+ struct inode *inode;
+ struct file *file;
+
+ atomic_inc(&vcpu->kvm->filp->f_count);
+ inode = kvmfs_inode(&kvm_vcpu_fops);
+ if (IS_ERR(inode)) {
+ r = PTR_ERR(inode);
+ goto out1;
+ }
+
+ file = kvmfs_file(inode, vcpu);
+ if (IS_ERR(file)) {
+ r = PTR_ERR(file);
+ goto out2;
+ }
+
+ r = get_unused_fd();
+ if (r < 0)
+ goto out3;
+ fd = r;
+ fd_install(fd, file);
+
+ return fd;
+
+out3:
+ fput(file);
+out2:
+ iput(inode);
+out1:
+ fput(vcpu->kvm->filp);
+ return r;
+}
+
+/*
+ * Creates some virtual cpus. Good luck creating more than one.
+ */
+static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
+{
+ int r;
+ struct kvm_vcpu *vcpu;
+
+ r = -EINVAL;
+ if (!valid_vcpu(n))
+ goto out;
+
+ vcpu = &kvm->vcpus[n];
+
+ mutex_lock(&vcpu->mutex);
+
+ if (vcpu->vmcs) {
+ mutex_unlock(&vcpu->mutex);
+ return -EEXIST;
+ }
+
+ vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf,
+ FX_IMAGE_ALIGN);
+ vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE;
+
+ r = kvm_arch_ops->vcpu_create(vcpu);
+ if (r < 0)
+ goto out_free_vcpus;
+
+ r = kvm_mmu_create(vcpu);
+ if (r < 0)
+ goto out_free_vcpus;
+
+ kvm_arch_ops->vcpu_load(vcpu);
+ r = kvm_mmu_setup(vcpu);
+ if (r >= 0)
+ r = kvm_arch_ops->vcpu_setup(vcpu);
+ vcpu_put(vcpu);
+
+ if (r < 0)
+ goto out_free_vcpus;
+
+ r = create_vcpu_fd(vcpu);
+ if (r < 0)
+ goto out_free_vcpus;
+
+ return r;
+
+out_free_vcpus:
+ kvm_free_vcpu(vcpu);
+ mutex_unlock(&vcpu->mutex);
+out:
+ return r;
+}
+
+static long kvm_vcpu_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ struct kvm_vcpu *vcpu = filp->private_data;
void __user *argp = (void __user *)arg;
int r = -EINVAL;
switch (ioctl) {
- case KVM_GET_API_VERSION:
- r = KVM_API_VERSION;
- break;
- case KVM_CREATE_VCPU: {
- r = kvm_dev_ioctl_create_vcpu(kvm, arg);
- if (r)
- goto out;
- break;
- }
case KVM_RUN: {
struct kvm_run kvm_run;
r = -EFAULT;
if (copy_from_user(&kvm_run, argp, sizeof kvm_run))
goto out;
- r = kvm_dev_ioctl_run(kvm, &kvm_run);
+ r = kvm_vcpu_ioctl_run(vcpu, &kvm_run);
if (r < 0 && r != -EINTR)
goto out;
if (copy_to_user(argp, &kvm_run, sizeof kvm_run)) {
@@ -1825,10 +2021,8 @@ static long kvm_dev_ioctl(struct file *filp,
case KVM_GET_REGS: {
struct kvm_regs kvm_regs;
- r = -EFAULT;
- if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs))
- goto out;
- r = kvm_dev_ioctl_get_regs(kvm, &kvm_regs);
+ memset(&kvm_regs, 0, sizeof kvm_regs);
+ r = kvm_vcpu_ioctl_get_regs(vcpu, &kvm_regs);
if (r)
goto out;
r = -EFAULT;
@@ -1843,7 +2037,7 @@ static long kvm_dev_ioctl(struct file *filp,
r = -EFAULT;
if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs))
goto out;
- r = kvm_dev_ioctl_set_regs(kvm, &kvm_regs);
+ r = kvm_vcpu_ioctl_set_regs(vcpu, &kvm_regs);
if (r)
goto out;
r = 0;
@@ -1852,10 +2046,8 @@ static long kvm_dev_ioctl(struct file *filp,
case KVM_GET_SREGS: {
struct kvm_sregs kvm_sregs;
- r = -EFAULT;
- if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs))
- goto out;
- r = kvm_dev_ioctl_get_sregs(kvm, &kvm_sregs);
+ memset(&kvm_sregs, 0, sizeof kvm_sregs);
+ r = kvm_vcpu_ioctl_get_sregs(vcpu, &kvm_sregs);
if (r)
goto out;
r = -EFAULT;
@@ -1870,7 +2062,7 @@ static long kvm_dev_ioctl(struct file *filp,
r = -EFAULT;
if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs))
goto out;
- r = kvm_dev_ioctl_set_sregs(kvm, &kvm_sregs);
+ r = kvm_vcpu_ioctl_set_sregs(vcpu, &kvm_sregs);
if (r)
goto out;
r = 0;
@@ -1882,7 +2074,7 @@ static long kvm_dev_ioctl(struct file *filp,
r = -EFAULT;
if (copy_from_user(&tr, argp, sizeof tr))
goto out;
- r = kvm_dev_ioctl_translate(kvm, &tr);
+ r = kvm_vcpu_ioctl_translate(vcpu, &tr);
if (r)
goto out;
r = -EFAULT;
@@ -1897,7 +2089,7 @@ static long kvm_dev_ioctl(struct file *filp,
r = -EFAULT;
if (copy_from_user(&irq, argp, sizeof irq))
goto out;
- r = kvm_dev_ioctl_interrupt(kvm, &irq);
+ r = kvm_vcpu_ioctl_interrupt(vcpu, &irq);
if (r)
goto out;
r = 0;
@@ -1909,19 +2101,45 @@ static long kvm_dev_ioctl(struct file *filp,
r = -EFAULT;
if (copy_from_user(&dbg, argp, sizeof dbg))
goto out;
- r = kvm_dev_ioctl_debug_guest(kvm, &dbg);
+ r = kvm_vcpu_ioctl_debug_guest(vcpu, &dbg);
if (r)
goto out;
r = 0;
break;
}
+ case KVM_GET_MSRS:
+ r = msr_io(vcpu, argp, get_msr, 1);
+ break;
+ case KVM_SET_MSRS:
+ r = msr_io(vcpu, argp, do_set_msr, 0);
+ break;
+ default:
+ ;
+ }
+out:
+ return r;
+}
+
+static long kvm_vm_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ struct kvm *kvm = filp->private_data;
+ void __user *argp = (void __user *)arg;
+ int r = -EINVAL;
+
+ switch (ioctl) {
+ case KVM_CREATE_VCPU:
+ r = kvm_vm_ioctl_create_vcpu(kvm, arg);
+ if (r < 0)
+ goto out;
+ break;
case KVM_SET_MEMORY_REGION: {
struct kvm_memory_region kvm_mem;
r = -EFAULT;
if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem))
goto out;
- r = kvm_dev_ioctl_set_memory_region(kvm, &kvm_mem);
+ r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_mem);
if (r)
goto out;
break;
@@ -1932,16 +2150,112 @@ static long kvm_dev_ioctl(struct file *filp,
r = -EFAULT;
if (copy_from_user(&log, argp, sizeof log))
goto out;
- r = kvm_dev_ioctl_get_dirty_log(kvm, &log);
+ r = kvm_vm_ioctl_get_dirty_log(kvm, &log);
if (r)
goto out;
break;
}
- case KVM_GET_MSRS:
- r = msr_io(kvm, argp, get_msr, 1);
+ default:
+ ;
+ }
+out:
+ return r;
+}
+
+static struct page *kvm_vm_nopage(struct vm_area_struct *vma,
+ unsigned long address,
+ int *type)
+{
+ struct kvm *kvm = vma->vm_file->private_data;
+ unsigned long pgoff;
+ struct kvm_memory_slot *slot;
+ struct page *page;
+
+ *type = VM_FAULT_MINOR;
+ pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+ slot = gfn_to_memslot(kvm, pgoff);
+ if (!slot)
+ return NOPAGE_SIGBUS;
+ page = gfn_to_page(slot, pgoff);
+ if (!page)
+ return NOPAGE_SIGBUS;
+ get_page(page);
+ return page;
+}
+
+static struct vm_operations_struct kvm_vm_vm_ops = {
+ .nopage = kvm_vm_nopage,
+};
+
+static int kvm_vm_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ vma->vm_ops = &kvm_vm_vm_ops;
+ return 0;
+}
+
+static struct file_operations kvm_vm_fops = {
+ .release = kvm_vm_release,
+ .unlocked_ioctl = kvm_vm_ioctl,
+ .compat_ioctl = kvm_vm_ioctl,
+ .mmap = kvm_vm_mmap,
+};
+
+static int kvm_dev_ioctl_create_vm(void)
+{
+ int fd, r;
+ struct inode *inode;
+ struct file *file;
+ struct kvm *kvm;
+
+ inode = kvmfs_inode(&kvm_vm_fops);
+ if (IS_ERR(inode)) {
+ r = PTR_ERR(inode);
+ goto out1;
+ }
+
+ kvm = kvm_create_vm();
+ if (IS_ERR(kvm)) {
+ r = PTR_ERR(kvm);
+ goto out2;
+ }
+
+ file = kvmfs_file(inode, kvm);
+ if (IS_ERR(file)) {
+ r = PTR_ERR(file);
+ goto out3;
+ }
+ kvm->filp = file;
+
+ r = get_unused_fd();
+ if (r < 0)
+ goto out4;
+ fd = r;
+ fd_install(fd, file);
+
+ return fd;
+
+out4:
+ fput(file);
+out3:
+ kvm_destroy_vm(kvm);
+out2:
+ iput(inode);
+out1:
+ return r;
+}
+
+static long kvm_dev_ioctl(struct file *filp,
+ unsigned int ioctl, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int r = -EINVAL;
+
+ switch (ioctl) {
+ case KVM_GET_API_VERSION:
+ r = KVM_API_VERSION;
break;
- case KVM_SET_MSRS:
- r = msr_io(kvm, argp, do_set_msr, 0);
+ case KVM_CREATE_VM:
+ r = kvm_dev_ioctl_create_vm();
break;
case KVM_GET_MSR_INDEX_LIST: {
struct kvm_msr_list __user *user_msr_list = argp;
@@ -1977,43 +2291,11 @@ out:
return r;
}
-static struct page *kvm_dev_nopage(struct vm_area_struct *vma,
- unsigned long address,
- int *type)
-{
- struct kvm *kvm = vma->vm_file->private_data;
- unsigned long pgoff;
- struct kvm_memory_slot *slot;
- struct page *page;
-
- *type = VM_FAULT_MINOR;
- pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
- slot = gfn_to_memslot(kvm, pgoff);
- if (!slot)
- return NOPAGE_SIGBUS;
- page = gfn_to_page(slot, pgoff);
- if (!page)
- return NOPAGE_SIGBUS;
- get_page(page);
- return page;
-}
-
-static struct vm_operations_struct kvm_dev_vm_ops = {
- .nopage = kvm_dev_nopage,
-};
-
-static int kvm_dev_mmap(struct file *file, struct vm_area_struct *vma)
-{
- vma->vm_ops = &kvm_dev_vm_ops;
- return 0;
-}
-
static struct file_operations kvm_chardev_ops = {
.open = kvm_dev_open,
.release = kvm_dev_release,
.unlocked_ioctl = kvm_dev_ioctl,
.compat_ioctl = kvm_dev_ioctl,
- .mmap = kvm_dev_mmap,
};
static struct miscdevice kvm_dev = {
@@ -2080,13 +2362,17 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
int cpu = (long)v;
switch (val) {
- case CPU_DEAD:
+ case CPU_DOWN_PREPARE:
case CPU_UP_CANCELED:
+ printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
+ cpu);
decache_vcpus_on_cpu(cpu);
smp_call_function_single(cpu, kvm_arch_ops->hardware_disable,
NULL, 0, 1);
break;
- case CPU_UP_PREPARE:
+ case CPU_ONLINE:
+ printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n",
+ cpu);
smp_call_function_single(cpu, kvm_arch_ops->hardware_enable,
NULL, 0, 1);
break;
@@ -2121,13 +2407,13 @@ static void kvm_exit_debug(void)
static int kvm_suspend(struct sys_device *dev, pm_message_t state)
{
decache_vcpus_on_cpu(raw_smp_processor_id());
- on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1);
+ on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
return 0;
}
static int kvm_resume(struct sys_device *dev)
{
- on_each_cpu(kvm_arch_ops->hardware_enable, 0, 0, 1);
+ on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1);
return 0;
}
@@ -2144,6 +2430,18 @@ static struct sys_device kvm_sysdev = {
hpa_t bad_page_address;
+static int kvmfs_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data, struct vfsmount *mnt)
+{
+ return get_sb_pseudo(fs_type, "kvm:", NULL, KVMFS_SUPER_MAGIC, mnt);
+}
+
+static struct file_system_type kvm_fs_type = {
+ .name = "kvmfs",
+ .get_sb = kvmfs_get_sb,
+ .kill_sb = kill_anon_super,
+};
+
int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
{
int r;
@@ -2220,8 +2518,16 @@ void kvm_exit_arch(void)
static __init int kvm_init(void)
{
static struct page *bad_page;
- int r = 0;
+ int r;
+
+ r = register_filesystem(&kvm_fs_type);
+ if (r)
+ goto out3;
+ kvmfs_mnt = kern_mount(&kvm_fs_type);
+ r = PTR_ERR(kvmfs_mnt);
+ if (IS_ERR(kvmfs_mnt))
+ goto out2;
kvm_init_debug();
kvm_init_msr_list();
@@ -2234,10 +2540,14 @@ static __init int kvm_init(void)
bad_page_address = page_to_pfn(bad_page) << PAGE_SHIFT;
memset(__va(bad_page_address), 0, PAGE_SIZE);
- return r;
+ return 0;
out:
kvm_exit_debug();
+ mntput(kvmfs_mnt);
+out2:
+ unregister_filesystem(&kvm_fs_type);
+out3:
return r;
}
@@ -2245,6 +2555,8 @@ static __exit void kvm_exit(void)
{
kvm_exit_debug();
__free_page(pfn_to_page(bad_page_address >> PAGE_SHIFT));
+ mntput(kvmfs_mnt);
+ unregister_filesystem(&kvm_fs_type);
}
module_init(kvm_init)
diff --git a/drivers/kvm/kvm_svm.h b/drivers/kvm/kvm_svm.h
index 74cc862f493..624f1ca4865 100644
--- a/drivers/kvm/kvm_svm.h
+++ b/drivers/kvm/kvm_svm.h
@@ -1,6 +1,7 @@
#ifndef __KVM_SVM_H
#define __KVM_SVM_H
+#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/list.h>
#include <asm/msr.h>
@@ -18,7 +19,7 @@ static const u32 host_save_msrs[] = {
MSR_IA32_LASTBRANCHTOIP, MSR_IA32_LASTINTFROMIP,MSR_IA32_LASTINTTOIP,*/
};
-#define NR_HOST_SAVE_MSRS (sizeof(host_save_msrs) / sizeof(*host_save_msrs))
+#define NR_HOST_SAVE_MSRS ARRAY_SIZE(host_save_msrs)
#define NUM_DB_REGS 4
struct vcpu_svm {
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index be793770f31..a1a93368f31 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -298,18 +298,18 @@ static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte)
if (!is_rmap_pte(*spte))
return;
page = pfn_to_page((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT);
- if (!page->private) {
+ if (!page_private(page)) {
rmap_printk("rmap_add: %p %llx 0->1\n", spte, *spte);
- page->private = (unsigned long)spte;
- } else if (!(page->private & 1)) {
+ set_page_private(page,(unsigned long)spte);
+ } else if (!(page_private(page) & 1)) {
rmap_printk("rmap_add: %p %llx 1->many\n", spte, *spte);
desc = mmu_alloc_rmap_desc(vcpu);
- desc->shadow_ptes[0] = (u64 *)page->private;
+ desc->shadow_ptes[0] = (u64 *)page_private(page);
desc->shadow_ptes[1] = spte;
- page->private = (unsigned long)desc | 1;
+ set_page_private(page,(unsigned long)desc | 1);
} else {
rmap_printk("rmap_add: %p %llx many->many\n", spte, *spte);
- desc = (struct kvm_rmap_desc *)(page->private & ~1ul);
+ desc = (struct kvm_rmap_desc *)(page_private(page) & ~1ul);
while (desc->shadow_ptes[RMAP_EXT-1] && desc->more)
desc = desc->more;
if (desc->shadow_ptes[RMAP_EXT-1]) {
@@ -337,12 +337,12 @@ static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu,
if (j != 0)
return;
if (!prev_desc && !desc->more)
- page->private = (unsigned long)desc->shadow_ptes[0];
+ set_page_private(page,(unsigned long)desc->shadow_ptes[0]);
else
if (prev_desc)
prev_desc->more = desc->more;
else
- page->private = (unsigned long)desc->more | 1;
+ set_page_private(page,(unsigned long)desc->more | 1);
mmu_free_rmap_desc(vcpu, desc);
}
@@ -356,20 +356,20 @@ static void rmap_remove(struct kvm_vcpu *vcpu, u64 *spte)
if (!is_rmap_pte(*spte))
return;
page = pfn_to_page((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT);
- if (!page->private) {
+ if (!page_private(page)) {
printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte);
BUG();
- } else if (!(page->private & 1)) {
+ } else if (!(page_private(page) & 1)) {
rmap_printk("rmap_remove: %p %llx 1->0\n", spte, *spte);
- if ((u64 *)page->private != spte) {
+ if ((u64 *)page_private(page) != spte) {
printk(KERN_ERR "rmap_remove: %p %llx 1->BUG\n",
spte, *spte);
BUG();
}
- page->private = 0;
+ set_page_private(page,0);
} else {
rmap_printk("rmap_remove: %p %llx many->many\n", spte, *spte);
- desc = (struct kvm_rmap_desc *)(page->private & ~1ul);
+ desc = (struct kvm_rmap_desc *)(page_private(page) & ~1ul);
prev_desc = NULL;
while (desc) {
for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i)
@@ -398,11 +398,11 @@ static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
BUG_ON(!slot);
page = gfn_to_page(slot, gfn);
- while (page->private) {
- if (!(page->private & 1))
- spte = (u64 *)page->private;
+ while (page_private(page)) {
+ if (!(page_private(page) & 1))
+ spte = (u64 *)page_private(page);
else {
- desc = (struct kvm_rmap_desc *)(page->private & ~1ul);
+ desc = (struct kvm_rmap_desc *)(page_private(page) & ~1ul);
spte = desc->shadow_ptes[0];
}
BUG_ON(!spte);
@@ -1218,7 +1218,7 @@ static int alloc_mmu_pages(struct kvm_vcpu *vcpu)
INIT_LIST_HEAD(&page_header->link);
if ((page = alloc_page(GFP_KERNEL)) == NULL)
goto error_1;
- page->private = (unsigned long)page_header;
+ set_page_private(page, (unsigned long)page_header);
page_header->page_hpa = (hpa_t)page_to_pfn(page) << PAGE_SHIFT;
memset(__va(page_header->page_hpa), 0, PAGE_SIZE);
list_add(&page_header->link, &vcpu->free_pages);
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index b6b90e9e130..f3bcee90465 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -128,8 +128,10 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
goto access_error;
#endif
- if (!(*ptep & PT_ACCESSED_MASK))
- *ptep |= PT_ACCESSED_MASK; /* avoid rmw */
+ if (!(*ptep & PT_ACCESSED_MASK)) {
+ mark_page_dirty(vcpu->kvm, table_gfn);
+ *ptep |= PT_ACCESSED_MASK;
+ }
if (walker->level == PT_PAGE_TABLE_LEVEL) {
walker->gfn = (*ptep & PT_BASE_ADDR_MASK)
@@ -185,6 +187,12 @@ static void FNAME(release_walker)(struct guest_walker *walker)
kunmap_atomic(walker->table, KM_USER0);
}
+static void FNAME(mark_pagetable_dirty)(struct kvm *kvm,
+ struct guest_walker *walker)
+{
+ mark_page_dirty(kvm, walker->table_gfn[walker->level - 1]);
+}
+
static void FNAME(set_pte)(struct kvm_vcpu *vcpu, u64 guest_pte,
u64 *shadow_pte, u64 access_bits, gfn_t gfn)
{
@@ -348,12 +356,15 @@ static int FNAME(fix_write_pf)(struct kvm_vcpu *vcpu,
} else if (kvm_mmu_lookup_page(vcpu, gfn)) {
pgprintk("%s: found shadow page for %lx, marking ro\n",
__FUNCTION__, gfn);
+ mark_page_dirty(vcpu->kvm, gfn);
+ FNAME(mark_pagetable_dirty)(vcpu->kvm, walker);
*guest_ent |= PT_DIRTY_MASK;
*write_pt = 1;
return 0;
}
mark_page_dirty(vcpu->kvm, gfn);
*shadow_ent |= PT_WRITABLE_MASK;
+ FNAME(mark_pagetable_dirty)(vcpu->kvm, walker);
*guest_ent |= PT_DIRTY_MASK;
rmap_add(vcpu, shadow_ent);
@@ -430,9 +441,8 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
/*
* mmio: emulate if accessible, otherwise its a guest fault.
*/
- if (is_io_pte(*shadow_pte)) {
+ if (is_io_pte(*shadow_pte))
return 1;
- }
++kvm_stat.pf_fixed;
kvm_mmu_audit(vcpu, "post page fault (fixed)");
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index 83da4ea150a..3d8ea7ac2ec 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -15,6 +15,7 @@
*/
#include <linux/module.h>
+#include <linux/kernel.h>
#include <linux/vmalloc.h>
#include <linux/highmem.h>
#include <linux/profile.h>
@@ -75,7 +76,7 @@ struct svm_init_data {
static u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000};
-#define NUM_MSR_MAPS (sizeof(msrpm_ranges) / sizeof(*msrpm_ranges))
+#define NUM_MSR_MAPS ARRAY_SIZE(msrpm_ranges)
#define MSRS_RANGE_SIZE 2048
#define MSRS_IN_RANGE (MSRS_RANGE_SIZE * 8 / 2)
@@ -485,6 +486,7 @@ static void init_vmcb(struct vmcb *vmcb)
control->intercept = (1ULL << INTERCEPT_INTR) |
(1ULL << INTERCEPT_NMI) |
+ (1ULL << INTERCEPT_SMI) |
/*
* selective cr0 intercept bug?
* 0: 0f 22 d8 mov %eax,%cr3
@@ -553,7 +555,7 @@ static void init_vmcb(struct vmcb *vmcb)
* cr0 val on cpu init should be 0x60000010, we enable cpu
* cache by default. the orderly way is to enable cache in bios.
*/
- save->cr0 = 0x00000010 | CR0_PG_MASK;
+ save->cr0 = 0x00000010 | CR0_PG_MASK | CR0_WP_MASK;
save->cr4 = CR4_PAE_MASK;
/* rdx = ?? */
}
@@ -598,10 +600,9 @@ static void svm_free_vcpu(struct kvm_vcpu *vcpu)
kfree(vcpu->svm);
}
-static struct kvm_vcpu *svm_vcpu_load(struct kvm_vcpu *vcpu)
+static void svm_vcpu_load(struct kvm_vcpu *vcpu)
{
get_cpu();
- return vcpu;
}
static void svm_vcpu_put(struct kvm_vcpu *vcpu)
@@ -1042,22 +1043,22 @@ static int io_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
addr_mask = io_adress(vcpu, _in, &kvm_run->io.address);
if (!addr_mask) {
- printk(KERN_DEBUG "%s: get io address failed\n", __FUNCTION__);
+ printk(KERN_DEBUG "%s: get io address failed\n",
+ __FUNCTION__);
return 1;
}
if (kvm_run->io.rep) {
- kvm_run->io.count = vcpu->regs[VCPU_REGS_RCX] & addr_mask;
+ kvm_run->io.count
+ = vcpu->regs[VCPU_REGS_RCX] & addr_mask;
kvm_run->io.string_down = (vcpu->svm->vmcb->save.rflags
& X86_EFLAGS_DF) != 0;
}
- } else {
+ } else
kvm_run->io.value = vcpu->svm->vmcb->save.rax;
- }
return 0;
}
-
static int nop_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
return 1;
@@ -1075,6 +1076,12 @@ static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 0;
}
+static int vmmcall_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ vcpu->svm->vmcb->save.rip += 3;
+ return kvm_hypercall(vcpu, kvm_run);
+}
+
static int invalid_op_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
inject_ud(vcpu);
@@ -1275,7 +1282,7 @@ static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu,
[SVM_EXIT_TASK_SWITCH] = task_switch_interception,
[SVM_EXIT_SHUTDOWN] = shutdown_interception,
[SVM_EXIT_VMRUN] = invalid_op_interception,
- [SVM_EXIT_VMMCALL] = invalid_op_interception,
+ [SVM_EXIT_VMMCALL] = vmmcall_interception,
[SVM_EXIT_VMLOAD] = invalid_op_interception,
[SVM_EXIT_VMSAVE] = invalid_op_interception,
[SVM_EXIT_STGI] = invalid_op_interception,
@@ -1297,7 +1304,7 @@ static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
__FUNCTION__, vcpu->svm->vmcb->control.exit_int_info,
exit_code);
- if (exit_code >= sizeof(svm_exit_handlers) / sizeof(*svm_exit_handlers)
+ if (exit_code >= ARRAY_SIZE(svm_exit_handlers)
|| svm_exit_handlers[exit_code] == 0) {
kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
printk(KERN_ERR "%s: 0x%x @ 0x%llx cr0 0x%lx rflags 0x%llx\n",
@@ -1668,6 +1675,18 @@ static int is_disabled(void)
return 0;
}
+static void
+svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
+{
+ /*
+ * Patch in the VMMCALL instruction:
+ */
+ hypercall[0] = 0x0f;
+ hypercall[1] = 0x01;
+ hypercall[2] = 0xd9;
+ hypercall[3] = 0xc3;
+}
+
static struct kvm_arch_ops svm_arch_ops = {
.cpu_has_kvm_support = has_svm,
.disabled_by_bios = is_disabled,
@@ -1716,6 +1735,7 @@ static struct kvm_arch_ops svm_arch_ops = {
.run = svm_vcpu_run,
.skip_emulated_instruction = skip_emulated_instruction,
.vcpu_setup = svm_vcpu_setup,
+ .patch_hypercall = svm_patch_hypercall,
};
static int __init svm_init(void)
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index fd4e9173438..c07178e6112 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -19,6 +19,7 @@
#include "vmx.h"
#include "kvm_vmx.h"
#include <linux/module.h>
+#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/profile.h>
@@ -27,7 +28,6 @@
#include "segment_descriptor.h"
-
MODULE_AUTHOR("Qumranet");
MODULE_LICENSE("GPL");
@@ -76,7 +76,7 @@ static const u32 vmx_msr_index[] = {
#endif
MSR_EFER, MSR_K6_STAR,
};
-#define NR_VMX_MSR (sizeof(vmx_msr_index) / sizeof(*vmx_msr_index))
+#define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index)
static inline int is_page_fault(u32 intr_info)
{
@@ -204,7 +204,7 @@ static void vmcs_write64(unsigned long field, u64 value)
* Switches to specified vcpu, until a matching vcpu_put(), but assumes
* vcpu mutex is already taken.
*/
-static struct kvm_vcpu *vmx_vcpu_load(struct kvm_vcpu *vcpu)
+static void vmx_vcpu_load(struct kvm_vcpu *vcpu)
{
u64 phys_addr = __pa(vcpu->vmcs);
int cpu;
@@ -242,7 +242,6 @@ static struct kvm_vcpu *vmx_vcpu_load(struct kvm_vcpu *vcpu)
rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp);
vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */
}
- return vcpu;
}
static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
@@ -418,10 +417,9 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
case MSR_IA32_SYSENTER_ESP:
vmcs_write32(GUEST_SYSENTER_ESP, data);
break;
- case MSR_IA32_TIME_STAMP_COUNTER: {
+ case MSR_IA32_TIME_STAMP_COUNTER:
guest_write_tsc(data);
break;
- }
default:
msr = find_msr_entry(vcpu, msr_index);
if (msr) {
@@ -793,6 +791,9 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
*/
static void vmx_set_cr0_no_modeswitch(struct kvm_vcpu *vcpu, unsigned long cr0)
{
+ if (!vcpu->rmode.active && !(cr0 & CR0_PE_MASK))
+ enter_rmode(vcpu);
+
vcpu->rmode.active = ((cr0 & CR0_PE_MASK) == 0);
update_exception_bitmap(vcpu);
vmcs_writel(CR0_READ_SHADOW, cr0);
@@ -1467,6 +1468,18 @@ static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 0;
}
+static void
+vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
+{
+ /*
+ * Patch in the VMCALL instruction:
+ */
+ hypercall[0] = 0x0f;
+ hypercall[1] = 0x01;
+ hypercall[2] = 0xc1;
+ hypercall[3] = 0xc3;
+}
+
static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
u64 exit_qualification;
@@ -1643,6 +1656,12 @@ static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 0;
}
+static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ vmcs_writel(GUEST_RIP, vmcs_readl(GUEST_RIP)+3);
+ return kvm_hypercall(vcpu, kvm_run);
+}
+
/*
* The exit handlers return 1 if the exit was handled fully and guest execution
* may resume. Otherwise they set the kvm_run parameter to indicate what needs
@@ -1661,6 +1680,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
[EXIT_REASON_MSR_WRITE] = handle_wrmsr,
[EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window,
[EXIT_REASON_HLT] = handle_halt,
+ [EXIT_REASON_VMCALL] = handle_vmcall,
};
static const int kvm_vmx_max_exit_handlers =
@@ -2062,6 +2082,7 @@ static struct kvm_arch_ops vmx_arch_ops = {
.run = vmx_vcpu_run,
.skip_emulated_instruction = skip_emulated_instruction,
.vcpu_setup = vmx_vcpu_setup,
+ .patch_hypercall = vmx_patch_hypercall,
};
static int __init vmx_init(void)
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 7399ba79111..80acd08f0e9 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -82,6 +82,18 @@ config LEDS_WRAP
help
This option enables support for the PCEngines WRAP programmable LEDs.
+config LEDS_H1940
+ tristate "LED Support for iPAQ H1940 device"
+ depends LEDS_CLASS && ARCH_H1940
+ help
+ This option enables support for the LEDs on the h1940.
+
+config LEDS_COBALT
+ tristate "LED Support for Cobalt Server front LED"
+ depends on LEDS_CLASS && MIPS_COBALT
+ help
+ This option enables support for the front LED on Cobalt Server
+
comment "LED Triggers"
config LEDS_TRIGGERS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 500de3dc962..aa2c18efa5b 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -14,6 +14,8 @@ obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
+obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
+obj-$(CONFIG_LEDS_COBALT) += leds-cobalt.o
# LED Triggers
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
diff --git a/drivers/leds/leds-cobalt.c b/drivers/leds/leds-cobalt.c
new file mode 100644
index 00000000000..d16439ce5da
--- /dev/null
+++ b/drivers/leds/leds-cobalt.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2006 - Florian Fainelli <florian@openwrt.org>
+ *
+ * Control the Cobalt Qube/RaQ front LED
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/leds.h>
+#include <asm/mach-cobalt/cobalt.h>
+
+static void cobalt_led_set(struct led_classdev *led_cdev, enum led_brightness brightness)
+{
+ if (brightness)
+ COBALT_LED_PORT = COBALT_LED_BAR_LEFT | COBALT_LED_BAR_RIGHT;
+ else
+ COBALT_LED_PORT = 0;
+}
+
+static struct led_classdev cobalt_led = {
+ .name = "cobalt-front-led",
+ .brightness_set = cobalt_led_set,
+ .default_trigger = "ide-disk",
+};
+
+static int __init cobalt_led_init(void)
+{
+ return led_classdev_register(NULL, &cobalt_led);
+}
+
+static void __exit cobalt_led_exit(void)
+{
+ led_classdev_unregister(&cobalt_led);
+}
+
+module_init(cobalt_led_init);
+module_exit(cobalt_led_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Front LED support for Cobalt Server");
+MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
diff --git a/drivers/leds/leds-h1940.c b/drivers/leds/leds-h1940.c
new file mode 100644
index 00000000000..1d49d2ade55
--- /dev/null
+++ b/drivers/leds/leds-h1940.c
@@ -0,0 +1,163 @@
+/*
+ * drivers/leds/h1940-leds.c
+ * Copyright (c) Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * 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.
+ *
+ * H1940 leds driver
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/leds.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/hardware.h>
+#include <asm/arch/h1940-latch.h>
+
+/*
+ * Green led.
+ */
+void h1940_greenled_set(struct led_classdev *led_dev, enum led_brightness value)
+{
+ switch (value) {
+ case LED_HALF:
+ h1940_latch_control(0,H1940_LATCH_LED_FLASH);
+ s3c2410_gpio_setpin(S3C2410_GPA7,1);
+ break;
+ case LED_FULL:
+ h1940_latch_control(0,H1940_LATCH_LED_GREEN);
+ s3c2410_gpio_setpin(S3C2410_GPA7,1);
+ break;
+ default:
+ case LED_OFF:
+ h1940_latch_control(H1940_LATCH_LED_FLASH,0);
+ h1940_latch_control(H1940_LATCH_LED_GREEN,0);
+ s3c2410_gpio_setpin(S3C2410_GPA7,0);
+ break;
+ }
+}
+
+static struct led_classdev h1940_greenled = {
+ .name = "h1940:green",
+ .brightness_set = h1940_greenled_set,
+ .default_trigger = "h1940-charger",
+};
+
+/*
+ * Red led.
+ */
+void h1940_redled_set(struct led_classdev *led_dev, enum led_brightness value)
+{
+ switch (value) {
+ case LED_HALF:
+ h1940_latch_control(0,H1940_LATCH_LED_FLASH);
+ s3c2410_gpio_setpin(S3C2410_GPA1,1);
+ break;
+ case LED_FULL:
+ h1940_latch_control(0,H1940_LATCH_LED_RED);
+ s3c2410_gpio_setpin(S3C2410_GPA1,1);
+ break;
+ default:
+ case LED_OFF:
+ h1940_latch_control(H1940_LATCH_LED_FLASH,0);
+ h1940_latch_control(H1940_LATCH_LED_RED,0);
+ s3c2410_gpio_setpin(S3C2410_GPA1,0);
+ break;
+ }
+}
+
+static struct led_classdev h1940_redled = {
+ .name = "h1940:red",
+ .brightness_set = h1940_redled_set,
+ .default_trigger = "h1940-charger",
+};
+
+/*
+ * Blue led.
+ * (it can only be blue flashing led)
+ */
+void h1940_blueled_set(struct led_classdev *led_dev, enum led_brightness value)
+{
+ if (value) {
+ /* flashing Blue */
+ h1940_latch_control(0,H1940_LATCH_LED_FLASH);
+ s3c2410_gpio_setpin(S3C2410_GPA3,1);
+ } else {
+ h1940_latch_control(H1940_LATCH_LED_FLASH,0);
+ s3c2410_gpio_setpin(S3C2410_GPA3,0);
+ }
+
+}
+
+static struct led_classdev h1940_blueled = {
+ .name = "h1940:blue",
+ .brightness_set = h1940_blueled_set,
+ .default_trigger = "h1940-bluetooth",
+};
+
+static int __init h1940leds_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = led_classdev_register(&pdev->dev, &h1940_greenled);
+ if (ret)
+ goto err_green;
+
+ ret = led_classdev_register(&pdev->dev, &h1940_redled);
+ if (ret)
+ goto err_red;
+
+ ret = led_classdev_register(&pdev->dev, &h1940_blueled);
+ if (ret)
+ goto err_blue;
+
+ return 0;
+
+err_blue:
+ led_classdev_unregister(&h1940_redled);
+err_red:
+ led_classdev_unregister(&h1940_greenled);
+err_green:
+ return ret;
+}
+
+static int h1940leds_remove(struct platform_device *pdev)
+{
+ led_classdev_unregister(&h1940_greenled);
+ led_classdev_unregister(&h1940_redled);
+ led_classdev_unregister(&h1940_blueled);
+ return 0;
+}
+
+
+static struct platform_driver h1940leds_driver = {
+ .driver = {
+ .name = "h1940-leds",
+ },
+ .probe = h1940leds_probe,
+ .remove = h1940leds_remove,
+};
+
+
+static int __init h1940leds_init(void)
+{
+ return platform_driver_register(&h1940leds_driver);
+}
+
+static void __exit h1940leds_exit(void)
+{
+ platform_driver_unregister(&h1940leds_driver);
+}
+
+module_init(h1940leds_init);
+module_exit(h1940leds_exit);
+
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
+MODULE_DESCRIPTION("LED driver for the iPAQ H1940");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 05febfd9f07..6c06e825cff 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1296,27 +1296,17 @@ static struct super_type super_types[] = {
.sync_super = super_1_sync,
},
};
-
-static mdk_rdev_t * match_dev_unit(mddev_t *mddev, mdk_rdev_t *dev)
-{
- struct list_head *tmp;
- mdk_rdev_t *rdev;
-
- ITERATE_RDEV(mddev,rdev,tmp)
- if (rdev->bdev->bd_contains == dev->bdev->bd_contains)
- return rdev;
-
- return NULL;
-}
static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2)
{
- struct list_head *tmp;
- mdk_rdev_t *rdev;
+ struct list_head *tmp, *tmp2;
+ mdk_rdev_t *rdev, *rdev2;
ITERATE_RDEV(mddev1,rdev,tmp)
- if (match_dev_unit(mddev2, rdev))
- return 1;
+ ITERATE_RDEV(mddev2, rdev2, tmp2)
+ if (rdev->bdev->bd_contains ==
+ rdev2->bdev->bd_contains)
+ return 1;
return 0;
}
@@ -1325,8 +1315,7 @@ static LIST_HEAD(pending_raid_disks);
static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
{
- mdk_rdev_t *same_pdev;
- char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
+ char b[BDEVNAME_SIZE];
struct kobject *ko;
char *s;
@@ -1342,14 +1331,6 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
else
mddev->size = rdev->size;
}
- same_pdev = match_dev_unit(mddev, rdev);
- if (same_pdev)
- printk(KERN_WARNING
- "%s: WARNING: %s appears to be on the same physical"
- " disk as %s. True\n protection against single-disk"
- " failure might be compromised.\n",
- mdname(mddev), bdevname(rdev->bdev,b),
- bdevname(same_pdev->bdev,b2));
/* Verify rdev->desc_nr is unique.
* If it is -1, assign a free number, else
@@ -3109,6 +3090,36 @@ static int do_md_run(mddev_t * mddev)
return -EINVAL;
}
+ if (pers->sync_request) {
+ /* Warn if this is a potentially silly
+ * configuration.
+ */
+ char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
+ mdk_rdev_t *rdev2;
+ struct list_head *tmp2;
+ int warned = 0;
+ ITERATE_RDEV(mddev, rdev, tmp) {
+ ITERATE_RDEV(mddev, rdev2, tmp2) {
+ if (rdev < rdev2 &&
+ rdev->bdev->bd_contains ==
+ rdev2->bdev->bd_contains) {
+ printk(KERN_WARNING
+ "%s: WARNING: %s appears to be"
+ " on the same physical disk as"
+ " %s.\n",
+ mdname(mddev),
+ bdevname(rdev->bdev,b),
+ bdevname(rdev2->bdev,b2));
+ warned = 1;
+ }
+ }
+ }
+ if (warned)
+ printk(KERN_WARNING
+ "True protection against single-disk"
+ " failure might be compromised.\n");
+ }
+
mddev->recovery = 0;
mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */
mddev->barriers_work = 1;
@@ -3311,6 +3322,9 @@ static int do_md_stop(mddev_t * mddev, int mode)
set_disk_ro(disk, 0);
blk_queue_make_request(mddev->queue, md_fail_request);
mddev->pers->stop(mddev);
+ mddev->queue->merge_bvec_fn = NULL;
+ mddev->queue->unplug_fn = NULL;
+ mddev->queue->issue_flush_fn = NULL;
if (mddev->pers->sync_request)
sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
@@ -5343,6 +5357,44 @@ void md_do_sync(mddev_t *mddev)
EXPORT_SYMBOL_GPL(md_do_sync);
+static int remove_and_add_spares(mddev_t *mddev)
+{
+ mdk_rdev_t *rdev;
+ struct list_head *rtmp;
+ int spares = 0;
+
+ ITERATE_RDEV(mddev,rdev,rtmp)
+ if (rdev->raid_disk >= 0 &&
+ (test_bit(Faulty, &rdev->flags) ||
+ ! test_bit(In_sync, &rdev->flags)) &&
+ atomic_read(&rdev->nr_pending)==0) {
+ if (mddev->pers->hot_remove_disk(
+ mddev, rdev->raid_disk)==0) {
+ char nm[20];
+ sprintf(nm,"rd%d", rdev->raid_disk);
+ sysfs_remove_link(&mddev->kobj, nm);
+ rdev->raid_disk = -1;
+ }
+ }
+
+ if (mddev->degraded) {
+ ITERATE_RDEV(mddev,rdev,rtmp)
+ if (rdev->raid_disk < 0
+ && !test_bit(Faulty, &rdev->flags)) {
+ rdev->recovery_offset = 0;
+ if (mddev->pers->hot_add_disk(mddev,rdev)) {
+ char nm[20];
+ sprintf(nm, "rd%d", rdev->raid_disk);
+ sysfs_create_link(&mddev->kobj,
+ &rdev->kobj, nm);
+ spares++;
+ md_new_event(mddev);
+ } else
+ break;
+ }
+ }
+ return spares;
+}
/*
* This routine is regularly called by all per-raid-array threads to
* deal with generic issues like resync and super-block update.
@@ -5397,7 +5449,7 @@ void md_check_recovery(mddev_t *mddev)
return;
if (mddev_trylock(mddev)) {
- int spares =0;
+ int spares = 0;
spin_lock_irq(&mddev->write_lock);
if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
@@ -5460,35 +5512,13 @@ void md_check_recovery(mddev_t *mddev)
* Spare are also removed and re-added, to allow
* the personality to fail the re-add.
*/
- ITERATE_RDEV(mddev,rdev,rtmp)
- if (rdev->raid_disk >= 0 &&
- (test_bit(Faulty, &rdev->flags) || ! test_bit(In_sync, &rdev->flags)) &&
- atomic_read(&rdev->nr_pending)==0) {
- if (mddev->pers->hot_remove_disk(mddev, rdev->raid_disk)==0) {
- char nm[20];
- sprintf(nm,"rd%d", rdev->raid_disk);
- sysfs_remove_link(&mddev->kobj, nm);
- rdev->raid_disk = -1;
- }
- }
-
- if (mddev->degraded) {
- ITERATE_RDEV(mddev,rdev,rtmp)
- if (rdev->raid_disk < 0
- && !test_bit(Faulty, &rdev->flags)) {
- rdev->recovery_offset = 0;
- if (mddev->pers->hot_add_disk(mddev,rdev)) {
- char nm[20];
- sprintf(nm, "rd%d", rdev->raid_disk);
- sysfs_create_link(&mddev->kobj, &rdev->kobj, nm);
- spares++;
- md_new_event(mddev);
- } else
- break;
- }
- }
- if (spares) {
+ if (mddev->reshape_position != MaxSector) {
+ if (mddev->pers->check_reshape(mddev) != 0)
+ /* Cannot proceed */
+ goto unlock;
+ set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
+ } else if ((spares = remove_and_add_spares(mddev))) {
clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
} else if (mddev->recovery_cp < MaxSector) {
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index a9401c017e3..82249a69014 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -429,7 +429,7 @@ static sector_t raid10_find_virt(conf_t *conf, sector_t sector, int dev)
if (dev < 0)
dev += conf->raid_disks;
} else {
- while (sector > conf->stride) {
+ while (sector >= conf->stride) {
sector -= conf->stride;
if (dev < conf->near_copies)
dev += conf->raid_disks - conf->near_copies;
@@ -1801,6 +1801,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
for (k=0; k<conf->copies; k++)
if (r10_bio->devs[k].devnum == i)
break;
+ BUG_ON(k == conf->copies);
bio = r10_bio->devs[1].bio;
bio->bi_next = biolist;
biolist = bio;
@@ -2021,19 +2022,30 @@ static int run(mddev_t *mddev)
if (!conf->tmppage)
goto out_free_conf;
+ conf->mddev = mddev;
+ conf->raid_disks = mddev->raid_disks;
conf->near_copies = nc;
conf->far_copies = fc;
conf->copies = nc*fc;
conf->far_offset = fo;
conf->chunk_mask = (sector_t)(mddev->chunk_size>>9)-1;
conf->chunk_shift = ffz(~mddev->chunk_size) - 9;
+ size = mddev->size >> (conf->chunk_shift-1);
+ sector_div(size, fc);
+ size = size * conf->raid_disks;
+ sector_div(size, nc);
+ /* 'size' is now the number of chunks in the array */
+ /* calculate "used chunks per device" in 'stride' */
+ stride = size * conf->copies;
+ sector_div(stride, conf->raid_disks);
+ mddev->size = stride << (conf->chunk_shift-1);
+
if (fo)
- conf->stride = 1 << conf->chunk_shift;
- else {
- stride = mddev->size >> (conf->chunk_shift-1);
+ stride = 1;
+ else
sector_div(stride, fc);
- conf->stride = stride << conf->chunk_shift;
- }
+ conf->stride = stride << conf->chunk_shift;
+
conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc,
r10bio_pool_free, conf);
if (!conf->r10bio_pool) {
@@ -2063,8 +2075,6 @@ static int run(mddev_t *mddev)
disk->head_position = 0;
}
- conf->raid_disks = mddev->raid_disks;
- conf->mddev = mddev;
spin_lock_init(&conf->device_lock);
INIT_LIST_HEAD(&conf->retry_list);
@@ -2106,16 +2116,8 @@ static int run(mddev_t *mddev)
/*
* Ok, everything is just fine now
*/
- if (conf->far_offset) {
- size = mddev->size >> (conf->chunk_shift-1);
- size *= conf->raid_disks;
- size <<= conf->chunk_shift;
- sector_div(size, conf->far_copies);
- } else
- size = conf->stride * conf->raid_disks;
- sector_div(size, conf->near_copies);
- mddev->array_size = size/2;
- mddev->resync_max_sectors = size;
+ mddev->array_size = size << (conf->chunk_shift-1);
+ mddev->resync_max_sectors = size << conf->chunk_shift;
mddev->queue->unplug_fn = raid10_unplug;
mddev->queue->issue_flush_fn = raid10_issue_flush;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 11c3d7bfa79..54a1ad5eef4 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -1050,7 +1050,7 @@ static void compute_parity5(struct stripe_head *sh, int method)
static void compute_parity6(struct stripe_head *sh, int method)
{
raid6_conf_t *conf = sh->raid_conf;
- int i, pd_idx = sh->pd_idx, qd_idx, d0_idx, disks = conf->raid_disks, count;
+ int i, pd_idx = sh->pd_idx, qd_idx, d0_idx, disks = sh->disks, count;
struct bio *chosen;
/**** FIX THIS: This could be very bad if disks is close to 256 ****/
void *ptrs[disks];
@@ -1131,8 +1131,7 @@ static void compute_parity6(struct stripe_head *sh, int method)
/* Compute one missing block */
static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero)
{
- raid6_conf_t *conf = sh->raid_conf;
- int i, count, disks = conf->raid_disks;
+ int i, count, disks = sh->disks;
void *ptr[MAX_XOR_BLOCKS], *p;
int pd_idx = sh->pd_idx;
int qd_idx = raid6_next_disk(pd_idx, disks);
@@ -1170,8 +1169,7 @@ static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero)
/* Compute two missing blocks */
static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2)
{
- raid6_conf_t *conf = sh->raid_conf;
- int i, count, disks = conf->raid_disks;
+ int i, count, disks = sh->disks;
int pd_idx = sh->pd_idx;
int qd_idx = raid6_next_disk(pd_idx, disks);
int d0_idx = raid6_next_disk(qd_idx, disks);
@@ -1887,11 +1885,11 @@ static void handle_stripe5(struct stripe_head *sh)
static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
{
raid6_conf_t *conf = sh->raid_conf;
- int disks = conf->raid_disks;
+ int disks = sh->disks;
struct bio *return_bi= NULL;
struct bio *bi;
int i;
- int syncing;
+ int syncing, expanding, expanded;
int locked=0, uptodate=0, to_read=0, to_write=0, failed=0, written=0;
int non_overwrite = 0;
int failed_num[2] = {0, 0};
@@ -1909,6 +1907,8 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
clear_bit(STRIPE_DELAYED, &sh->state);
syncing = test_bit(STRIPE_SYNCING, &sh->state);
+ expanding = test_bit(STRIPE_EXPAND_SOURCE, &sh->state);
+ expanded = test_bit(STRIPE_EXPAND_READY, &sh->state);
/* Now to look around and see what can be done */
rcu_read_lock();
@@ -2114,13 +2114,15 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
* parity, or to satisfy requests
* or to load a block that is being partially written.
*/
- if (to_read || non_overwrite || (to_write && failed) || (syncing && (uptodate < disks))) {
+ if (to_read || non_overwrite || (to_write && failed) ||
+ (syncing && (uptodate < disks)) || expanding) {
for (i=disks; i--;) {
dev = &sh->dev[i];
if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
(dev->toread ||
(dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) ||
syncing ||
+ expanding ||
(failed >= 1 && (sh->dev[failed_num[0]].toread || to_write)) ||
(failed >= 2 && (sh->dev[failed_num[1]].toread || to_write))
)
@@ -2355,6 +2357,79 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
}
}
}
+
+ if (expanded && test_bit(STRIPE_EXPANDING, &sh->state)) {
+ /* Need to write out all blocks after computing P&Q */
+ sh->disks = conf->raid_disks;
+ sh->pd_idx = stripe_to_pdidx(sh->sector, conf,
+ conf->raid_disks);
+ compute_parity6(sh, RECONSTRUCT_WRITE);
+ for (i = conf->raid_disks ; i-- ; ) {
+ set_bit(R5_LOCKED, &sh->dev[i].flags);
+ locked++;
+ set_bit(R5_Wantwrite, &sh->dev[i].flags);
+ }
+ clear_bit(STRIPE_EXPANDING, &sh->state);
+ } else if (expanded) {
+ clear_bit(STRIPE_EXPAND_READY, &sh->state);
+ atomic_dec(&conf->reshape_stripes);
+ wake_up(&conf->wait_for_overlap);
+ md_done_sync(conf->mddev, STRIPE_SECTORS, 1);
+ }
+
+ if (expanding && locked == 0) {
+ /* We have read all the blocks in this stripe and now we need to
+ * copy some of them into a target stripe for expand.
+ */
+ clear_bit(STRIPE_EXPAND_SOURCE, &sh->state);
+ for (i = 0; i < sh->disks ; i++)
+ if (i != pd_idx && i != qd_idx) {
+ int dd_idx2, pd_idx2, j;
+ struct stripe_head *sh2;
+
+ sector_t bn = compute_blocknr(sh, i);
+ sector_t s = raid5_compute_sector(
+ bn, conf->raid_disks,
+ conf->raid_disks - conf->max_degraded,
+ &dd_idx2, &pd_idx2, conf);
+ sh2 = get_active_stripe(conf, s,
+ conf->raid_disks,
+ pd_idx2, 1);
+ if (sh2 == NULL)
+ /* so for only the early blocks of
+ * this stripe have been requests.
+ * When later blocks get requests, we
+ * will try again
+ */
+ continue;
+ if (!test_bit(STRIPE_EXPANDING, &sh2->state) ||
+ test_bit(R5_Expanded,
+ &sh2->dev[dd_idx2].flags)) {
+ /* must have already done this block */
+ release_stripe(sh2);
+ continue;
+ }
+ memcpy(page_address(sh2->dev[dd_idx2].page),
+ page_address(sh->dev[i].page),
+ STRIPE_SIZE);
+ set_bit(R5_Expanded, &sh2->dev[dd_idx2].flags);
+ set_bit(R5_UPTODATE, &sh2->dev[dd_idx2].flags);
+ for (j = 0 ; j < conf->raid_disks ; j++)
+ if (j != sh2->pd_idx &&
+ j != raid6_next_disk(sh2->pd_idx,
+ sh2->disks) &&
+ !test_bit(R5_Expanded,
+ &sh2->dev[j].flags))
+ break;
+ if (j == conf->raid_disks) {
+ set_bit(STRIPE_EXPAND_READY,
+ &sh2->state);
+ set_bit(STRIPE_HANDLE, &sh2->state);
+ }
+ release_stripe(sh2);
+ }
+ }
+
spin_unlock(&sh->lock);
while ((bi=return_bi)) {
@@ -2395,7 +2470,7 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
rcu_read_unlock();
if (rdev) {
- if (syncing)
+ if (syncing || expanding || expanded)
md_sync_acct(rdev->bdev, STRIPE_SECTORS);
bi->bi_bdev = rdev->bdev;
@@ -2915,8 +2990,9 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
struct stripe_head *sh;
int pd_idx;
sector_t first_sector, last_sector;
- int raid_disks;
- int data_disks;
+ int raid_disks = conf->previous_raid_disks;
+ int data_disks = raid_disks - conf->max_degraded;
+ int new_data_disks = conf->raid_disks - conf->max_degraded;
int i;
int dd_idx;
sector_t writepos, safepos, gap;
@@ -2925,7 +3001,7 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
conf->expand_progress != 0) {
/* restarting in the middle, skip the initial sectors */
sector_nr = conf->expand_progress;
- sector_div(sector_nr, conf->raid_disks-1);
+ sector_div(sector_nr, new_data_disks);
*skipped = 1;
return sector_nr;
}
@@ -2939,14 +3015,14 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
* to after where expand_lo old_maps to
*/
writepos = conf->expand_progress +
- conf->chunk_size/512*(conf->raid_disks-1);
- sector_div(writepos, conf->raid_disks-1);
+ conf->chunk_size/512*(new_data_disks);
+ sector_div(writepos, new_data_disks);
safepos = conf->expand_lo;
- sector_div(safepos, conf->previous_raid_disks-1);
+ sector_div(safepos, data_disks);
gap = conf->expand_progress - conf->expand_lo;
if (writepos >= safepos ||
- gap > (conf->raid_disks-1)*3000*2 /*3Meg*/) {
+ gap > (new_data_disks)*3000*2 /*3Meg*/) {
/* Cannot proceed until we've updated the superblock... */
wait_event(conf->wait_for_overlap,
atomic_read(&conf->reshape_stripes)==0);
@@ -2976,6 +3052,9 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
sector_t s;
if (j == sh->pd_idx)
continue;
+ if (conf->level == 6 &&
+ j == raid6_next_disk(sh->pd_idx, sh->disks))
+ continue;
s = compute_blocknr(sh, j);
if (s < (mddev->array_size<<1)) {
skipped = 1;
@@ -2992,28 +3071,27 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
release_stripe(sh);
}
spin_lock_irq(&conf->device_lock);
- conf->expand_progress = (sector_nr + i)*(conf->raid_disks-1);
+ conf->expand_progress = (sector_nr + i) * new_data_disks;
spin_unlock_irq(&conf->device_lock);
/* Ok, those stripe are ready. We can start scheduling
* reads on the source stripes.
* The source stripes are determined by mapping the first and last
* block on the destination stripes.
*/
- raid_disks = conf->previous_raid_disks;
- data_disks = raid_disks - 1;
first_sector =
- raid5_compute_sector(sector_nr*(conf->raid_disks-1),
+ raid5_compute_sector(sector_nr*(new_data_disks),
raid_disks, data_disks,
&dd_idx, &pd_idx, conf);
last_sector =
raid5_compute_sector((sector_nr+conf->chunk_size/512)
- *(conf->raid_disks-1) -1,
+ *(new_data_disks) -1,
raid_disks, data_disks,
&dd_idx, &pd_idx, conf);
if (last_sector >= (mddev->size<<1))
last_sector = (mddev->size<<1)-1;
while (first_sector <= last_sector) {
- pd_idx = stripe_to_pdidx(first_sector, conf, conf->previous_raid_disks);
+ pd_idx = stripe_to_pdidx(first_sector, conf,
+ conf->previous_raid_disks);
sh = get_active_stripe(conf, first_sector,
conf->previous_raid_disks, pd_idx, 0);
set_bit(STRIPE_EXPAND_SOURCE, &sh->state);
@@ -3348,35 +3426,44 @@ static int run(mddev_t *mddev)
*/
sector_t here_new, here_old;
int old_disks;
+ int max_degraded = (mddev->level == 5 ? 1 : 2);
if (mddev->new_level != mddev->level ||
mddev->new_layout != mddev->layout ||
mddev->new_chunk != mddev->chunk_size) {
- printk(KERN_ERR "raid5: %s: unsupported reshape required - aborting.\n",
+ printk(KERN_ERR "raid5: %s: unsupported reshape "
+ "required - aborting.\n",
mdname(mddev));
return -EINVAL;
}
if (mddev->delta_disks <= 0) {
- printk(KERN_ERR "raid5: %s: unsupported reshape (reduce disks) required - aborting.\n",
+ printk(KERN_ERR "raid5: %s: unsupported reshape "
+ "(reduce disks) required - aborting.\n",
mdname(mddev));
return -EINVAL;
}
old_disks = mddev->raid_disks - mddev->delta_disks;
/* reshape_position must be on a new-stripe boundary, and one
- * further up in new geometry must map after here in old geometry.
+ * further up in new geometry must map after here in old
+ * geometry.
*/
here_new = mddev->reshape_position;
- if (sector_div(here_new, (mddev->chunk_size>>9)*(mddev->raid_disks-1))) {
- printk(KERN_ERR "raid5: reshape_position not on a stripe boundary\n");
+ if (sector_div(here_new, (mddev->chunk_size>>9)*
+ (mddev->raid_disks - max_degraded))) {
+ printk(KERN_ERR "raid5: reshape_position not "
+ "on a stripe boundary\n");
return -EINVAL;
}
/* here_new is the stripe we will write to */
here_old = mddev->reshape_position;
- sector_div(here_old, (mddev->chunk_size>>9)*(old_disks-1));
- /* here_old is the first stripe that we might need to read from */
+ sector_div(here_old, (mddev->chunk_size>>9)*
+ (old_disks-max_degraded));
+ /* here_old is the first stripe that we might need to read
+ * from */
if (here_new >= here_old) {
/* Reading from the same stripe as writing to - bad */
- printk(KERN_ERR "raid5: reshape_position too early for auto-recovery - aborting.\n");
+ printk(KERN_ERR "raid5: reshape_position too early for "
+ "auto-recovery - aborting.\n");
return -EINVAL;
}
printk(KERN_INFO "raid5: reshape will continue\n");
@@ -3814,6 +3901,8 @@ static int raid5_check_reshape(mddev_t *mddev)
if (err)
return err;
+ if (mddev->degraded > conf->max_degraded)
+ return -EINVAL;
/* looks like we might be able to manage this */
return 0;
}
@@ -3827,8 +3916,7 @@ static int raid5_start_reshape(mddev_t *mddev)
int added_devices = 0;
unsigned long flags;
- if (mddev->degraded ||
- test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+ if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
return -EBUSY;
ITERATE_RDEV(mddev, rdev, rtmp)
@@ -3836,7 +3924,7 @@ static int raid5_start_reshape(mddev_t *mddev)
!test_bit(Faulty, &rdev->flags))
spares++;
- if (spares < mddev->delta_disks-1)
+ if (spares - mddev->degraded < mddev->delta_disks - conf->max_degraded)
/* Not enough devices even to make a degraded array
* of that size
*/
@@ -3899,7 +3987,8 @@ static void end_reshape(raid5_conf_t *conf)
struct block_device *bdev;
if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) {
- conf->mddev->array_size = conf->mddev->size * (conf->raid_disks-1);
+ conf->mddev->array_size = conf->mddev->size *
+ (conf->raid_disks - conf->max_degraded);
set_capacity(conf->mddev->gendisk, conf->mddev->array_size << 1);
conf->mddev->changed = 1;
@@ -3972,6 +4061,10 @@ static struct mdk_personality raid6_personality =
.spare_active = raid5_spare_active,
.sync_request = sync_request,
.resize = raid5_resize,
+#ifdef CONFIG_MD_RAID5_RESHAPE
+ .check_reshape = raid5_check_reshape,
+ .start_reshape = raid5_start_reshape,
+#endif
.quiesce = raid5_quiesce,
};
static struct mdk_personality raid5_personality =
diff --git a/drivers/md/raid6mmx.c b/drivers/md/raid6mmx.c
index 359157aaf9e..6181a5a3365 100644
--- a/drivers/md/raid6mmx.c
+++ b/drivers/md/raid6mmx.c
@@ -30,14 +30,8 @@ const struct raid6_mmx_constants {
static int raid6_have_mmx(void)
{
-#ifdef __KERNEL__
/* Not really "boot_cpu" but "all_cpus" */
return boot_cpu_has(X86_FEATURE_MMX);
-#else
- /* User space test code */
- u32 features = cpuid_features();
- return ( (features & (1<<23)) == (1<<23) );
-#endif
}
/*
@@ -48,13 +42,12 @@ static void raid6_mmx1_gen_syndrome(int disks, size_t bytes, void **ptrs)
u8 **dptr = (u8 **)ptrs;
u8 *p, *q;
int d, z, z0;
- raid6_mmx_save_t sa;
z0 = disks - 3; /* Highest data disk */
p = dptr[z0+1]; /* XOR parity */
q = dptr[z0+2]; /* RS syndrome */
- raid6_before_mmx(&sa);
+ kernel_fpu_begin();
asm volatile("movq %0,%%mm0" : : "m" (raid6_mmx_constants.x1d));
asm volatile("pxor %mm5,%mm5"); /* Zero temp */
@@ -78,7 +71,7 @@ static void raid6_mmx1_gen_syndrome(int disks, size_t bytes, void **ptrs)
asm volatile("pxor %mm4,%mm4");
}
- raid6_after_mmx(&sa);
+ kernel_fpu_end();
}
const struct raid6_calls raid6_mmxx1 = {
@@ -96,13 +89,12 @@ static void raid6_mmx2_gen_syndrome(int disks, size_t bytes, void **ptrs)
u8 **dptr = (u8 **)ptrs;
u8 *p, *q;
int d, z, z0;
- raid6_mmx_save_t sa;
z0 = disks - 3; /* Highest data disk */
p = dptr[z0+1]; /* XOR parity */
q = dptr[z0+2]; /* RS syndrome */
- raid6_before_mmx(&sa);
+ kernel_fpu_begin();
asm volatile("movq %0,%%mm0" : : "m" (raid6_mmx_constants.x1d));
asm volatile("pxor %mm5,%mm5"); /* Zero temp */
@@ -137,7 +129,7 @@ static void raid6_mmx2_gen_syndrome(int disks, size_t bytes, void **ptrs)
asm volatile("movq %%mm6,%0" : "=m" (q[d+8]));
}
- raid6_after_mmx(&sa);
+ kernel_fpu_end();
}
const struct raid6_calls raid6_mmxx2 = {
diff --git a/drivers/md/raid6sse1.c b/drivers/md/raid6sse1.c
index f7e7859f71a..f0a1ba8f40b 100644
--- a/drivers/md/raid6sse1.c
+++ b/drivers/md/raid6sse1.c
@@ -33,16 +33,10 @@ extern const struct raid6_mmx_constants {
static int raid6_have_sse1_or_mmxext(void)
{
-#ifdef __KERNEL__
/* Not really boot_cpu but "all_cpus" */
return boot_cpu_has(X86_FEATURE_MMX) &&
(boot_cpu_has(X86_FEATURE_XMM) ||
boot_cpu_has(X86_FEATURE_MMXEXT));
-#else
- /* User space test code - this incorrectly breaks on some Athlons */
- u32 features = cpuid_features();
- return ( (features & (5<<23)) == (5<<23) );
-#endif
}
/*
@@ -53,14 +47,12 @@ static void raid6_sse11_gen_syndrome(int disks, size_t bytes, void **ptrs)
u8 **dptr = (u8 **)ptrs;
u8 *p, *q;
int d, z, z0;
- raid6_mmx_save_t sa;
z0 = disks - 3; /* Highest data disk */
p = dptr[z0+1]; /* XOR parity */
q = dptr[z0+2]; /* RS syndrome */
- /* This is really MMX code, not SSE */
- raid6_before_mmx(&sa);
+ kernel_fpu_begin();
asm volatile("movq %0,%%mm0" : : "m" (raid6_mmx_constants.x1d));
asm volatile("pxor %mm5,%mm5"); /* Zero temp */
@@ -94,8 +86,8 @@ static void raid6_sse11_gen_syndrome(int disks, size_t bytes, void **ptrs)
asm volatile("movntq %%mm4,%0" : "=m" (q[d]));
}
- raid6_after_mmx(&sa);
asm volatile("sfence" : : : "memory");
+ kernel_fpu_end();
}
const struct raid6_calls raid6_sse1x1 = {
@@ -113,13 +105,12 @@ static void raid6_sse12_gen_syndrome(int disks, size_t bytes, void **ptrs)
u8 **dptr = (u8 **)ptrs;
u8 *p, *q;
int d, z, z0;
- raid6_mmx_save_t sa;
z0 = disks - 3; /* Highest data disk */
p = dptr[z0+1]; /* XOR parity */
q = dptr[z0+2]; /* RS syndrome */
- raid6_before_mmx(&sa);
+ kernel_fpu_begin();
asm volatile("movq %0,%%mm0" : : "m" (raid6_mmx_constants.x1d));
asm volatile("pxor %mm5,%mm5"); /* Zero temp */
@@ -157,8 +148,8 @@ static void raid6_sse12_gen_syndrome(int disks, size_t bytes, void **ptrs)
asm volatile("movntq %%mm6,%0" : "=m" (q[d+8]));
}
- raid6_after_mmx(&sa);
asm volatile("sfence" : :: "memory");
+ kernel_fpu_end();
}
const struct raid6_calls raid6_sse1x2 = {
diff --git a/drivers/md/raid6sse2.c b/drivers/md/raid6sse2.c
index b3aa7fe0877..0f019762a7c 100644
--- a/drivers/md/raid6sse2.c
+++ b/drivers/md/raid6sse2.c
@@ -30,17 +30,11 @@ static const struct raid6_sse_constants {
static int raid6_have_sse2(void)
{
-#ifdef __KERNEL__
/* Not really boot_cpu but "all_cpus" */
return boot_cpu_has(X86_FEATURE_MMX) &&
boot_cpu_has(X86_FEATURE_FXSR) &&
boot_cpu_has(X86_FEATURE_XMM) &&
boot_cpu_has(X86_FEATURE_XMM2);
-#else
- /* User space test code */
- u32 features = cpuid_features();
- return ( (features & (15<<23)) == (15<<23) );
-#endif
}
/*
@@ -51,13 +45,12 @@ static void raid6_sse21_gen_syndrome(int disks, size_t bytes, void **ptrs)
u8 **dptr = (u8 **)ptrs;
u8 *p, *q;
int d, z, z0;
- raid6_sse_save_t sa;
z0 = disks - 3; /* Highest data disk */
p = dptr[z0+1]; /* XOR parity */
q = dptr[z0+2]; /* RS syndrome */
- raid6_before_sse2(&sa);
+ kernel_fpu_begin();
asm volatile("movdqa %0,%%xmm0" : : "m" (raid6_sse_constants.x1d[0]));
asm volatile("pxor %xmm5,%xmm5"); /* Zero temp */
@@ -93,8 +86,8 @@ static void raid6_sse21_gen_syndrome(int disks, size_t bytes, void **ptrs)
asm volatile("pxor %xmm4,%xmm4");
}
- raid6_after_sse2(&sa);
asm volatile("sfence" : : : "memory");
+ kernel_fpu_end();
}
const struct raid6_calls raid6_sse2x1 = {
@@ -112,13 +105,12 @@ static void raid6_sse22_gen_syndrome(int disks, size_t bytes, void **ptrs)
u8 **dptr = (u8 **)ptrs;
u8 *p, *q;
int d, z, z0;
- raid6_sse_save_t sa;
z0 = disks - 3; /* Highest data disk */
p = dptr[z0+1]; /* XOR parity */
q = dptr[z0+2]; /* RS syndrome */
- raid6_before_sse2(&sa);
+ kernel_fpu_begin();
asm volatile("movdqa %0,%%xmm0" : : "m" (raid6_sse_constants.x1d[0]));
asm volatile("pxor %xmm5,%xmm5"); /* Zero temp */
@@ -156,8 +148,8 @@ static void raid6_sse22_gen_syndrome(int disks, size_t bytes, void **ptrs)
asm volatile("movntdq %%xmm6,%0" : "=m" (q[d+16]));
}
- raid6_after_sse2(&sa);
asm volatile("sfence" : : : "memory");
+ kernel_fpu_end();
}
const struct raid6_calls raid6_sse2x2 = {
@@ -179,13 +171,12 @@ static void raid6_sse24_gen_syndrome(int disks, size_t bytes, void **ptrs)
u8 **dptr = (u8 **)ptrs;
u8 *p, *q;
int d, z, z0;
- raid6_sse16_save_t sa;
z0 = disks - 3; /* Highest data disk */
p = dptr[z0+1]; /* XOR parity */
q = dptr[z0+2]; /* RS syndrome */
- raid6_before_sse16(&sa);
+ kernel_fpu_begin();
asm volatile("movdqa %0,%%xmm0" :: "m" (raid6_sse_constants.x1d[0]));
asm volatile("pxor %xmm2,%xmm2"); /* P[0] */
@@ -256,8 +247,9 @@ static void raid6_sse24_gen_syndrome(int disks, size_t bytes, void **ptrs)
asm volatile("movntdq %%xmm14,%0" : "=m" (q[d+48]));
asm volatile("pxor %xmm14,%xmm14");
}
+
asm volatile("sfence" : : : "memory");
- raid6_after_sse16(&sa);
+ kernel_fpu_end();
}
const struct raid6_calls raid6_sse2x4 = {
diff --git a/drivers/md/raid6x86.h b/drivers/md/raid6x86.h
index 4cf20534fe4..9111950414f 100644
--- a/drivers/md/raid6x86.h
+++ b/drivers/md/raid6x86.h
@@ -21,224 +21,40 @@
#if defined(__i386__) || defined(__x86_64__)
-#ifdef __x86_64__
-
-typedef struct {
- unsigned int fsave[27];
- unsigned long cr0;
-} raid6_mmx_save_t __attribute__((aligned(16)));
-
-/* N.B.: For SSE we only save %xmm0-%xmm7 even for x86-64, since
- the code doesn't know about the additional x86-64 registers */
-typedef struct {
- unsigned int sarea[8*4+2];
- unsigned long cr0;
-} raid6_sse_save_t __attribute__((aligned(16)));
-
-/* This is for x86-64-specific code which uses all 16 XMM registers */
-typedef struct {
- unsigned int sarea[16*4+2];
- unsigned long cr0;
-} raid6_sse16_save_t __attribute__((aligned(16)));
-
-/* On x86-64 the stack *SHOULD* be 16-byte aligned, but currently this
- is buggy in the kernel and it's only 8-byte aligned in places, so
- we need to do this anyway. Sigh. */
-#define SAREA(x) ((unsigned int *)((((unsigned long)&(x)->sarea)+15) & ~15))
-
-#else /* __i386__ */
-
-typedef struct {
- unsigned int fsave[27];
- unsigned long cr0;
-} raid6_mmx_save_t;
-
-/* On i386, the stack is only 8-byte aligned, but SSE requires 16-byte
- alignment. The +3 is so we have the slack space to manually align
- a properly-sized area correctly. */
-typedef struct {
- unsigned int sarea[8*4+3];
- unsigned long cr0;
-} raid6_sse_save_t;
-
-/* Find the 16-byte aligned save area */
-#define SAREA(x) ((unsigned int *)((((unsigned long)&(x)->sarea)+15) & ~15))
-
-#endif
-
#ifdef __KERNEL__ /* Real code */
-/* Note: %cr0 is 32 bits on i386 and 64 bits on x86-64 */
-
-static inline unsigned long raid6_get_fpu(void)
-{
- unsigned long cr0;
-
- preempt_disable();
- asm volatile("mov %%cr0,%0 ; clts" : "=r" (cr0));
- return cr0;
-}
-
-static inline void raid6_put_fpu(unsigned long cr0)
-{
- asm volatile("mov %0,%%cr0" : : "r" (cr0));
- preempt_enable();
-}
+#include <asm/i387.h>
#else /* Dummy code for user space testing */
-static inline unsigned long raid6_get_fpu(void)
-{
- return 0xf00ba6;
-}
-
-static inline void raid6_put_fpu(unsigned long cr0)
-{
- (void)cr0;
-}
-
-#endif
-
-static inline void raid6_before_mmx(raid6_mmx_save_t *s)
-{
- s->cr0 = raid6_get_fpu();
- asm volatile("fsave %0 ; fwait" : "=m" (s->fsave[0]));
-}
-
-static inline void raid6_after_mmx(raid6_mmx_save_t *s)
-{
- asm volatile("frstor %0" : : "m" (s->fsave[0]));
- raid6_put_fpu(s->cr0);
-}
-
-static inline void raid6_before_sse(raid6_sse_save_t *s)
-{
- unsigned int *rsa = SAREA(s);
-
- s->cr0 = raid6_get_fpu();
-
- asm volatile("movaps %%xmm0,%0" : "=m" (rsa[0]));
- asm volatile("movaps %%xmm1,%0" : "=m" (rsa[4]));
- asm volatile("movaps %%xmm2,%0" : "=m" (rsa[8]));
- asm volatile("movaps %%xmm3,%0" : "=m" (rsa[12]));
- asm volatile("movaps %%xmm4,%0" : "=m" (rsa[16]));
- asm volatile("movaps %%xmm5,%0" : "=m" (rsa[20]));
- asm volatile("movaps %%xmm6,%0" : "=m" (rsa[24]));
- asm volatile("movaps %%xmm7,%0" : "=m" (rsa[28]));
-}
-
-static inline void raid6_after_sse(raid6_sse_save_t *s)
-{
- unsigned int *rsa = SAREA(s);
-
- asm volatile("movaps %0,%%xmm0" : : "m" (rsa[0]));
- asm volatile("movaps %0,%%xmm1" : : "m" (rsa[4]));
- asm volatile("movaps %0,%%xmm2" : : "m" (rsa[8]));
- asm volatile("movaps %0,%%xmm3" : : "m" (rsa[12]));
- asm volatile("movaps %0,%%xmm4" : : "m" (rsa[16]));
- asm volatile("movaps %0,%%xmm5" : : "m" (rsa[20]));
- asm volatile("movaps %0,%%xmm6" : : "m" (rsa[24]));
- asm volatile("movaps %0,%%xmm7" : : "m" (rsa[28]));
-
- raid6_put_fpu(s->cr0);
-}
-
-static inline void raid6_before_sse2(raid6_sse_save_t *s)
+static inline void kernel_fpu_begin(void)
{
- unsigned int *rsa = SAREA(s);
-
- s->cr0 = raid6_get_fpu();
-
- asm volatile("movdqa %%xmm0,%0" : "=m" (rsa[0]));
- asm volatile("movdqa %%xmm1,%0" : "=m" (rsa[4]));
- asm volatile("movdqa %%xmm2,%0" : "=m" (rsa[8]));
- asm volatile("movdqa %%xmm3,%0" : "=m" (rsa[12]));
- asm volatile("movdqa %%xmm4,%0" : "=m" (rsa[16]));
- asm volatile("movdqa %%xmm5,%0" : "=m" (rsa[20]));
- asm volatile("movdqa %%xmm6,%0" : "=m" (rsa[24]));
- asm volatile("movdqa %%xmm7,%0" : "=m" (rsa[28]));
}
-static inline void raid6_after_sse2(raid6_sse_save_t *s)
+static inline void kernel_fpu_end(void)
{
- unsigned int *rsa = SAREA(s);
-
- asm volatile("movdqa %0,%%xmm0" : : "m" (rsa[0]));
- asm volatile("movdqa %0,%%xmm1" : : "m" (rsa[4]));
- asm volatile("movdqa %0,%%xmm2" : : "m" (rsa[8]));
- asm volatile("movdqa %0,%%xmm3" : : "m" (rsa[12]));
- asm volatile("movdqa %0,%%xmm4" : : "m" (rsa[16]));
- asm volatile("movdqa %0,%%xmm5" : : "m" (rsa[20]));
- asm volatile("movdqa %0,%%xmm6" : : "m" (rsa[24]));
- asm volatile("movdqa %0,%%xmm7" : : "m" (rsa[28]));
-
- raid6_put_fpu(s->cr0);
}
-#ifdef __x86_64__
-
-static inline void raid6_before_sse16(raid6_sse16_save_t *s)
-{
- unsigned int *rsa = SAREA(s);
-
- s->cr0 = raid6_get_fpu();
+#define X86_FEATURE_MMX (0*32+23) /* Multimedia Extensions */
+#define X86_FEATURE_FXSR (0*32+24) /* FXSAVE and FXRSTOR instructions
+ * (fast save and restore) */
+#define X86_FEATURE_XMM (0*32+25) /* Streaming SIMD Extensions */
+#define X86_FEATURE_XMM2 (0*32+26) /* Streaming SIMD Extensions-2 */
+#define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */
- asm volatile("movdqa %%xmm0,%0" : "=m" (rsa[0]));
- asm volatile("movdqa %%xmm1,%0" : "=m" (rsa[4]));
- asm volatile("movdqa %%xmm2,%0" : "=m" (rsa[8]));
- asm volatile("movdqa %%xmm3,%0" : "=m" (rsa[12]));
- asm volatile("movdqa %%xmm4,%0" : "=m" (rsa[16]));
- asm volatile("movdqa %%xmm5,%0" : "=m" (rsa[20]));
- asm volatile("movdqa %%xmm6,%0" : "=m" (rsa[24]));
- asm volatile("movdqa %%xmm7,%0" : "=m" (rsa[28]));
- asm volatile("movdqa %%xmm8,%0" : "=m" (rsa[32]));
- asm volatile("movdqa %%xmm9,%0" : "=m" (rsa[36]));
- asm volatile("movdqa %%xmm10,%0" : "=m" (rsa[40]));
- asm volatile("movdqa %%xmm11,%0" : "=m" (rsa[44]));
- asm volatile("movdqa %%xmm12,%0" : "=m" (rsa[48]));
- asm volatile("movdqa %%xmm13,%0" : "=m" (rsa[52]));
- asm volatile("movdqa %%xmm14,%0" : "=m" (rsa[56]));
- asm volatile("movdqa %%xmm15,%0" : "=m" (rsa[60]));
-}
-
-static inline void raid6_after_sse16(raid6_sse16_save_t *s)
+/* Should work well enough on modern CPUs for testing */
+static inline int boot_cpu_has(int flag)
{
- unsigned int *rsa = SAREA(s);
+ u32 eax = (flag >> 5) ? 0x80000001 : 1;
+ u32 edx;
- asm volatile("movdqa %0,%%xmm0" : : "m" (rsa[0]));
- asm volatile("movdqa %0,%%xmm1" : : "m" (rsa[4]));
- asm volatile("movdqa %0,%%xmm2" : : "m" (rsa[8]));
- asm volatile("movdqa %0,%%xmm3" : : "m" (rsa[12]));
- asm volatile("movdqa %0,%%xmm4" : : "m" (rsa[16]));
- asm volatile("movdqa %0,%%xmm5" : : "m" (rsa[20]));
- asm volatile("movdqa %0,%%xmm6" : : "m" (rsa[24]));
- asm volatile("movdqa %0,%%xmm7" : : "m" (rsa[28]));
- asm volatile("movdqa %0,%%xmm8" : : "m" (rsa[32]));
- asm volatile("movdqa %0,%%xmm9" : : "m" (rsa[36]));
- asm volatile("movdqa %0,%%xmm10" : : "m" (rsa[40]));
- asm volatile("movdqa %0,%%xmm11" : : "m" (rsa[44]));
- asm volatile("movdqa %0,%%xmm12" : : "m" (rsa[48]));
- asm volatile("movdqa %0,%%xmm13" : : "m" (rsa[52]));
- asm volatile("movdqa %0,%%xmm14" : : "m" (rsa[56]));
- asm volatile("movdqa %0,%%xmm15" : : "m" (rsa[60]));
+ asm volatile("cpuid"
+ : "+a" (eax), "=d" (edx)
+ : : "ecx", "ebx");
- raid6_put_fpu(s->cr0);
+ return (edx >> (flag & 31)) & 1;
}
-#endif /* __x86_64__ */
-
-/* User space test hack */
-#ifndef __KERNEL__
-static inline int cpuid_features(void)
-{
- u32 eax = 1;
- u32 ebx, ecx, edx;
-
- asm volatile("cpuid" :
- "+a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx));
-
- return edx;
-}
#endif /* ndef __KERNEL__ */
#endif
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 87410dbd3df..91d25798ae4 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -70,6 +70,7 @@ config VIDEO_TUNER
depends on I2C
config VIDEO_BUF
+ depends on PCI
tristate
config VIDEO_BUF_DVB
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index f33e5d97341..c120114c241 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -5,8 +5,4 @@ config VIDEO_SAA7146
config VIDEO_SAA7146_VV
tristate
select VIDEO_BUF
- select VIDEO_VIDEOBUF
select VIDEO_SAA7146
-
-config VIDEO_VIDEOBUF
- tristate
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index 9a8dd8764c9..cbf7c056488 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -256,6 +256,112 @@ int ir_decode_biphase(u32 *samples, int count, int low, int high)
return value;
}
+/* RC5 decoding stuff, moved from bttv-input.c to share it with
+ * saa7134 */
+
+/* decode raw bit pattern to RC5 code */
+u32 ir_rc5_decode(unsigned int code)
+{
+ unsigned int org_code = code;
+ unsigned int pair;
+ unsigned int rc5 = 0;
+ int i;
+
+ for (i = 0; i < 14; ++i) {
+ pair = code & 0x3;
+ code >>= 2;
+
+ rc5 <<= 1;
+ switch (pair) {
+ case 0:
+ case 2:
+ break;
+ case 1:
+ rc5 |= 1;
+ break;
+ case 3:
+ dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);
+ return 0;
+ }
+ }
+ dprintk(1, "ir-common: code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
+ "instr=%x\n", rc5, org_code, RC5_START(rc5),
+ RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
+ return rc5;
+}
+
+void ir_rc5_timer_end(unsigned long data)
+{
+ struct card_ir *ir = (struct card_ir *)data;
+ struct timeval tv;
+ unsigned long current_jiffies, timeout;
+ u32 gap;
+ u32 rc5 = 0;
+
+ /* get time */
+ current_jiffies = jiffies;
+ do_gettimeofday(&tv);
+
+ /* avoid overflow with gap >1s */
+ if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+ gap = 200000;
+ } else {
+ gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+ tv.tv_usec - ir->base_time.tv_usec;
+ }
+
+ /* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */
+ if (gap < 28000) {
+ dprintk(1, "ir-common: spurious timer_end\n");
+ return;
+ }
+
+ ir->active = 0;
+ if (ir->last_bit < 20) {
+ /* ignore spurious codes (caused by light/other remotes) */
+ dprintk(1, "ir-common: short code: %x\n", ir->code);
+ } else {
+ ir->code = (ir->code << ir->shift_by) | 1;
+ rc5 = ir_rc5_decode(ir->code);
+
+ /* two start bits? */
+ if (RC5_START(rc5) != ir->start) {
+ dprintk(1, "ir-common: rc5 start bits invalid: %u\n", RC5_START(rc5));
+
+ /* right address? */
+ } else if (RC5_ADDR(rc5) == ir->addr) {
+ u32 toggle = RC5_TOGGLE(rc5);
+ u32 instr = RC5_INSTR(rc5);
+
+ /* Good code, decide if repeat/repress */
+ if (toggle != RC5_TOGGLE(ir->last_rc5) ||
+ instr != RC5_INSTR(ir->last_rc5)) {
+ dprintk(1, "ir-common: instruction %x, toggle %x\n", instr,
+ toggle);
+ ir_input_nokey(ir->dev, &ir->ir);
+ ir_input_keydown(ir->dev, &ir->ir, instr,
+ instr);
+ }
+
+ /* Set/reset key-up timer */
+ timeout = current_jiffies + (500 + ir->rc5_key_timeout
+ * HZ) / 1000;
+ mod_timer(&ir->timer_keyup, timeout);
+
+ /* Save code for repeat test */
+ ir->last_rc5 = rc5;
+ }
+ }
+}
+
+void ir_rc5_timer_keyup(unsigned long data)
+{
+ struct card_ir *ir = (struct card_ir *)data;
+
+ dprintk(1, "ir-common: key released\n");
+ ir_input_nokey(ir->dev, &ir->ir);
+}
+
EXPORT_SYMBOL_GPL(ir_input_init);
EXPORT_SYMBOL_GPL(ir_input_nokey);
EXPORT_SYMBOL_GPL(ir_input_keydown);
@@ -265,6 +371,10 @@ EXPORT_SYMBOL_GPL(ir_dump_samples);
EXPORT_SYMBOL_GPL(ir_decode_biphase);
EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
+EXPORT_SYMBOL_GPL(ir_rc5_decode);
+EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
+EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
+
/*
* Local variables:
* c-basic-offset: 8
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index 0e948a5c5a0..03b47a262f2 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -1606,3 +1606,174 @@ IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE] = {
};
EXPORT_SYMBOL_GPL(ir_codes_budget_ci_old);
+
+/*
+ * Marc Fargas <telenieko@telenieko.com>
+ * this is the remote control that comes with the asus p7131
+ * which has a label saying is "Model PC-39"
+ */
+IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE] = {
+ /* Keys 0 to 9 */
+ [ 0x15 ] = KEY_0,
+ [ 0x29 ] = KEY_1,
+ [ 0x2d ] = KEY_2,
+ [ 0x2b ] = KEY_3,
+ [ 0x09 ] = KEY_4,
+ [ 0x0d ] = KEY_5,
+ [ 0x0b ] = KEY_6,
+ [ 0x31 ] = KEY_7,
+ [ 0x35 ] = KEY_8,
+ [ 0x33 ] = KEY_9,
+
+ [ 0x3e ] = KEY_RADIO, /* radio */
+ [ 0x03 ] = KEY_MENU, /* dvd/menu */
+ [ 0x2a ] = KEY_VOLUMEUP,
+ [ 0x19 ] = KEY_VOLUMEDOWN,
+ [ 0x37 ] = KEY_UP,
+ [ 0x3b ] = KEY_DOWN,
+ [ 0x27 ] = KEY_LEFT,
+ [ 0x2f ] = KEY_RIGHT,
+ [ 0x25 ] = KEY_VIDEO, /* video */
+ [ 0x39 ] = KEY_AUDIO, /* music */
+
+ [ 0x21 ] = KEY_TV, /* tv */
+ [ 0x1d ] = KEY_EXIT, /* back */
+ [ 0x0a ] = KEY_CHANNELUP, /* channel / program + */
+ [ 0x1b ] = KEY_CHANNELDOWN, /* channel / program - */
+ [ 0x1a ] = KEY_ENTER, /* enter */
+
+ [ 0x06 ] = KEY_PAUSE, /* play/pause */
+ [ 0x1e ] = KEY_PREVIOUS, /* rew */
+ [ 0x26 ] = KEY_NEXT, /* forward */
+ [ 0x0e ] = KEY_REWIND, /* backward << */
+ [ 0x3a ] = KEY_FASTFORWARD, /* forward >> */
+ [ 0x36 ] = KEY_STOP,
+ [ 0x2e ] = KEY_RECORD, /* recording */
+ [ 0x16 ] = KEY_POWER, /* the button that reads "close" */
+
+ [ 0x11 ] = KEY_ZOOM, /* full screen */
+ [ 0x13 ] = KEY_MACRO, /* recall */
+ [ 0x23 ] = KEY_HOME, /* home */
+ [ 0x05 ] = KEY_PVR, /* picture */
+ [ 0x3d ] = KEY_MUTE, /* mute */
+ [ 0x01 ] = KEY_DVD, /* dvd */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_asus_pc39);
+
+
+/* Encore ENLTV-FM - black plastic, white front cover with white glowing buttons
+ Juan Pablo Sormani <sorman@gmail.com> */
+IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE] = {
+
+ /* Power button does nothing, neither in Windows app,
+ although it sends data (used for BIOS wakeup?) */
+ [ 0x0d ] = KEY_MUTE,
+
+ [ 0x1e ] = KEY_TV,
+ [ 0x00 ] = KEY_VIDEO,
+ [ 0x01 ] = KEY_AUDIO, /* music */
+ [ 0x02 ] = KEY_MHP, /* picture */
+
+ [ 0x1f ] = KEY_1,
+ [ 0x03 ] = KEY_2,
+ [ 0x04 ] = KEY_3,
+ [ 0x05 ] = KEY_4,
+ [ 0x1c ] = KEY_5,
+ [ 0x06 ] = KEY_6,
+ [ 0x07 ] = KEY_7,
+ [ 0x08 ] = KEY_8,
+ [ 0x1d ] = KEY_9,
+ [ 0x0a ] = KEY_0,
+
+ [ 0x09 ] = KEY_LIST, /* -/-- */
+ [ 0x0b ] = KEY_LAST, /* recall */
+
+ [ 0x14 ] = KEY_HOME, /* win start menu */
+ [ 0x15 ] = KEY_EXIT, /* exit */
+ [ 0x16 ] = KEY_UP,
+ [ 0x12 ] = KEY_DOWN,
+ [ 0x0c ] = KEY_RIGHT,
+ [ 0x17 ] = KEY_LEFT,
+
+ [ 0x18 ] = KEY_ENTER, /* OK */
+
+ [ 0x0e ] = KEY_ESC,
+ [ 0x13 ] = KEY_D, /* desktop */
+ [ 0x11 ] = KEY_TAB,
+ [ 0x19 ] = KEY_SWITCHVIDEOMODE, /* switch */
+
+ [ 0x1a ] = KEY_MENU,
+ [ 0x1b ] = KEY_ZOOM, /* fullscreen */
+ [ 0x44 ] = KEY_TIME, /* time shift */
+ [ 0x40 ] = KEY_MODE, /* source */
+
+ [ 0x5a ] = KEY_RECORD,
+ [ 0x42 ] = KEY_PLAY, /* play/pause */
+ [ 0x45 ] = KEY_STOP,
+ [ 0x43 ] = KEY_CAMERA, /* camera icon */
+
+ [ 0x48 ] = KEY_REWIND,
+ [ 0x4a ] = KEY_FASTFORWARD,
+ [ 0x49 ] = KEY_PREVIOUS,
+ [ 0x4b ] = KEY_NEXT,
+
+ [ 0x4c ] = KEY_FAVORITES, /* tv wall */
+ [ 0x4d ] = KEY_SOUND, /* DVD sound */
+ [ 0x4e ] = KEY_LANGUAGE, /* DVD lang */
+ [ 0x4f ] = KEY_TEXT, /* DVD text */
+
+ [ 0x50 ] = KEY_SLEEP, /* shutdown */
+ [ 0x51 ] = KEY_MODE, /* stereo > main */
+ [ 0x52 ] = KEY_SELECT, /* stereo > sap */
+ [ 0x53 ] = KEY_PROG1, /* teletext */
+
+
+ [ 0x59 ] = KEY_RED, /* AP1 */
+ [ 0x41 ] = KEY_GREEN, /* AP2 */
+ [ 0x47 ] = KEY_YELLOW, /* AP3 */
+ [ 0x57 ] = KEY_BLUE, /* AP4 */
+
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_encore_enltv);
+
+/* for the Technotrend 1500 bundled remote: */
+IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = {
+ [ 0x01 ] = KEY_POWER,
+ [ 0x02 ] = KEY_SHUFFLE, /* ? double-arrow key */
+ [ 0x03 ] = KEY_1,
+ [ 0x04 ] = KEY_2,
+ [ 0x05 ] = KEY_3,
+ [ 0x06 ] = KEY_4,
+ [ 0x07 ] = KEY_5,
+ [ 0x08 ] = KEY_6,
+ [ 0x09 ] = KEY_7,
+ [ 0x0a ] = KEY_8,
+ [ 0x0b ] = KEY_9,
+ [ 0x0c ] = KEY_0,
+ [ 0x0d ] = KEY_UP,
+ [ 0x0e ] = KEY_LEFT,
+ [ 0x0f ] = KEY_OK,
+ [ 0x10 ] = KEY_RIGHT,
+ [ 0x11 ] = KEY_DOWN,
+ [ 0x12 ] = KEY_INFO,
+ [ 0x13 ] = KEY_EXIT,
+ [ 0x14 ] = KEY_RED,
+ [ 0x15 ] = KEY_GREEN,
+ [ 0x16 ] = KEY_YELLOW,
+ [ 0x17 ] = KEY_BLUE,
+ [ 0x18 ] = KEY_MUTE,
+ [ 0x19 ] = KEY_TEXT,
+ [ 0x1a ] = KEY_MODE, /* ? TV/Radio */
+ [ 0x21 ] = KEY_OPTION,
+ [ 0x22 ] = KEY_EPG,
+ [ 0x23 ] = KEY_CHANNELUP,
+ [ 0x24 ] = KEY_CHANNELDOWN,
+ [ 0x25 ] = KEY_VOLUMEUP,
+ [ 0x26 ] = KEY_VOLUMEDOWN,
+ [ 0x27 ] = KEY_SETUP,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_tt_1500);
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index b8dcfa16526..c18a5da6493 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -508,7 +508,7 @@ int saa7146_vv_release(struct saa7146_dev* dev)
DEB_EE(("dev:%p\n",dev));
- pci_free_consistent(dev->pci, SAA7146_RPS_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
+ pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
kfree(vv);
dev->vv_data = NULL;
dev->vv_callback = NULL;
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index c2b35e36624..752cf79c532 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -385,9 +385,9 @@ static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
else buf[3] = 0x88;
if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
+ fe->ops.i2c_gate_ctrl(fe, 0);
deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]);
- ret = fc->i2c_request(fc,FC_WRITE,FC_I2C_PORT_TUNER,0x61,buf[0],&buf[1],3);
+ ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_TUNER, 0x61, buf[0], &buf[1], 3);
deb_tuner("tuner write returned: %d\n",ret);
return 0;
@@ -398,91 +398,71 @@ static u8 alps_tdee4_stv0297_inittab[] = {
0x80, 0x00,
0x81, 0x01,
0x81, 0x00,
- 0x00, 0x09,
- 0x01, 0x69,
+ 0x00, 0x48,
+ 0x01, 0x58,
0x03, 0x00,
0x04, 0x00,
0x07, 0x00,
0x08, 0x00,
- 0x20, 0x00,
- 0x21, 0x40,
- 0x22, 0x00,
- 0x23, 0x00,
- 0x24, 0x40,
- 0x25, 0x88,
0x30, 0xff,
- 0x31, 0x00,
+ 0x31, 0x9d,
0x32, 0xff,
0x33, 0x00,
- 0x34, 0x50,
- 0x35, 0x7f,
- 0x36, 0x00,
- 0x37, 0x20,
- 0x38, 0x00,
- 0x40, 0x1c,
- 0x41, 0xff,
- 0x42, 0x29,
+ 0x34, 0x29,
+ 0x35, 0x55,
+ 0x36, 0x80,
+ 0x37, 0x6e,
+ 0x38, 0x9c,
+ 0x40, 0x1a,
+ 0x41, 0xfe,
+ 0x42, 0x33,
0x43, 0x00,
0x44, 0xff,
0x45, 0x00,
0x46, 0x00,
0x49, 0x04,
- 0x4a, 0x00,
+ 0x4a, 0x51,
0x4b, 0xf8,
0x52, 0x30,
- 0x55, 0xae,
- 0x56, 0x47,
- 0x57, 0xe1,
- 0x58, 0x3a,
- 0x5a, 0x1e,
- 0x5b, 0x34,
- 0x60, 0x00,
- 0x63, 0x00,
- 0x64, 0x00,
- 0x65, 0x00,
- 0x66, 0x00,
- 0x67, 0x00,
- 0x68, 0x00,
- 0x69, 0x00,
- 0x6a, 0x02,
- 0x6b, 0x00,
+ 0x53, 0x06,
+ 0x59, 0x06,
+ 0x5a, 0x5e,
+ 0x5b, 0x04,
+ 0x61, 0x49,
+ 0x62, 0x0a,
0x70, 0xff,
- 0x71, 0x00,
+ 0x71, 0x04,
0x72, 0x00,
0x73, 0x00,
0x74, 0x0c,
- 0x80, 0x00,
+ 0x80, 0x20,
0x81, 0x00,
- 0x82, 0x00,
+ 0x82, 0x30,
0x83, 0x00,
0x84, 0x04,
- 0x85, 0x80,
- 0x86, 0x24,
- 0x87, 0x78,
- 0x88, 0x10,
+ 0x85, 0x22,
+ 0x86, 0x08,
+ 0x87, 0x1b,
+ 0x88, 0x00,
0x89, 0x00,
- 0x90, 0x01,
- 0x91, 0x01,
- 0xa0, 0x04,
+ 0x90, 0x00,
+ 0x91, 0x04,
+ 0xa0, 0x86,
0xa1, 0x00,
0xa2, 0x00,
0xb0, 0x91,
0xb1, 0x0b,
- 0xc0, 0x53,
- 0xc1, 0x70,
+ 0xc0, 0x5b,
+ 0xc1, 0x10,
0xc2, 0x12,
- 0xd0, 0x00,
+ 0xd0, 0x02,
0xd1, 0x00,
0xd2, 0x00,
0xd3, 0x00,
- 0xd4, 0x00,
+ 0xd4, 0x02,
0xd5, 0x00,
0xde, 0x00,
- 0xdf, 0x00,
- 0x61, 0x49,
- 0x62, 0x0b,
- 0x53, 0x08,
- 0x59, 0x08,
+ 0xdf, 0x01,
0xff, 0xff,
};
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index 329a51c1856..83b090ef244 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -390,6 +390,7 @@ static struct cards card_list[] __devinitdata = {
{ 0xfc00270f, BTTV_BOARD_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" },
{ 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" },
{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" },
+ { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" },
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
{ 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV" },
{ 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini" },
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 9f72b7000c0..0393a3d1992 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1161,7 +1161,7 @@ static int dst_get_device_id(struct dst_state *state)
}
}
- if (i >= sizeof (dst_tlist) / sizeof (dst_tlist [0])) {
+ if (i >= ARRAY_SIZE(dst_tlist)) {
dprintk(verbose, DST_ERROR, 1, "Unable to recognize %s or %s", &state->rxbuffer[0], &state->rxbuffer[1]);
dprintk(verbose, DST_ERROR, 1, "please email linux-dvb@linuxtv.org with this type in");
use_dst_type = DST_TYPE_IS_SAT;
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index 3e35931af35..58f69f6ae39 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
+#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/slab.h>
@@ -213,7 +214,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend
freq = 2150000; /* satellite IF is 950..2150MHz */
/* decide which VCO to use for the input frequency */
- for(i=1;(i<sizeof(osci)/sizeof(osci[0]))&&(osci[i]<freq);i++);
+ for(i = 1; (i < ARRAY_SIZE(osci)) && (osci[i] < freq); i++);
printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq);
band=bandsel[i];
/* the gain values must be set by SetSymbolrate */
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index d64b96cb0c4..a6cbbdd262d 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -819,6 +819,11 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
set_bit(rc_keys[i + 2], input_dev->keybit);
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.version = 1;
+ input_dev->cdev.dev = &cinergyt2->udev->dev;
err = input_register_device(input_dev);
if (err) {
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 7c42d53a1cc..a21a894d3f9 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -36,6 +36,7 @@
#include <linux/list.h>
#include <linux/freezer.h>
#include <linux/jiffies.h>
+#include <linux/kthread.h>
#include <asm/processor.h>
#include "dvb_frontend.h"
@@ -100,7 +101,7 @@ struct dvb_frontend_private {
struct semaphore sem;
struct list_head list_head;
wait_queue_head_t wait_queue;
- pid_t thread_pid;
+ struct task_struct *thread;
unsigned long release_jiffies;
unsigned int exit;
unsigned int wakeup;
@@ -508,19 +509,11 @@ static int dvb_frontend_thread(void *data)
struct dvb_frontend *fe = data;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
unsigned long timeout;
- char name [15];
fe_status_t s;
struct dvb_frontend_parameters *params;
dprintk("%s\n", __FUNCTION__);
- snprintf (name, sizeof(name), "kdvb-fe-%i", fe->dvb->num);
-
- lock_kernel();
- daemonize(name);
- sigfillset(&current->blocked);
- unlock_kernel();
-
fepriv->check_wrapped = 0;
fepriv->quality = 0;
fepriv->delay = 3*HZ;
@@ -532,16 +525,18 @@ static int dvb_frontend_thread(void *data)
while (1) {
up(&fepriv->sem); /* is locked when we enter the thread... */
-
+restart:
timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
- dvb_frontend_should_wakeup(fe),
- fepriv->delay);
- if (0 != dvb_frontend_is_exiting(fe)) {
+ dvb_frontend_should_wakeup(fe) || kthread_should_stop(),
+ fepriv->delay);
+
+ if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
/* got signal or quitting */
break;
}
- try_to_freeze();
+ if (try_to_freeze())
+ goto restart;
if (down_interruptible(&fepriv->sem))
break;
@@ -591,7 +586,7 @@ static int dvb_frontend_thread(void *data)
fe->ops.sleep(fe);
}
- fepriv->thread_pid = 0;
+ fepriv->thread = NULL;
mb();
dvb_frontend_wakeup(fe);
@@ -600,7 +595,6 @@ static int dvb_frontend_thread(void *data)
static void dvb_frontend_stop(struct dvb_frontend *fe)
{
- unsigned long ret;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
dprintk ("%s\n", __FUNCTION__);
@@ -608,33 +602,17 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
fepriv->exit = 1;
mb();
- if (!fepriv->thread_pid)
+ if (!fepriv->thread)
return;
- /* check if the thread is really alive */
- if (kill_proc(fepriv->thread_pid, 0, 1) == -ESRCH) {
- printk("dvb_frontend_stop: thread PID %d already died\n",
- fepriv->thread_pid);
- /* make sure the mutex was not held by the thread */
- init_MUTEX (&fepriv->sem);
- return;
- }
-
- /* wake up the frontend thread, so it notices that fe->exit == 1 */
- dvb_frontend_wakeup(fe);
-
- /* wait until the frontend thread has exited */
- ret = wait_event_interruptible(fepriv->wait_queue,0 == fepriv->thread_pid);
- if (-ERESTARTSYS != ret) {
- fepriv->state = FESTATE_IDLE;
- return;
- }
+ kthread_stop(fepriv->thread);
+ init_MUTEX (&fepriv->sem);
fepriv->state = FESTATE_IDLE;
/* paranoia check in case a signal arrived */
- if (fepriv->thread_pid)
- printk("dvb_frontend_stop: warning: thread PID %d won't exit\n",
- fepriv->thread_pid);
+ if (fepriv->thread)
+ printk("dvb_frontend_stop: warning: thread %p won't exit\n",
+ fepriv->thread);
}
s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)
@@ -684,10 +662,11 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
{
int ret;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ struct task_struct *fe_thread;
dprintk ("%s\n", __FUNCTION__);
- if (fepriv->thread_pid) {
+ if (fepriv->thread) {
if (!fepriv->exit)
return 0;
else
@@ -701,18 +680,18 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
fepriv->state = FESTATE_IDLE;
fepriv->exit = 0;
- fepriv->thread_pid = 0;
+ fepriv->thread = NULL;
mb();
- ret = kernel_thread (dvb_frontend_thread, fe, 0);
-
- if (ret < 0) {
- printk("dvb_frontend_start: failed to start kernel_thread (%d)\n", ret);
+ fe_thread = kthread_run(dvb_frontend_thread, fe,
+ "kdvb-fe-%i", fe->dvb->num);
+ if (IS_ERR(fe_thread)) {
+ ret = PTR_ERR(fe_thread);
+ printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);
up(&fepriv->sem);
return ret;
}
- fepriv->thread_pid = ret;
-
+ fepriv->thread = fe_thread;
return 0;
}
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index 826b47f155a..490337b5ee3 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -199,12 +199,14 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
const struct dvb_device *template, void *priv, int type)
{
struct dvb_device *dvbdev;
+ struct file_operations *dvbdevfops;
+
int id;
if (mutex_lock_interruptible(&dvbdev_register_lock))
return -ERESTARTSYS;
- if ((id = dvbdev_get_free_id (adap, type)) < 0) {
+ if ((id = dvbdev_get_free_id (adap, type)) < 0){
mutex_unlock(&dvbdev_register_lock);
*pdvbdev = NULL;
printk ("%s: could get find free device id...\n", __FUNCTION__);
@@ -213,7 +215,15 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
*pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);
- if (!dvbdev) {
+ if (!dvbdev){
+ mutex_unlock(&dvbdev_register_lock);
+ return -ENOMEM;
+ }
+
+ dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
+
+ if (!dvbdevfops){
+ kfree (dvbdev);
mutex_unlock(&dvbdev_register_lock);
return -ENOMEM;
}
@@ -223,7 +233,9 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
dvbdev->id = id;
dvbdev->adapter = adap;
dvbdev->priv = priv;
+ dvbdev->fops = dvbdevfops;
+ memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations));
dvbdev->fops->owner = adap->module;
list_add_tail (&dvbdev->list_head, &adap->device_list);
@@ -251,6 +263,7 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
dvbdev->type, dvbdev->id)));
list_del (&dvbdev->list_head);
+ kfree (dvbdev->fops);
kfree (dvbdev);
}
EXPORT_SYMBOL(dvb_unregister_device);
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index ad52143602c..80f67a51b90 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -109,6 +109,34 @@ config DVB_USB_CXUSB
Medion MD95700 hybrid USB2.0 device.
DViCO FusionHDTV (Bluebird) USB2.0 devices
+config DVB_USB_M920X
+ tristate "Uli m920x DVB-T USB2.0 support"
+ depends on DVB_USB
+ select DVB_MT352 if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
+ Currently, only devices with a product id of
+ "DTV USB MINI" (in cold state) are supported.
+ Firmware required.
+
+config DVB_USB_GL861
+ tristate "Genesys Logic GL861 USB2.0 support"
+ depends on DVB_USB
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
+ receiver with USB ID 0db0:5581.
+
+config DVB_USB_AU6610
+ tristate "Alcor Micro AU6610 USB2.0 support"
+ depends on DVB_USB
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
+
config DVB_USB_DIGITV
tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
depends on DVB_USB
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 154d593bbb0..40f28f559b5 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -30,6 +30,15 @@ obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2
dvb-usb-umt-010-objs = umt-010.o
obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o
+dvb-usb-m920x-objs = m920x.o
+obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o
+
+dvb-usb-gl861-objs = gl861.o
+obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o
+
+dvb-usb-au6610-objs = au6610.o
+obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o
+
dvb-usb-digitv-objs = digitv.o
obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c
new file mode 100644
index 00000000000..0dc66a8d2ba
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/au6610.c
@@ -0,0 +1,255 @@
+/* DVB USB compliant linux driver for Sigmatek DVB-110 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+
+#include "au6610.h"
+
+#include "zl10353.h"
+#include "qt1010.h"
+
+/* debug */
+static int dvb_usb_au6610_debug;
+module_param_named(debug, dvb_usb_au6610_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+ int ret;
+ u16 index;
+ u8 usb_buf[6]; /* enough for all known requests,
+ read returns 5 and write 6 bytes */
+ switch (wlen) {
+ case 1:
+ index = wbuf[0] << 8;
+ break;
+ case 2:
+ index = wbuf[0] << 8;
+ index += wbuf[1];
+ break;
+ default:
+ warn("wlen = %x, aborting.", wlen);
+ return -EINVAL;
+ }
+
+ ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
+ USB_TYPE_VENDOR|USB_DIR_IN, addr, index, usb_buf,
+ sizeof(usb_buf), AU6610_USB_TIMEOUT);
+
+ if (ret < 0)
+ return ret;
+
+ switch (operation) {
+ case AU6610_REQ_I2C_READ:
+ case AU6610_REQ_USB_READ:
+ /* requested value is always 5th byte in buffer */
+ rbuf[0] = usb_buf[4];
+ }
+
+ return ret;
+}
+
+static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+ u8 request;
+ u8 wo = (rbuf == NULL || rlen == 0); /* write-only */
+
+ if (wo) {
+ request = AU6610_REQ_I2C_WRITE;
+ } else { /* rw */
+ request = AU6610_REQ_I2C_READ;
+ }
+
+ return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen);
+}
+
+
+/* I2C */
+static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int i;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ if (num > 2)
+ return -EINVAL;
+
+ for (i = 0; i < num; i++) {
+ /* write/read request */
+ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+ if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
+ msg[i].len, msg[i+1].buf,
+ msg[i+1].len) < 0)
+ break;
+ i++;
+ } else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
+ msg[i].len, NULL, 0) < 0)
+ break;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+ return i;
+}
+
+
+static u32 au6610_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm au6610_i2c_algo = {
+ .master_xfer = au6610_i2c_xfer,
+ .functionality = au6610_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static int au6610_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 au6610_zl10353_config = {
+ .demod_address = 0x1e,
+ .no_tuner = 1,
+ .parallel_ts = 1,
+};
+
+static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ if ((adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
+ &adap->dev->i2c_adap)) != NULL) {
+ return 0;
+ }
+
+ return -EIO;
+}
+
+static struct qt1010_config au6610_qt1010_config = {
+ .i2c_address = 0xc4
+};
+
+static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ return dvb_attach(qt1010_attach,
+ adap->fe, &adap->dev->i2c_adap,
+ &au6610_qt1010_config) == NULL ? -ENODEV : 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties au6610_properties;
+
+static int au6610_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct dvb_usb_device *d;
+ struct usb_host_interface *alt;
+ int ret;
+
+ if (intf->num_altsetting < AU6610_ALTSETTING_COUNT)
+ return -ENODEV;
+
+ if ((ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d)) == 0) {
+ alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);
+
+ if (alt == NULL) {
+ deb_rc("no alt found!\n");
+ return -ENODEV;
+ }
+ ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
+ alt->desc.bAlternateSetting);
+ }
+
+ return ret;
+}
+
+
+static struct usb_device_id au6610_table [] = {
+ { USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, au6610_table);
+
+static struct dvb_usb_device_properties au6610_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .size_of_priv = 0,
+ .identify_state = au6610_identify_state,
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .frontend_attach = au6610_zl10353_frontend_attach,
+ .tuner_attach = au6610_qt1010_tuner_attach,
+
+ .stream = {
+ .type = USB_ISOC,
+ .count = 5,
+ .endpoint = 0x82,
+ .u = {
+ .isoc = {
+ .framesperurb = 40,
+ .framesize = 942, /* maximum packet size */
+ .interval = 1.25, /* 125 us */
+ }
+ }
+ },
+ }
+ },
+ .i2c_algo = &au6610_i2c_algo,
+ .num_device_descs = 1,
+ .devices = {
+ {
+ "Sigmatek DVB-110 DVB-T USB2.0",
+ { &au6610_table[0], NULL },
+ { NULL },
+ },
+ }
+};
+
+static struct usb_driver au6610_driver = {
+ .name = "dvb_usb_au6610",
+ .probe = au6610_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = au6610_table,
+};
+
+/* module stuff */
+static int __init au6610_module_init(void)
+{
+ int ret;
+
+ if ((ret = usb_register(&au6610_driver))) {
+ err("usb_register failed. Error number %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit au6610_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&au6610_driver);
+}
+
+module_init (au6610_module_init);
+module_exit (au6610_module_exit);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Driver Sigmatek DVB-110 DVB-T USB2.0 / AU6610");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/au6610.h b/drivers/media/dvb/dvb-usb/au6610.h
new file mode 100644
index 00000000000..4161b054c71
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/au6610.h
@@ -0,0 +1,19 @@
+#ifndef _DVB_USB_AU6610_H_
+#define _DVB_USB_AU6610_H_
+
+#define DVB_USB_LOG_PREFIX "au6610"
+#include "dvb-usb.h"
+
+#define deb_rc(args...) dprintk(dvb_usb_au6610_debug,0x01,args)
+
+#define AU6610_REQ_I2C_WRITE 0x14
+#define AU6610_REQ_I2C_READ 0x13
+#define AU6610_REQ_USB_WRITE 0x16
+#define AU6610_REQ_USB_READ 0x15
+
+#define AU6610_USB_TIMEOUT 1000
+
+#define AU6610_ALTSETTING_COUNT 6
+#define AU6610_ALTSETTING 5
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 15d12fce34d..127a94b9a1b 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -469,9 +469,9 @@ static int bluebird_patch_dvico_firmware_download(struct usb_device *udev,
fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) {
fw->data[BLUEBIRD_01_ID_OFFSET + 2] =
- udev->descriptor.idProduct + 1;
+ le16_to_cpu(udev->descriptor.idProduct) + 1;
fw->data[BLUEBIRD_01_ID_OFFSET + 3] =
- udev->descriptor.idProduct >> 8;
+ le16_to_cpu(udev->descriptor.idProduct) >> 8;
return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2);
}
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index 4a198d4755b..b5acb11c0bc 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -119,6 +119,8 @@ static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_f
struct dvb_usb_adapter *adap = fe->dvb->priv;
u8 b[5];
dvb_usb_tuner_calc_regs(fe,fep,b, 5);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0);
}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 299382dcb81..148386aba27 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -11,6 +11,7 @@
/* Vendor IDs */
#define USB_VID_ADSTECH 0x06e1
+#define USB_VID_ALCOR_MICRO 0x058f
#define USB_VID_ANCHOR 0x0547
#define USB_VID_AVERMEDIA 0x07ca
#define USB_VID_COMPRO 0x185b
@@ -29,6 +30,7 @@
#define USB_VID_LEADTEK 0x0413
#define USB_VID_LITEON 0x04ca
#define USB_VID_MEDION 0x1660
+#define USB_VID_MSI 0x0db0
#define USB_VID_PINNACLE 0x2304
#define USB_VID_VISIONPLUS 0x13d3
#define USB_VID_TWINHAN 0x1822
@@ -119,6 +121,8 @@
#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54
#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM 0xdb55
#define USB_PID_MEDION_MD95700 0x0932
+#define USB_PID_MSI_MEGASKY580 0x5580
+#define USB_PID_MSI_MEGASKY580_55801 0x5581
#define USB_PID_KYE_DVB_T_COLD 0x701e
#define USB_PID_KYE_DVB_T_WARM 0x701f
#define USB_PID_PCTV_200E 0x020e
@@ -134,6 +138,7 @@
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00
#define USB_PID_GENPIX_8PSK_COLD 0x0200
#define USB_PID_GENPIX_8PSK_WARM 0x0201
+#define USB_PID_SIGMATEK_DVB_110 0x6610
#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 19ff5978bc9..9511a31c8f5 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -151,7 +151,7 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
int dvb_usb_remote_exit(struct dvb_usb_device *d)
{
if (d->state & DVB_USB_STATE_REMOTE) {
- cancel_delayed_work(&d->rc_query_work);
+ cancel_rearming_delayed_work(&d->rc_query_work);
flush_scheduled_work();
input_unregister_device(d->rc_input_dev);
}
diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
new file mode 100644
index 00000000000..c9f38a5e70d
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/gl861.c
@@ -0,0 +1,231 @@
+/* DVB USB compliant linux driver for GL861 USB2.0 devices.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "gl861.h"
+
+#include "zl10353.h"
+#include "qt1010.h"
+
+/* debug */
+int dvb_usb_gl861_debug;
+module_param_named(debug,dvb_usb_gl861_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+ u16 index;
+ u16 value = addr << 8;
+ int wo = (rbuf == NULL || rlen == 0); /* write-only */
+ u8 req, type;
+
+ if (wo) {
+ req = GL861_REQ_I2C_WRITE;
+ type = GL861_WRITE;
+ } else { /* rw */
+ req = GL861_REQ_I2C_READ;
+ type = GL861_READ;
+ }
+
+ switch (wlen) {
+ case 1:
+ index = wbuf[0];
+ break;
+ case 2:
+ index = wbuf[0];
+ value = value + wbuf[1];
+ break;
+ default:
+ warn("wlen = %x, aborting.", wlen);
+ return -EINVAL;
+ }
+
+ return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type,
+ value, index, rbuf, rlen, 2000);
+}
+
+/* I2C */
+static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int i;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ if (num > 2)
+ return -EINVAL;
+
+ for (i = 0; i < num; i++) {
+ /* write/read request */
+ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+ if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
+ msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
+ break;
+ i++;
+ } else
+ if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
+ msg[i].len, NULL, 0) < 0)
+ break;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+ return i;
+}
+
+static u32 gl861_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm gl861_i2c_algo = {
+ .master_xfer = gl861_i2c_xfer,
+ .functionality = gl861_i2c_func,
+};
+
+/* 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 = 0x1e,
+ .no_tuner = 1,
+ .parallel_ts = 1,
+};
+
+static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ if ((adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
+ &adap->dev->i2c_adap)) != NULL) {
+ return 0;
+ }
+
+ return -EIO;
+}
+
+static struct qt1010_config gl861_qt1010_config = {
+ .i2c_address = 0xc4
+};
+
+static int gl861_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ return dvb_attach(qt1010_attach,
+ adap->fe, &adap->dev->i2c_adap,
+ &gl861_qt1010_config) == NULL ? -ENODEV : 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties gl861_properties;
+
+static int gl861_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct dvb_usb_device *d;
+ struct usb_host_interface *alt;
+ int ret;
+
+ if (intf->num_altsetting < 2)
+ return -ENODEV;
+
+ if ((ret = dvb_usb_device_init(intf, &gl861_properties, THIS_MODULE, &d)) == 0) {
+ alt = usb_altnum_to_altsetting(intf, 0);
+
+ if (alt == NULL) {
+ deb_rc("not alt found!\n");
+ return -ENODEV;
+ }
+
+ ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
+ alt->desc.bAlternateSetting);
+ }
+
+ return ret;
+}
+
+static struct usb_device_id gl861_table [] = {
+ { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, gl861_table);
+
+static struct dvb_usb_device_properties gl861_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+ .usb_ctrl = DEVICE_SPECIFIC,
+
+ .size_of_priv = 0,
+
+ .identify_state = gl861_identify_state,
+ .num_adapters = 1,
+ .adapter = {{
+
+ .frontend_attach = gl861_frontend_attach,
+ .tuner_attach = gl861_tuner_attach,
+
+ .stream = {
+ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x81,
+ .u = {
+ .bulk = {
+ .buffersize = 512,
+ }
+ }
+ },
+ }},
+ .i2c_algo = &gl861_i2c_algo,
+
+ .num_device_descs = 1,
+ .devices = {
+ { "MSI Mega Sky 55801 DVB-T USB2.0",
+ { &gl861_table[0], NULL },
+ { NULL },
+ },
+ }
+};
+
+static struct usb_driver gl861_driver = {
+ .name = "dvb_usb_gl861",
+ .probe = gl861_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = gl861_table,
+};
+
+/* module stuff */
+static int __init gl861_module_init(void)
+{
+ int ret;
+
+ if ((ret = usb_register(&gl861_driver))) {
+ err("usb_register failed. Error number %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit gl861_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&gl861_driver);
+}
+
+module_init (gl861_module_init);
+module_exit (gl861_module_exit);
+
+MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>");
+MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/gl861.h b/drivers/media/dvb/dvb-usb/gl861.h
new file mode 100644
index 00000000000..72a51afd5ee
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/gl861.h
@@ -0,0 +1,15 @@
+#ifndef _DVB_USB_GL861_H_
+#define _DVB_USB_GL861_H_
+
+#define DVB_USB_LOG_PREFIX "gl861"
+#include "dvb-usb.h"
+
+#define deb_rc(args...) dprintk(dvb_usb_gl861_debug,0x01,args)
+
+#define GL861_WRITE 0x40
+#define GL861_READ 0xc0
+
+#define GL861_REQ_I2C_WRITE 0x01
+#define GL861_REQ_I2C_READ 0x02
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
new file mode 100644
index 00000000000..d48b24d9abf
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -0,0 +1,541 @@
+/* DVB USB compliant linux driver for MSI Mega Sky 580 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2006 Aapo Tahkola (aet@rasterburn.org)
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+
+#include "m920x.h"
+
+#include "mt352.h"
+#include "mt352_priv.h"
+#include "qt1010.h"
+
+/* debug */
+static int dvb_usb_m920x_debug;
+module_param_named(debug,dvb_usb_m920x_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+static struct dvb_usb_rc_key megasky_rc_keys [] = {
+ { 0x0, 0x12, KEY_POWER },
+ { 0x0, 0x1e, KEY_CYCLEWINDOWS }, /* min/max */
+ { 0x0, 0x02, KEY_CHANNELUP },
+ { 0x0, 0x05, KEY_CHANNELDOWN },
+ { 0x0, 0x03, KEY_VOLUMEUP },
+ { 0x0, 0x06, KEY_VOLUMEDOWN },
+ { 0x0, 0x04, KEY_MUTE },
+ { 0x0, 0x07, KEY_OK }, /* TS */
+ { 0x0, 0x08, KEY_STOP },
+ { 0x0, 0x09, KEY_MENU }, /* swap */
+ { 0x0, 0x0a, KEY_REWIND },
+ { 0x0, 0x1b, KEY_PAUSE },
+ { 0x0, 0x1f, KEY_FASTFORWARD },
+ { 0x0, 0x0c, KEY_RECORD },
+ { 0x0, 0x0d, KEY_CAMERA }, /* screenshot */
+ { 0x0, 0x0e, KEY_COFFEE }, /* "MTS" */
+};
+
+static inline int m9206_read(struct usb_device *udev, u8 request, u16 value,\
+ u16 index, void *data, int size)
+{
+ int ret;
+
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ request, USB_TYPE_VENDOR | USB_DIR_IN,
+ value, index, data, size, 2000);
+ if (ret < 0)
+ return ret;
+
+ if (ret != size)
+ return -EIO;
+
+ return 0;
+}
+
+static inline int m9206_write(struct usb_device *udev, u8 request,
+ u16 value, u16 index)
+{
+ int ret;
+
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ request, USB_TYPE_VENDOR | USB_DIR_OUT,
+ value, index, NULL, 0, 2000);
+ return ret;
+}
+
+static int m9206_rc_init(struct usb_device *udev)
+{
+ int ret = 0;
+
+ /* Remote controller init. */
+ if ((ret = m9206_write(udev, M9206_CORE, 0xa8, M9206_RC_INIT2)) != 0)
+ return ret;
+
+ if ((ret = m9206_write(udev, M9206_CORE, 0x51, M9206_RC_INIT1)) != 0)
+ return ret;
+
+ return ret;
+}
+
+static int m9206_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+ struct m9206_state *m = d->priv;
+ int i, ret = 0;
+ u8 rc_state[2];
+
+
+ if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0)
+ goto unlock;
+
+ if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
+ goto unlock;
+
+ for (i = 0; i < ARRAY_SIZE(megasky_rc_keys); i++)
+ if (megasky_rc_keys[i].data == rc_state[1]) {
+ *event = megasky_rc_keys[i].event;
+
+ switch(rc_state[0]) {
+ case 0x80:
+ *state = REMOTE_NO_KEY_PRESSED;
+ goto unlock;
+
+ case 0x93:
+ case 0x92:
+ m->rep_count = 0;
+ *state = REMOTE_KEY_PRESSED;
+ goto unlock;
+
+ case 0x91:
+ /* For comfort. */
+ if (++m->rep_count > 2)
+ *state = REMOTE_KEY_REPEAT;
+ goto unlock;
+
+ default:
+ deb_rc("Unexpected rc response %x\n", rc_state[0]);
+ *state = REMOTE_NO_KEY_PRESSED;
+ goto unlock;
+ }
+ }
+
+ if (rc_state[1] != 0)
+ deb_rc("Unknown rc key %x\n", rc_state[1]);
+
+ *state = REMOTE_NO_KEY_PRESSED;
+
+ unlock:
+
+ return ret;
+}
+
+/* I2C */
+static int m9206_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct m9206_state *m = d->priv;
+ int i;
+ int ret = 0;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ if (num > 2)
+ return -EINVAL;
+
+ for (i = 0; i < num; i++) {
+ if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].addr, 0x80)) != 0)
+ goto unlock;
+
+ if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[0], 0x0)) != 0)
+ goto unlock;
+
+ if (i + 1 < num && msg[i + 1].flags & I2C_M_RD) {
+ int i2c_i;
+
+ for (i2c_i = 0; i2c_i < M9206_I2C_MAX; i2c_i++)
+ if (msg[i].addr == m->i2c_r[i2c_i].addr)
+ break;
+
+ if (i2c_i >= M9206_I2C_MAX) {
+ deb_rc("No magic for i2c addr!\n");
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ if ((ret = m9206_write(d->udev, M9206_I2C, m->i2c_r[i2c_i].magic, 0x80)) != 0)
+ goto unlock;
+
+ if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x60, msg[i + 1].buf, msg[i + 1].len)) != 0)
+ goto unlock;
+
+ i++;
+ } else {
+ if (msg[i].len != 2)
+ return -EINVAL;
+
+ if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[1], 0x40)) != 0)
+ goto unlock;
+ }
+ }
+ ret = i;
+ unlock:
+ mutex_unlock(&d->i2c_mutex);
+
+ return ret;
+}
+
+static u32 m9206_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm m9206_i2c_algo = {
+ .master_xfer = m9206_i2c_xfer,
+ .functionality = m9206_i2c_func,
+};
+
+
+static int m9206_set_filter(struct dvb_usb_adapter *adap, int type, int idx,
+ int pid)
+{
+ int ret = 0;
+
+ if (pid >= 0x8000)
+ return -EINVAL;
+
+ pid |= 0x8000;
+
+ if ((ret = m9206_write(adap->dev->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
+ return ret;
+
+ if ((ret = m9206_write(adap->dev->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
+ return ret;
+
+ return ret;
+}
+
+static int m9206_update_filters(struct dvb_usb_adapter *adap)
+{
+ struct m9206_state *m = adap->dev->priv;
+ int enabled = m->filtering_enabled;
+ int i, ret = 0, filter = 0;
+
+ for (i = 0; i < M9206_MAX_FILTERS; i++)
+ if (m->filters[i] == 8192)
+ enabled = 0;
+
+ /* Disable all filters */
+ if ((ret = m9206_set_filter(adap, 0x81, 1, enabled)) != 0)
+ return ret;
+
+ for (i = 0; i < M9206_MAX_FILTERS; i++)
+ if ((ret = m9206_set_filter(adap, 0x81, i + 2, 0)) != 0)
+ return ret;
+
+ if ((ret = m9206_set_filter(adap, 0x82, 0, 0x0)) != 0)
+ return ret;
+
+ /* Set */
+ if (enabled) {
+ for (i = 0; i < M9206_MAX_FILTERS; i++) {
+ if (m->filters[i] == 0)
+ continue;
+
+ if ((ret = m9206_set_filter(adap, 0x81, filter + 2, m->filters[i])) != 0)
+ return ret;
+
+ filter++;
+ }
+ }
+
+ if ((ret = m9206_set_filter(adap, 0x82, 0, 0x02f5)) != 0)
+ return ret;
+
+ return ret;
+}
+
+static int m9206_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ struct m9206_state *m = adap->dev->priv;
+
+ m->filtering_enabled = onoff ? 1 : 0;
+
+ return m9206_update_filters(adap);
+}
+
+static int m9206_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+ int onoff)
+{
+ struct m9206_state *m = adap->dev->priv;
+
+ m->filters[index] = onoff ? pid : 0;
+
+ return m9206_update_filters(adap);
+}
+
+static int m9206_firmware_download(struct usb_device *udev,
+ const struct firmware *fw)
+{
+ u16 value, index, size;
+ u8 read[4], *buff;
+ int i, pass, ret = 0;
+
+ buff = kmalloc(65536, GFP_KERNEL);
+
+ if ((ret = m9206_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0)
+ goto done;
+ deb_rc("%x %x %x %x\n", read[0], read[1], read[2], read[3]);
+
+ if ((ret = m9206_read(udev, M9206_FW, 0x0, 0x0, read, 1)) != 0)
+ goto done;
+ deb_rc("%x\n", read[0]);
+
+ for (pass = 0; pass < 2; pass++) {
+ for (i = 0; i + (sizeof(u16) * 3) < fw->size;) {
+ value = le16_to_cpu(*(u16 *)(fw->data + i));
+ i += sizeof(u16);
+
+ index = le16_to_cpu(*(u16 *)(fw->data + i));
+ i += sizeof(u16);
+
+ size = le16_to_cpu(*(u16 *)(fw->data + i));
+ i += sizeof(u16);
+
+ if (pass == 1) {
+ /* Will stall if using fw->data ... */
+ memcpy(buff, fw->data + i, size);
+
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0),
+ M9206_FW,
+ USB_TYPE_VENDOR | USB_DIR_OUT,
+ value, index, buff, size, 20);
+ if (ret != size) {
+ deb_rc("error while uploading fw!\n");
+ ret = -EIO;
+ goto done;
+ }
+ msleep(3);
+ }
+ i += size;
+ }
+ if (i != fw->size) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ msleep(36);
+
+ /* m9206 will disconnect itself from the bus after this. */
+ (void) m9206_write(udev, M9206_CORE, 0x01, M9206_FW_GO);
+ deb_rc("firmware uploaded!\n");
+
+ done:
+ kfree(buff);
+
+ return ret;
+}
+
+/* Callbacks for DVB USB */
+static int megasky_identify_state(struct usb_device *udev,
+ struct dvb_usb_device_properties *props,
+ struct dvb_usb_device_description **desc,
+ int *cold)
+{
+ struct usb_host_interface *alt;
+
+ alt = usb_altnum_to_altsetting(usb_ifnum_to_if(udev, 0), 1);
+ *cold = (alt == NULL) ? 1 : 0;
+
+ return 0;
+}
+
+static int megasky_mt352_demod_init(struct dvb_frontend *fe)
+{
+ u8 config[] = { CONFIG, 0x3d };
+ u8 clock[] = { CLOCK_CTL, 0x30 };
+ u8 reset[] = { RESET, 0x80 };
+ u8 adc_ctl[] = { ADC_CTL_1, 0x40 };
+ u8 agc[] = { AGC_TARGET, 0x1c, 0x20 };
+ u8 sec_agc[] = { 0x69, 0x00, 0xff, 0xff, 0x40, 0xff, 0x00, 0x40, 0x40 };
+ u8 unk1[] = { 0x93, 0x1a };
+ u8 unk2[] = { 0xb5, 0x7a };
+
+ mt352_write(fe, config, ARRAY_SIZE(config));
+ mt352_write(fe, clock, ARRAY_SIZE(clock));
+ mt352_write(fe, reset, ARRAY_SIZE(reset));
+ mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl));
+ mt352_write(fe, agc, ARRAY_SIZE(agc));
+ mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc));
+ mt352_write(fe, unk1, ARRAY_SIZE(unk1));
+ mt352_write(fe, unk2, ARRAY_SIZE(unk2));
+
+ deb_rc("Demod init!\n");
+
+ return 0;
+}
+
+static struct mt352_config megasky_mt352_config = {
+ .demod_address = 0x1e,
+ .no_tuner = 1,
+ .demod_init = megasky_mt352_demod_init,
+};
+
+static int megasky_mt352_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct m9206_state *m = adap->dev->priv;
+
+ deb_rc("megasky_frontend_attach!\n");
+
+ m->i2c_r[M9206_I2C_DEMOD].addr = megasky_mt352_config.demod_address;
+ m->i2c_r[M9206_I2C_DEMOD].magic = 0x1f;
+
+ if ((adap->fe = dvb_attach(mt352_attach, &megasky_mt352_config, &adap->dev->i2c_adap)) == NULL)
+ return -EIO;
+
+ return 0;
+}
+
+static struct qt1010_config megasky_qt1010_config = {
+ .i2c_address = 0xc4
+};
+
+static int megasky_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct m9206_state *m = adap->dev->priv;
+
+ m->i2c_r[M9206_I2C_TUNER].addr = megasky_qt1010_config.i2c_address;
+ m->i2c_r[M9206_I2C_TUNER].magic = 0xc5;
+
+ if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap,
+ &megasky_qt1010_config) == NULL)
+ return -ENODEV;
+
+ return 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties megasky_properties;
+
+static int m920x_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct dvb_usb_device *d;
+ struct usb_host_interface *alt;
+ int ret;
+
+ if ((ret = dvb_usb_device_init(intf, &megasky_properties, THIS_MODULE, &d)) == 0) {
+ deb_rc("probed!\n");
+
+ alt = usb_altnum_to_altsetting(intf, 1);
+ if (alt == NULL) {
+ deb_rc("not alt found!\n");
+ return -ENODEV;
+ }
+
+ ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
+ alt->desc.bAlternateSetting);
+ if (ret < 0)
+ return ret;
+
+ deb_rc("Changed to alternate setting!\n");
+
+ if ((ret = m9206_rc_init(d->udev)) != 0)
+ return ret;
+ }
+ return ret;
+}
+
+static struct usb_device_id m920x_table [] = {
+ { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, m920x_table);
+
+static struct dvb_usb_device_properties megasky_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .firmware = "dvb-usb-megasky-02.fw",
+ .download_firmware = m9206_firmware_download,
+
+ .rc_interval = 100,
+ .rc_key_map = megasky_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(megasky_rc_keys),
+ .rc_query = m9206_rc_query,
+
+ .size_of_priv = sizeof(struct m9206_state),
+
+ .identify_state = megasky_identify_state,
+ .num_adapters = 1,
+ .adapter = {{
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+ .pid_filter_count = 8,
+ .pid_filter = m9206_pid_filter,
+ .pid_filter_ctrl = m9206_pid_filter_ctrl,
+
+ .frontend_attach = megasky_mt352_frontend_attach,
+ .tuner_attach = megasky_qt1010_tuner_attach,
+
+ .stream = {
+ .type = USB_BULK,
+ .count = 8,
+ .endpoint = 0x81,
+ .u = {
+ .bulk = {
+ .buffersize = 512,
+ }
+ }
+ },
+ }},
+ .i2c_algo = &m9206_i2c_algo,
+
+ .num_device_descs = 1,
+ .devices = {
+ { "MSI Mega Sky 580 DVB-T USB2.0",
+ { &m920x_table[0], NULL },
+ { NULL },
+ },
+ }
+};
+
+static struct usb_driver m920x_driver = {
+ .name = "dvb_usb_m920x",
+ .probe = m920x_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = m920x_table,
+};
+
+/* module stuff */
+static int __init m920x_module_init(void)
+{
+ int ret;
+
+ if ((ret = usb_register(&m920x_driver))) {
+ err("usb_register failed. Error number %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit m920x_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&m920x_driver);
+}
+
+module_init (m920x_module_init);
+module_exit (m920x_module_exit);
+
+MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
+MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / Uli m920x");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/m920x.h b/drivers/media/dvb/dvb-usb/m920x.h
new file mode 100644
index 00000000000..c354196ffe5
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/m920x.h
@@ -0,0 +1,35 @@
+#ifndef _DVB_USB_M920X_H_
+#define _DVB_USB_M920X_H_
+
+#define DVB_USB_LOG_PREFIX "m920x"
+#include "dvb-usb.h"
+
+#define deb_rc(args...) dprintk(dvb_usb_m920x_debug,0x01,args)
+
+#define M9206_CORE 0x22
+#define M9206_RC_STATE 0xff51
+#define M9206_RC_KEY 0xff52
+#define M9206_RC_INIT1 0xff54
+#define M9206_RC_INIT2 0xff55
+#define M9206_FW_GO 0xff69
+
+#define M9206_I2C 0x23
+#define M9206_FILTER 0x25
+#define M9206_FW 0x30
+
+#define M9206_MAX_FILTERS 8
+
+#define M9206_I2C_TUNER 0
+#define M9206_I2C_DEMOD 1
+#define M9206_I2C_MAX 2
+
+struct m9206_state {
+ u16 filters[M9206_MAX_FILTERS];
+ int filtering_enabled;
+ int rep_count;
+ struct {
+ unsigned char addr;
+ unsigned char magic;
+ }i2c_r[M9206_I2C_MAX];
+};
+#endif
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index af314bb1dca..22c2cf2cea9 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -290,6 +290,13 @@ config DVB_TDA826X
help
A DVB-S silicon tuner module. Say Y when you want to support this tuner.
+config DVB_TUNER_QT1010
+ tristate "Quantek QT1010 silicon tuner"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon tuner QT1010 from Quantek.
+
config DVB_TUNER_MT2060
tristate "Microtune MT2060 silicon IF tuner"
depends on I2C
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 3fa6e5d32a9..a646d9969b7 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -38,5 +38,6 @@ obj-$(CONFIG_DVB_ISL6421) += isl6421.o
obj-$(CONFIG_DVB_TDA10086) += tda10086.o
obj-$(CONFIG_DVB_TDA826X) += tda826x.o
obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
+obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
obj-$(CONFIG_DVB_TUA6100) += tua6100.o
obj-$(CONFIG_DVB_TUNER_LGH06XF) += lgh06xf.o
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index ae96395217a..10fc0c8316d 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -254,7 +254,7 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
if (srate<500000)
srate=500000;
- for(i=0;(i<sizeof(bands)/sizeof(bands[0]))&&(srate>bands[i]);i++)
+ for(i = 0; (i < ARRAY_SIZE(bands)) && (srate>bands[i]); i++)
;
/* first, check which sample rate is appropriate: 45, 60 80 or 90 MHz,
and set the PLL accordingly (R07[1:0] Fclk, R06[7:4] PLLmult,
@@ -361,7 +361,7 @@ static int cx24110_initfe(struct dvb_frontend* fe)
dprintk("%s: init chip\n", __FUNCTION__);
- for(i=0;i<sizeof(cx24110_regdata)/sizeof(cx24110_regdata[0]);i++) {
+ for(i = 0; i < ARRAY_SIZE(cx24110_regdata); i++) {
cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
};
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index a356d28fc3b..732e94aaa36 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -507,7 +507,7 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa
int i = 0;
int pump = 2;
int band = 0;
- int num_bands = sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]);
+ int num_bands = ARRAY_SIZE(cx24123_bandselect_vals);
/* Defaults for low freq, low rate */
state->VCAarg = cx24123_AGC_vals[0].VCAprogdata;
@@ -516,7 +516,7 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa
vco_div = cx24123_bandselect_vals[0].VCOdivider;
/* For the given symbol rate, determine the VCA, VGA and FILTUNE programming bits */
- for (i = 0; i < sizeof(cx24123_AGC_vals) / sizeof(cx24123_AGC_vals[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++)
{
if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) &&
(cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) {
@@ -658,7 +658,7 @@ static int cx24123_initfe(struct dvb_frontend* fe)
dprintk("%s: init frontend\n",__FUNCTION__);
/* Configure the demod to a good set of defaults */
- for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(cx24123_regdata); i++)
cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
/* Set the LNB polarity */
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index 23aa75a27c1..054d7e6d966 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -475,7 +475,7 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx
tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha;
dib3000mc_write_word(state, 0, tmp);
- dib3000mc_write_word(state, 5, seq);
+ dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4));
tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp);
if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp))
diff --git a/drivers/media/dvb/frontends/qt1010.c b/drivers/media/dvb/frontends/qt1010.c
new file mode 100644
index 00000000000..825aa1412e6
--- /dev/null
+++ b/drivers/media/dvb/frontends/qt1010.c
@@ -0,0 +1,485 @@
+/*
+ * Driver for Quantek QT1010 silicon tuner
+ *
+ * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ * Aapo Tahkola <aet@rasterburn.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include "qt1010.h"
+#include "qt1010_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "QT1010: " args); \
+ } while (0)
+
+/* read single register */
+static int qt1010_readreg(struct qt1010_priv *priv, u8 reg, u8 *val)
+{
+ struct i2c_msg msg[2] = {
+ { .addr = priv->cfg->i2c_address,
+ .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = priv->cfg->i2c_address,
+ .flags = I2C_M_RD, .buf = val, .len = 1 },
+ };
+
+ if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+ printk(KERN_WARNING "qt1010 I2C read failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+/* write single register */
+static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val)
+{
+ u8 buf[2] = { reg, val };
+ struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+ .flags = 0, .buf = buf, .len = 2 };
+
+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "qt1010 I2C write failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+/* dump all registers */
+static void qt1010_dump_regs(struct qt1010_priv *priv)
+{
+ char buf[52], buf2[4];
+ u8 reg, val;
+
+ for (reg = 0; ; reg++) {
+ if (reg % 16 == 0) {
+ if (reg)
+ printk("%s\n", buf);
+ sprintf(buf, "%02x: ", reg);
+ }
+ if (qt1010_readreg(priv, reg, &val) == 0)
+ sprintf(buf2, "%02x ", val);
+ else
+ strcpy(buf2, "-- ");
+ strcat(buf, buf2);
+ if (reg == 0x2f)
+ break;
+ }
+ printk("%s\n", buf);
+}
+
+static int qt1010_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct qt1010_priv *priv;
+ int err;
+ u32 freq, div, mod1, mod2;
+ u8 i, tmpval, reg05;
+ qt1010_i2c_oper_t rd[48] = {
+ { QT1010_WR, 0x01, 0x80 },
+ { QT1010_WR, 0x02, 0x3f },
+ { QT1010_WR, 0x05, 0xff }, /* 02 c write */
+ { QT1010_WR, 0x06, 0x44 },
+ { QT1010_WR, 0x07, 0xff }, /* 04 c write */
+ { QT1010_WR, 0x08, 0x08 },
+ { QT1010_WR, 0x09, 0xff }, /* 06 c write */
+ { QT1010_WR, 0x0a, 0xff }, /* 07 c write */
+ { QT1010_WR, 0x0b, 0xff }, /* 08 c write */
+ { QT1010_WR, 0x0c, 0xe1 },
+ { QT1010_WR, 0x1a, 0xff }, /* 10 c write */
+ { QT1010_WR, 0x1b, 0x00 },
+ { QT1010_WR, 0x1c, 0x89 },
+ { QT1010_WR, 0x11, 0xff }, /* 13 c write */
+ { QT1010_WR, 0x12, 0xff }, /* 14 c write */
+ { QT1010_WR, 0x22, 0xff }, /* 15 c write */
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x1e, 0xd0 },
+ { QT1010_RD, 0x22, 0xff }, /* 16 c read */
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_RD, 0x05, 0xff }, /* 20 c read */
+ { QT1010_RD, 0x22, 0xff }, /* 21 c read */
+ { QT1010_WR, 0x23, 0xd0 },
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x1e, 0xe0 },
+ { QT1010_RD, 0x23, 0xff }, /* 25 c read */
+ { QT1010_RD, 0x23, 0xff }, /* 26 c read */
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x24, 0xd0 },
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x1e, 0xf0 },
+ { QT1010_RD, 0x24, 0xff }, /* 31 c read */
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x14, 0x7f },
+ { QT1010_WR, 0x15, 0x7f },
+ { QT1010_WR, 0x05, 0xff }, /* 35 c write */
+ { QT1010_WR, 0x06, 0x00 },
+ { QT1010_WR, 0x15, 0x1f },
+ { QT1010_WR, 0x16, 0xff },
+ { QT1010_WR, 0x18, 0xff },
+ { QT1010_WR, 0x1f, 0xff }, /* 40 c write */
+ { QT1010_WR, 0x20, 0xff }, /* 41 c write */
+ { QT1010_WR, 0x21, 0x53 },
+ { QT1010_WR, 0x25, 0xff }, /* 43 c write */
+ { QT1010_WR, 0x26, 0x15 },
+ { QT1010_WR, 0x00, 0xff }, /* 45 c write */
+ { QT1010_WR, 0x02, 0x00 },
+ { QT1010_WR, 0x01, 0x00 }
+ };
+
+#define FREQ1 32000000 /* 32 MHz */
+#define FREQ2 4000000 /* 4 MHz Quartz oscillator in the stick? */
+
+ priv = fe->tuner_priv;
+ freq = params->frequency;
+ div = (freq + QT1010_OFFSET) / QT1010_STEP;
+ freq = (div * QT1010_STEP) - QT1010_OFFSET;
+ mod1 = (freq + QT1010_OFFSET) % FREQ1;
+ mod2 = (freq + QT1010_OFFSET) % FREQ2;
+ priv->bandwidth =
+ (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+ priv->frequency = freq;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+ /* reg 05 base value */
+ if (freq < 290000000) reg05 = 0x14; /* 290 MHz */
+ else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */
+ else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */
+ else reg05 = 0x74;
+
+ /* 0x5 */
+ rd[2].val = reg05;
+
+ /* 07 - set frequency: 32 MHz scale */
+ rd[4].val = (freq + QT1010_OFFSET) / FREQ1;
+
+ /* 09 - changes every 8/24 MHz */
+ if (mod1 < 8000000) rd[6].val = 0x1d;
+ else rd[6].val = 0x1c;
+
+ /* 0a - set frequency: 4 MHz scale (max 28 MHz) */
+ if (mod1 < 1*FREQ2) rd[7].val = 0x09; /* +0 MHz */
+ else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /* +4 MHz */
+ else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /* +8 MHz */
+ else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */
+ else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */
+ else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */
+ else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */
+ else rd[7].val = 0x0a; /* +28 MHz */
+
+ /* 0b - changes every 2/2 MHz */
+ if (mod2 < 2000000) rd[8].val = 0x45;
+ else rd[8].val = 0x44;
+
+ /* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/
+ tmpval = 0x78; /* byte, overflows intentionally */
+ rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08);
+
+ /* 11 */
+ rd[13].val = 0xfd; /* TODO: correct value calculation */
+
+ /* 12 */
+ rd[14].val = 0x91; /* TODO: correct value calculation */
+
+ /* 22 */
+ if (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */
+ else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */
+ else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */
+ else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */
+ else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */
+ else rd[15].val = 0xd0;
+
+ /* 05 */
+ rd[35].val = (reg05 & 0xf0);
+
+ /* 1f */
+ if (mod1 < 8000000) tmpval = 0x00;
+ else if (mod1 < 12000000) tmpval = 0x01;
+ else if (mod1 < 16000000) tmpval = 0x02;
+ else if (mod1 < 24000000) tmpval = 0x03;
+ else if (mod1 < 28000000) tmpval = 0x04;
+ else tmpval = 0x05;
+ rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval);
+
+ /* 20 */
+ if (mod1 < 8000000) tmpval = 0x00;
+ else if (mod1 < 12000000) tmpval = 0x01;
+ else if (mod1 < 20000000) tmpval = 0x02;
+ else if (mod1 < 24000000) tmpval = 0x03;
+ else if (mod1 < 28000000) tmpval = 0x04;
+ else tmpval = 0x05;
+ rd[41].val = (priv->reg20_init_val + 0x0d + tmpval);
+
+ /* 25 */
+ rd[43].val = priv->reg25_init_val;
+
+ /* 00 */
+ rd[45].val = 0x92; /* TODO: correct value calculation */
+
+ dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \
+ "1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \
+ "20:%02x 25:%02x 00:%02x", \
+ freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \
+ rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \
+ rd[40].val, rd[41].val, rd[43].val, rd[45].val);
+
+ for (i = 0; i < ARRAY_SIZE(rd); i++) {
+ if (rd[i].oper == QT1010_WR) {
+ err = qt1010_writereg(priv, rd[i].reg, rd[i].val);
+ } else { /* read is required to proper locking */
+ err = qt1010_readreg(priv, rd[i].reg, &tmpval);
+ }
+ if (err) return err;
+ }
+
+ if (debug)
+ qt1010_dump_regs(priv);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+ return 0;
+}
+
+static int qt1010_init_meas1(struct qt1010_priv *priv,
+ u8 oper, u8 reg, u8 reg_init_val, u8 *retval)
+{
+ u8 i, val1, val2;
+ int err;
+
+ qt1010_i2c_oper_t i2c_data[] = {
+ { QT1010_WR, reg, reg_init_val },
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x1e, oper },
+ { QT1010_RD, reg, 0xff }
+ };
+
+ for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
+ if (i2c_data[i].oper == QT1010_WR) {
+ err = qt1010_writereg(priv, i2c_data[i].reg,
+ i2c_data[i].val);
+ } else {
+ err = qt1010_readreg(priv, i2c_data[i].reg, &val2);
+ }
+ if (err) return err;
+ }
+
+ do {
+ val1 = val2;
+ err = qt1010_readreg(priv, reg, &val2);
+ if (err) return err;
+ dprintk("compare reg:%02x %02x %02x", reg, val1, val2);
+ } while (val1 != val2);
+ *retval = val1;
+
+ return qt1010_writereg(priv, 0x1e, 0x00);
+}
+
+static u8 qt1010_init_meas2(struct qt1010_priv *priv,
+ u8 reg_init_val, u8 *retval)
+{
+ u8 i, val;
+ int err;
+ qt1010_i2c_oper_t i2c_data[] = {
+ { QT1010_WR, 0x07, reg_init_val },
+ { QT1010_WR, 0x22, 0xd0 },
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x1e, 0xd0 },
+ { QT1010_RD, 0x22, 0xff },
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x22, 0xff }
+ };
+ for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
+ if (i2c_data[i].oper == QT1010_WR) {
+ err = qt1010_writereg(priv, i2c_data[i].reg,
+ i2c_data[i].val);
+ } else {
+ err = qt1010_readreg(priv, i2c_data[i].reg, &val);
+ }
+ if (err) return err;
+ }
+ *retval = val;
+ return 0;
+}
+
+static int qt1010_init(struct dvb_frontend *fe)
+{
+ struct qt1010_priv *priv = fe->tuner_priv;
+ struct dvb_frontend_parameters params;
+ int err = 0;
+ u8 i, tmpval, *valptr = NULL;
+
+ qt1010_i2c_oper_t i2c_data[] = {
+ { QT1010_WR, 0x01, 0x80 },
+ { QT1010_WR, 0x0d, 0x84 },
+ { QT1010_WR, 0x0e, 0xb7 },
+ { QT1010_WR, 0x2a, 0x23 },
+ { QT1010_WR, 0x2c, 0xdc },
+ { QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */
+ { QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */
+ { QT1010_WR, 0x2b, 0x70 },
+ { QT1010_WR, 0x2a, 0x23 },
+ { QT1010_M1, 0x26, 0x08 },
+ { QT1010_M1, 0x82, 0xff },
+ { QT1010_WR, 0x05, 0x14 },
+ { QT1010_WR, 0x06, 0x44 },
+ { QT1010_WR, 0x07, 0x28 },
+ { QT1010_WR, 0x08, 0x0b },
+ { QT1010_WR, 0x11, 0xfd },
+ { QT1010_M1, 0x22, 0x0d },
+ { QT1010_M1, 0xd0, 0xff },
+ { QT1010_WR, 0x06, 0x40 },
+ { QT1010_WR, 0x16, 0xf0 },
+ { QT1010_WR, 0x02, 0x38 },
+ { QT1010_WR, 0x03, 0x18 },
+ { QT1010_WR, 0x20, 0xe0 },
+ { QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */
+ { QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */
+ { QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */
+ { QT1010_WR, 0x03, 0x19 },
+ { QT1010_WR, 0x02, 0x3f },
+ { QT1010_WR, 0x21, 0x53 },
+ { QT1010_RD, 0x21, 0xff },
+ { QT1010_WR, 0x11, 0xfd },
+ { QT1010_WR, 0x05, 0x34 },
+ { QT1010_WR, 0x06, 0x44 },
+ { QT1010_WR, 0x08, 0x08 }
+ };
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+ for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
+ switch (i2c_data[i].oper) {
+ case QT1010_WR:
+ err = qt1010_writereg(priv, i2c_data[i].reg,
+ i2c_data[i].val);
+ break;
+ case QT1010_RD:
+ if (i2c_data[i].val == 0x20)
+ valptr = &priv->reg20_init_val;
+ else
+ valptr = &tmpval;
+ err = qt1010_readreg(priv, i2c_data[i].reg, valptr);
+ break;
+ case QT1010_M1:
+ if (i2c_data[i].val == 0x25)
+ valptr = &priv->reg25_init_val;
+ else if (i2c_data[i].val == 0x1f)
+ valptr = &priv->reg1f_init_val;
+ else
+ valptr = &tmpval;
+ err = qt1010_init_meas1(priv, i2c_data[i+1].reg,
+ i2c_data[i].reg,
+ i2c_data[i].val, valptr);
+ i++;
+ break;
+ }
+ if (err) return err;
+ }
+
+ for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */
+ if ((err = qt1010_init_meas2(priv, i, &tmpval)))
+ return err;
+
+ params.frequency = 545000000; /* Sigmatek DVB-110 545000000 */
+ /* MSI Megasky 580 GL861 533000000 */
+ return qt1010_set_params(fe, &params);
+}
+
+static int qt1010_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct qt1010_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static int qt1010_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct qt1010_priv *priv = fe->tuner_priv;
+ *bandwidth = priv->bandwidth;
+ return 0;
+}
+
+static const struct dvb_tuner_ops qt1010_tuner_ops = {
+ .info = {
+ .name = "Quantek QT1010",
+ .frequency_min = QT1010_MIN_FREQ,
+ .frequency_max = QT1010_MAX_FREQ,
+ .frequency_step = QT1010_STEP,
+ },
+
+ .release = qt1010_release,
+ .init = qt1010_init,
+ /* TODO: implement sleep */
+
+ .set_params = qt1010_set_params,
+ .get_frequency = qt1010_get_frequency,
+ .get_bandwidth = qt1010_get_bandwidth
+};
+
+struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct qt1010_config *cfg)
+{
+ struct qt1010_priv *priv = NULL;
+ u8 id;
+
+ priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->cfg = cfg;
+ priv->i2c = i2c;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+
+ /* Try to detect tuner chip. Probably this is not correct register. */
+ if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) {
+ kfree(priv);
+ return NULL;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+ printk(KERN_INFO "Quantek QT1010 successfully identified.\n");
+ memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ fe->tuner_priv = priv;
+ return fe;
+}
+EXPORT_SYMBOL(qt1010_attach);
+
+MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/qt1010.h b/drivers/media/dvb/frontends/qt1010.h
new file mode 100644
index 00000000000..3ab4aa045c3
--- /dev/null
+++ b/drivers/media/dvb/frontends/qt1010.h
@@ -0,0 +1,53 @@
+/*
+ * Driver for Quantek QT1010 silicon tuner
+ *
+ * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ * Aapo Tahkola <aet@rasterburn.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef QT1010_H
+#define QT1010_H
+
+#include "dvb_frontend.h"
+
+struct qt1010_config {
+ u8 i2c_address;
+};
+
+/**
+ * Attach a qt1010 tuner to the supplied frontend structure.
+ *
+ * @param fe frontend to attach to
+ * @param i2c i2c adapter to use
+ * @param cfg tuner hw based configuration
+ * @return fe pointer on success, NULL on failure
+ */
+#if defined(CONFIG_DVB_TUNER_QT1010) || (defined(CONFIG_DVB_TUNER_QT1010_MODULE) && defined(MODULE))
+extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct qt1010_config *cfg);
+#else
+static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct qt1010_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_TUNER_QT1010
+
+#endif
diff --git a/drivers/media/dvb/frontends/qt1010_priv.h b/drivers/media/dvb/frontends/qt1010_priv.h
new file mode 100644
index 00000000000..090cf475f09
--- /dev/null
+++ b/drivers/media/dvb/frontends/qt1010_priv.h
@@ -0,0 +1,105 @@
+/*
+ * Driver for Quantek QT1010 silicon tuner
+ *
+ * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ * Aapo Tahkola <aet@rasterburn.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef QT1010_PRIV_H
+#define QT1010_PRIV_H
+
+/*
+reg def meaning
+=== === =======
+00 00 ?
+01 a0 ? operation start/stop; start=80, stop=00
+02 00 ?
+03 19 ?
+04 00 ?
+05 00 ? maybe band selection
+06 00 ?
+07 2b set frequency: 32 MHz scale, n*32 MHz
+08 0b ?
+09 10 ? changes every 8/24 MHz; values 1d/1c
+0a 08 set frequency: 4 MHz scale, n*4 MHz
+0b 41 ? changes every 2/2 MHz; values 45/45
+0c e1 ?
+0d 94 ?
+0e b6 ?
+0f 2c ?
+10 10 ?
+11 f1 ? maybe device specified adjustment
+12 11 ? maybe device specified adjustment
+13 3f ?
+14 1f ?
+15 3f ?
+16 ff ?
+17 ff ?
+18 f7 ?
+19 80 ?
+1a d0 set frequency: 125 kHz scale, n*125 kHz
+1b 00 ?
+1c 89 ?
+1d 00 ?
+1e 00 ? looks like operation register; write cmd here, read result from 1f-26
+1f 20 ? chip initialization
+20 e0 ? chip initialization
+21 20 ?
+22 d0 ?
+23 d0 ?
+24 d0 ?
+25 40 ? chip initialization
+26 08 ?
+27 29 ?
+28 55 ?
+29 39 ?
+2a 13 ?
+2b 01 ?
+2c ea ?
+2d 00 ?
+2e 00 ? not used?
+2f 00 ? not used?
+*/
+
+#define QT1010_STEP 125000 /* 125 kHz used by Windows drivers,
+ hw could be more precise but we don't
+ know how to use */
+#define QT1010_MIN_FREQ 48000000 /* 48 MHz */
+#define QT1010_MAX_FREQ 860000000 /* 860 MHz */
+#define QT1010_OFFSET 1246000000 /* 1246 MHz */
+
+#define QT1010_WR 0
+#define QT1010_RD 1
+#define QT1010_M1 3
+
+typedef struct {
+ u8 oper, reg, val;
+} qt1010_i2c_oper_t;
+
+struct qt1010_priv {
+ struct qt1010_config *cfg;
+ struct i2c_adapter *i2c;
+
+ u8 reg1f_init_val;
+ u8 reg20_init_val;
+ u8 reg25_init_val;
+
+ u32 frequency;
+ u32 bandwidth;
+};
+
+#endif
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
index 1ca64249010..9a343972ff5 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -35,6 +35,7 @@ struct stv0297_state {
const struct stv0297_config *config;
struct dvb_frontend frontend;
+ unsigned long last_ber;
unsigned long base_freq;
};
@@ -310,6 +311,8 @@ static int stv0297_init(struct dvb_frontend *fe)
stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]);
msleep(200);
+ state->last_ber = 0;
+
return 0;
}
@@ -340,11 +343,13 @@ static int stv0297_read_ber(struct dvb_frontend *fe, u32 * ber)
struct stv0297_state *state = fe->demodulator_priv;
u8 BER[3];
- stv0297_writereg(state, 0xA0, 0x80); // Start Counting bit errors for 4096 Bytes
- mdelay(25); // Hopefully got 4096 Bytes
stv0297_readregs(state, 0xA0, BER, 3);
- mdelay(25);
- *ber = (BER[2] << 8 | BER[1]) / (8 * 4096);
+ if (!(BER[0] & 0x80)) {
+ state->last_ber = BER[2] << 8 | BER[1];
+ stv0297_writereg_mask(state, 0xA0, 0x80, 0x80);
+ }
+
+ *ber = state->last_ber;
return 0;
}
@@ -376,9 +381,14 @@ static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
{
struct stv0297_state *state = fe->demodulator_priv;
+ stv0297_writereg_mask(state, 0xDF, 0x03, 0x03); /* freeze the counters */
+
*ucblocks = (stv0297_readreg(state, 0xD5) << 8)
| stv0297_readreg(state, 0xD4);
+ stv0297_writereg_mask(state, 0xDF, 0x03, 0x02); /* clear the counters */
+ stv0297_writereg_mask(state, 0xDF, 0x03, 0x01); /* re-enable the counters */
+
return 0;
}
@@ -648,6 +658,7 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config,
/* setup the state */
state->config = config;
state->i2c = i2c;
+ state->last_ber = 0;
state->base_freq = 0;
/* check if the demod is there */
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 93483769eca..18768d2f6d4 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -92,7 +92,7 @@ static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
-int stv0299_write(struct dvb_frontend* fe, u8 *buf, int len)
+static int stv0299_write(struct dvb_frontend* fe, u8 *buf, int len)
{
struct stv0299_state* state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index dca89171be1..5b9c5bb29b2 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -201,7 +201,7 @@ static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate
return 0;
}
-int tda10021_write(struct dvb_frontend* fe, u8 *buf, int len)
+static int tda10021_write(struct dvb_frontend* fe, u8 *buf, int len)
{
struct tda10021_state* state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index 00e4bcd9f1a..f4a9cf9d26d 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -579,7 +579,7 @@ static int tda1004x_decode_fec(int tdafec)
return -1;
}
-int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len)
+static int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len)
{
struct tda1004x_state* state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index 0e9b59af271..245f9b7dddf 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -38,6 +38,12 @@ struct zl10353_state {
struct zl10353_config config;
};
+static int debug;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "zl10353: " args); \
+ } while (0)
+
static int debug_regs = 0;
static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
@@ -54,7 +60,7 @@ static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
return 0;
}
-int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen)
+static int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen)
{
int err, i;
for (i = 0; i < ilen - 1; i++)
@@ -113,6 +119,36 @@ static void zl10353_dump_regs(struct dvb_frontend *fe)
printk(KERN_DEBUG "%s\n", buf);
}
+static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
+ enum fe_bandwidth bandwidth,
+ u16 *nominal_rate)
+{
+ u32 adc_clock = 22528; /* 20.480 MHz on the board(!?) */
+ u8 bw;
+ struct zl10353_state *state = fe->demodulator_priv;
+
+ if (state->config.adc_clock)
+ adc_clock = state->config.adc_clock;
+
+ switch (bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ bw = 6;
+ break;
+ case BANDWIDTH_7_MHZ:
+ bw = 7;
+ break;
+ case BANDWIDTH_8_MHZ:
+ default:
+ bw = 8;
+ break;
+ }
+
+ *nominal_rate = (64 * bw * (1<<16) / (7 * 8) * 4000 / adc_clock + 2) / 4;
+
+ dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
+ __FUNCTION__, bw, adc_clock, *nominal_rate);
+}
+
static int zl10353_sleep(struct dvb_frontend *fe)
{
static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 };
@@ -125,7 +161,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
struct dvb_frontend_parameters *param)
{
struct zl10353_state *state = fe->demodulator_priv;
-
+ u16 nominal_rate;
u8 pllbuf[6] = { 0x67 };
/* These settings set "auto-everything" and start the FSM. */
@@ -138,18 +174,23 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
zl10353_single_write(fe, 0x56, 0x28);
zl10353_single_write(fe, 0x89, 0x20);
zl10353_single_write(fe, 0x5E, 0x00);
- zl10353_single_write(fe, 0x65, 0x5A);
- zl10353_single_write(fe, 0x66, 0xE9);
+
+ zl10353_calc_nominal_rate(fe, param->u.ofdm.bandwidth, &nominal_rate);
+ zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate));
+ zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate));
+
zl10353_single_write(fe, 0x6C, 0xCD);
zl10353_single_write(fe, 0x6D, 0x7E);
- zl10353_single_write(fe, 0x62, 0x0A);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
// if there is no attached secondary tuner, we call set_params to program
// a potential tuner attached somewhere else
if (state->config.no_tuner) {
if (fe->ops.tuner_ops.set_params) {
fe->ops.tuner_ops.set_params(fe, param);
- if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
}
}
@@ -213,6 +254,29 @@ static int zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status)
return 0;
}
+static int zl10353_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct zl10353_state *state = fe->demodulator_priv;
+
+ *ber = zl10353_read_register(state, RS_ERR_CNT_2) << 16 |
+ zl10353_read_register(state, RS_ERR_CNT_1) << 8 |
+ zl10353_read_register(state, RS_ERR_CNT_0);
+
+ return 0;
+}
+
+static int zl10353_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct zl10353_state *state = fe->demodulator_priv;
+
+ u16 signal = zl10353_read_register(state, AGC_GAIN_1) << 10 |
+ zl10353_read_register(state, AGC_GAIN_0) << 2 | 3;
+
+ *strength = ~signal;
+
+ return 0;
+}
+
static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct zl10353_state *state = fe->demodulator_priv;
@@ -227,6 +291,16 @@ static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr)
return 0;
}
+static int zl10353_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ struct zl10353_state *state = fe->demodulator_priv;
+
+ *ucblocks = zl10353_read_register(state, RS_UBC_1) << 8 |
+ zl10353_read_register(state, RS_UBC_0);
+
+ return 0;
+}
+
static int zl10353_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings
*fe_tune_settings)
@@ -261,6 +335,16 @@ static int zl10353_init(struct dvb_frontend *fe)
return 0;
}
+static int zl10353_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ u8 val = 0x0a;
+
+ if (enable)
+ val |= 0x10;
+
+ return zl10353_single_write(fe, 0x62, val);
+}
+
static void zl10353_release(struct dvb_frontend *fe)
{
struct zl10353_state *state = fe->demodulator_priv;
@@ -319,15 +403,22 @@ static struct dvb_frontend_ops zl10353_ops = {
.init = zl10353_init,
.sleep = zl10353_sleep,
+ .i2c_gate_ctrl = zl10353_i2c_gate_ctrl,
.write = zl10353_write,
.set_frontend = zl10353_set_parameters,
.get_tune_settings = zl10353_get_tune_settings,
.read_status = zl10353_read_status,
+ .read_ber = zl10353_read_ber,
+ .read_signal_strength = zl10353_read_signal_strength,
.read_snr = zl10353_read_snr,
+ .read_ucblocks = zl10353_read_ucblocks,
};
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
module_param(debug_regs, int, 0644);
MODULE_PARM_DESC(debug_regs, "Turn on/off frontend register dumps (default:off).");
diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
index 0bc0109737f..cb274dc12b8 100644
--- a/drivers/media/dvb/frontends/zl10353.h
+++ b/drivers/media/dvb/frontends/zl10353.h
@@ -29,6 +29,9 @@ struct zl10353_config
/* demodulator's I2C address */
u8 demod_address;
+ /* frequencies in kHz */
+ int adc_clock; // default: 22528
+
/* set if no pll is connected to the secondary i2c bus */
int no_tuner;
diff --git a/drivers/media/dvb/frontends/zl10353_priv.h b/drivers/media/dvb/frontends/zl10353_priv.h
index b72224bd7dd..4962434b35e 100644
--- a/drivers/media/dvb/frontends/zl10353_priv.h
+++ b/drivers/media/dvb/frontends/zl10353_priv.h
@@ -24,19 +24,31 @@
#define ID_ZL10353 0x14
+#define msb(x) (((x) >> 8) & 0xff)
+#define lsb(x) ((x) & 0xff)
+
enum zl10353_reg_addr {
- INTERRUPT_0 = 0x00,
- INTERRUPT_1 = 0x01,
- INTERRUPT_2 = 0x02,
- INTERRUPT_3 = 0x03,
- INTERRUPT_4 = 0x04,
- INTERRUPT_5 = 0x05,
- STATUS_6 = 0x06,
- STATUS_7 = 0x07,
- STATUS_8 = 0x08,
- STATUS_9 = 0x09,
- SNR = 0x10,
- CHIP_ID = 0x7F,
+ INTERRUPT_0 = 0x00,
+ INTERRUPT_1 = 0x01,
+ INTERRUPT_2 = 0x02,
+ INTERRUPT_3 = 0x03,
+ INTERRUPT_4 = 0x04,
+ INTERRUPT_5 = 0x05,
+ STATUS_6 = 0x06,
+ STATUS_7 = 0x07,
+ STATUS_8 = 0x08,
+ STATUS_9 = 0x09,
+ AGC_GAIN_1 = 0x0A,
+ AGC_GAIN_0 = 0x0B,
+ SNR = 0x10,
+ RS_ERR_CNT_2 = 0x11,
+ RS_ERR_CNT_1 = 0x12,
+ RS_ERR_CNT_0 = 0x13,
+ RS_UBC_1 = 0x14,
+ RS_UBC_0 = 0x15,
+ TRL_NOMINAL_RATE_1 = 0x65,
+ TRL_NOMINAL_RATE_0 = 0x66,
+ CHIP_ID = 0x7F,
};
#endif /* _ZL10353_PRIV_ */
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 366c1371ee9..29ed532ba96 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -51,6 +51,7 @@
#include <linux/firmware.h>
#include <linux/crc32.h>
#include <linux/i2c.h>
+#include <linux/kthread.h>
#include <asm/system.h>
@@ -223,11 +224,10 @@ static void recover_arm(struct av7110 *av7110)
static void av7110_arm_sync(struct av7110 *av7110)
{
- av7110->arm_rmmod = 1;
- wake_up_interruptible(&av7110->arm_wait);
+ if (av7110->arm_thread)
+ kthread_stop(av7110->arm_thread);
- while (av7110->arm_thread)
- msleep(1);
+ av7110->arm_thread = NULL;
}
static int arm_thread(void *data)
@@ -238,17 +238,11 @@ static int arm_thread(void *data)
dprintk(4, "%p\n",av7110);
- lock_kernel();
- daemonize("arm_mon");
- sigfillset(&current->blocked);
- unlock_kernel();
-
- av7110->arm_thread = current;
-
for (;;) {
timeout = wait_event_interruptible_timeout(av7110->arm_wait,
- av7110->arm_rmmod, 5 * HZ);
- if (-ERESTARTSYS == timeout || av7110->arm_rmmod) {
+ kthread_should_stop(), 5 * HZ);
+
+ if (-ERESTARTSYS == timeout || kthread_should_stop()) {
/* got signal or told to quit*/
break;
}
@@ -276,7 +270,6 @@ static int arm_thread(void *data)
av7110->arm_errors = 0;
}
- av7110->arm_thread = NULL;
return 0;
}
@@ -695,8 +688,8 @@ static void gpioirq(unsigned long data)
static int dvb_osd_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
dprintk(4, "%p\n", av7110);
@@ -786,7 +779,7 @@ int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter)
{
struct dvb_demux_feed *dvbdmxfeed = dvbdmxfilter->feed;
- struct av7110 *av7110 = (struct av7110 *) dvbdmxfeed->demux->priv;
+ struct av7110 *av7110 = dvbdmxfeed->demux->priv;
u16 buf[20];
int ret, i;
u16 handle;
@@ -835,7 +828,7 @@ static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter)
static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
{
- struct av7110 *av7110 = (struct av7110 *) dvbdmxfilter->feed->demux->priv;
+ struct av7110 *av7110 = dvbdmxfilter->feed->demux->priv;
u16 buf[3];
u16 answ[2];
int ret;
@@ -871,7 +864,7 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
{
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
- struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv;
+ struct av7110 *av7110 = dvbdmx->priv;
u16 *pid = dvbdmx->pids, npids[5];
int i;
int ret = 0;
@@ -914,7 +907,7 @@ static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed)
{
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
- struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv;
+ struct av7110 *av7110 = dvbdmx->priv;
u16 *pid = dvbdmx->pids, npids[5];
int i;
@@ -1103,9 +1096,9 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
/* pointer casting paranoia... */
BUG_ON(!demux);
- dvbdemux = (struct dvb_demux *) demux->priv;
+ dvbdemux = demux->priv;
BUG_ON(!dvbdemux);
- av7110 = (struct av7110 *) dvbdemux->priv;
+ av7110 = dvbdemux->priv;
dprintk(4, "%p\n", av7110);
@@ -1137,7 +1130,7 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
- struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ struct av7110* av7110 = fe->dvb->priv;
switch (tone) {
case SEC_TONE_ON:
@@ -1197,7 +1190,7 @@ static int start_ts_capture(struct av7110 *budget)
static int budget_start_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
- struct av7110 *budget = (struct av7110 *) demux->priv;
+ struct av7110 *budget = demux->priv;
int status;
dprintk(2, "av7110: %p\n", budget);
@@ -1212,7 +1205,7 @@ static int budget_start_feed(struct dvb_demux_feed *feed)
static int budget_stop_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
- struct av7110 *budget = (struct av7110 *) demux->priv;
+ struct av7110 *budget = demux->priv;
int status;
dprintk(2, "budget: %p\n", budget);
@@ -1551,7 +1544,7 @@ static int get_firmware(struct av7110* av7110)
static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
- struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ struct av7110* av7110 = fe->dvb->priv;
u8 pwr = 0;
u8 buf[4];
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
@@ -1702,7 +1695,7 @@ static int alps_tdlb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_front
static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
{
#if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE)
- struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ struct av7110* av7110 = fe->dvb->priv;
return request_firmware(fw, name, &av7110->dev->pci->dev);
#else
@@ -1867,7 +1860,7 @@ static struct stv0297_config nexusca_stv0297_config = {
static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
- struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ struct av7110* av7110 = fe->dvb->priv;
u32 div;
u8 cfg, cpump, band_select;
u8 data[4];
@@ -2338,6 +2331,7 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
const int length = TS_WIDTH * TS_HEIGHT;
struct pci_dev *pdev = dev->pci;
struct av7110 *av7110;
+ struct task_struct *thread;
int ret, count = 0;
dprintk(4, "dev: %p\n", dev);
@@ -2622,9 +2616,12 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
printk ("dvb-ttpci: Warning, firmware version 0x%04x is too old. "
"System might be unstable!\n", FW_VERSION(av7110->arm_app));
- ret = kernel_thread(arm_thread, (void *) av7110, 0);
- if (ret < 0)
+ thread = kthread_run(arm_thread, (void *) av7110, "arm_mon");
+ if (IS_ERR(thread)) {
+ ret = PTR_ERR(thread);
goto err_stop_arm_9;
+ }
+ av7110->arm_thread = thread;
/* set initial volume in mixer struct */
av7110->mixer.volume_left = volume;
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index 9c79696da08..b98bd453cad 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -35,7 +35,6 @@
#define ANALOG_TUNER_VES1820 1
#define ANALOG_TUNER_STV0297 2
-#define ANALOG_TUNER_VBI 0x100
extern int av7110_debug;
@@ -205,7 +204,6 @@ struct av7110 {
struct task_struct *arm_thread;
wait_queue_head_t arm_wait;
u16 arm_loops;
- int arm_rmmod;
void *debi_virt;
dma_addr_t debi_bus;
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 795e6e95915..e719af80768 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -880,8 +880,8 @@ static int dvb_video_get_event (struct av7110 *av7110, struct video_event *event
static unsigned int dvb_video_poll(struct file *file, poll_table *wait)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
unsigned int mask = 0;
dprintk(2, "av7110:%p, \n", av7110);
@@ -908,8 +908,8 @@ static unsigned int dvb_video_poll(struct file *file, poll_table *wait)
static ssize_t dvb_video_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
dprintk(2, "av7110:%p, \n", av7110);
@@ -924,8 +924,8 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf,
static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
unsigned int mask = 0;
dprintk(2, "av7110:%p, \n", av7110);
@@ -944,8 +944,8 @@ static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)
static ssize_t dvb_audio_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
dprintk(2, "av7110:%p, \n", av7110);
@@ -989,8 +989,8 @@ static int play_iframe(struct av7110 *av7110, u8 __user *buf, unsigned int len,
static int dvb_video_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
unsigned long arg = (unsigned long) parg;
int ret = 0;
@@ -1203,8 +1203,8 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
static int dvb_audio_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
unsigned long arg = (unsigned long) parg;
int ret = 0;
@@ -1349,8 +1349,8 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
static int dvb_video_open(struct inode *inode, struct file *file)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
int err;
dprintk(2, "av7110:%p, \n", av7110);
@@ -1374,8 +1374,8 @@ static int dvb_video_open(struct inode *inode, struct file *file)
static int dvb_video_release(struct inode *inode, struct file *file)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
dprintk(2, "av7110:%p, \n", av7110);
@@ -1388,9 +1388,9 @@ static int dvb_video_release(struct inode *inode, struct file *file)
static int dvb_audio_open(struct inode *inode, struct file *file)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
- int err=dvb_generic_open(inode, file);
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
+ int err = dvb_generic_open(inode, file);
dprintk(2, "av7110:%p, \n", av7110);
@@ -1403,8 +1403,8 @@ static int dvb_audio_open(struct inode *inode, struct file *file)
static int dvb_audio_release(struct inode *inode, struct file *file)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
dprintk(2, "av7110:%p, \n", av7110);
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
index 4251a97d420..e9b4e88e793 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
@@ -214,8 +214,8 @@ static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file,
static int dvb_ca_open(struct inode *inode, struct file *file)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
int err = dvb_generic_open(inode, file);
dprintk(8, "av7110:%p\n",av7110);
@@ -228,8 +228,8 @@ static int dvb_ca_open(struct inode *inode, struct file *file)
static unsigned int dvb_ca_poll (struct file *file, poll_table *wait)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
struct dvb_ringbuffer *rbuf = &av7110->ci_rbuffer;
struct dvb_ringbuffer *wbuf = &av7110->ci_wbuffer;
unsigned int mask = 0;
@@ -251,8 +251,8 @@ static unsigned int dvb_ca_poll (struct file *file, poll_table *wait)
static int dvb_ca_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
unsigned long arg = (unsigned long) parg;
dprintk(8, "av7110:%p\n",av7110);
@@ -329,8 +329,8 @@ static int dvb_ca_ioctl(struct inode *inode, struct file *file,
static ssize_t dvb_ca_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
dprintk(8, "av7110:%p\n",av7110);
return ci_ll_write(&av7110->ci_wbuffer, file, buf, count, ppos);
@@ -339,15 +339,13 @@ static ssize_t dvb_ca_write(struct file *file, const char __user *buf,
static ssize_t dvb_ca_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
dprintk(8, "av7110:%p\n",av7110);
return ci_ll_read(&av7110->ci_rbuffer, file, buf, count, ppos);
}
-
-
static struct file_operations dvb_ca_fops = {
.owner = THIS_MODULE,
.read = dvb_ca_read,
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
index e4544ea2b89..f59465bb0af 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -4,6 +4,7 @@
#include <linux/moduleparam.h>
#include <linux/input.h>
#include <linux/proc_fs.h>
+#include <linux/kernel.h>
#include <asm/bitops.h>
#include "av7110.h"
@@ -16,6 +17,7 @@
static int av_cnt;
static struct av7110 *av_list[4];
static struct input_dev *input_dev;
+static char input_phys[32];
static u8 delay_timer_finished;
@@ -217,7 +219,7 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
static struct proc_dir_entry *e;
int err;
- if (av_cnt >= sizeof av_list/sizeof av_list[0])
+ if (av_cnt >= ARRAY_SIZE(av_list))
return -ENOSPC;
av7110_setup_irc_config(av7110, 0x0001);
@@ -231,8 +233,22 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
if (!input_dev)
return -ENOMEM;
+ snprintf(input_phys, sizeof(input_phys),
+ "pci-%s/ir0", pci_name(av7110->dev->pci));
+
input_dev->name = "DVB on-card IR receiver";
+ input_dev->phys = input_phys;
+ input_dev->id.bustype = BUS_PCI;
+ input_dev->id.version = 1;
+ if (av7110->dev->pci->subsystem_vendor) {
+ input_dev->id.vendor = av7110->dev->pci->subsystem_vendor;
+ input_dev->id.product = av7110->dev->pci->subsystem_device;
+ } else {
+ input_dev->id.vendor = av7110->dev->pci->vendor;
+ input_dev->id.product = av7110->dev->pci->device;
+ }
+ input_dev->cdev.dev = &av7110->dev->pci->dev;
set_bit(EV_KEY, input_dev->evbit);
set_bit(EV_REP, input_dev->evbit);
input_register_keys();
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index dbfd5e7b4be..cde5d3ae7ec 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -140,17 +140,6 @@ static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
return 0;
}
-static int stv0297_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
-{
- u8 buf [] = { reg, data };
- struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 2 };
-
- if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
- return -1;
- return 0;
-}
-
-
static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4])
{
struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
@@ -193,6 +182,7 @@ static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq)
static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq)
{
+ struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
u32 div;
u8 data[4];
@@ -213,8 +203,8 @@ static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq)
else
return -EINVAL;
- stv0297_writereg(dev, 0x1C, 0x87, 0x78);
- stv0297_writereg(dev, 0x1C, 0x86, 0xc8);
+ if (av7110->fe->ops.i2c_gate_ctrl)
+ av7110->fe->ops.i2c_gate_ctrl(av7110->fe, 1);
return tuner_write(dev, 0x63, data);
}
@@ -817,20 +807,20 @@ int av7110_init_v4l(struct av7110 *av7110)
saa7146_vv_release(dev);
return -ENODEV;
}
- if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
+ if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI))
ERR(("cannot register vbi v4l2 device. skipping.\n"));
- } else {
- if (av7110->analog_tuner_flags)
- av7110->analog_tuner_flags |= ANALOG_TUNER_VBI;
- }
return 0;
}
int av7110_exit_v4l(struct av7110 *av7110)
{
+ struct saa7146_dev* dev = av7110->dev;
+
saa7146_unregister_device(&av7110->v4l_dev, av7110->dev);
- if (av7110->analog_tuner_flags & ANALOG_TUNER_VBI)
- saa7146_unregister_device(&av7110->vbi_dev, av7110->dev);
+ saa7146_unregister_device(&av7110->vbi_dev, av7110->dev);
+
+ saa7146_vv_release(dev);
+
return 0;
}
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 89ab4b59155..3035b224c7a 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -1089,6 +1089,8 @@ static int budget_av_detach(struct saa7146_dev *dev)
msleep(200);
saa7146_unregister_device(&budget_av->vd, dev);
+
+ saa7146_vv_release(dev);
}
if (budget_av->budget.ci_present)
@@ -1145,6 +1147,7 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
/* fixme: proper cleanup here */
ERR(("cannot register capture v4l2 device.\n"));
+ saa7146_vv_release(dev);
return err;
}
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index f2066b47bae..464feaf1a9a 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -29,8 +29,6 @@
* the project's page is at http://www.linuxtv.org/dvb/
*/
-#include "budget.h"
-
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/slab.h>
@@ -39,6 +37,8 @@
#include <linux/spinlock.h>
#include <media/ir-common.h>
+#include "budget.h"
+
#include "dvb_ca_en50221.h"
#include "stv0299.h"
#include "stv0297.h"
@@ -130,6 +130,7 @@ static void msp430_ir_interrupt(unsigned long data)
int toggle;
static int prev_toggle = -1;
static u32 ir_key;
+ static int state = 0;
u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
/*
@@ -138,21 +139,34 @@ static void msp430_ir_interrupt(unsigned long data)
* type1: X1CCCCCC, C = command bits (0 - 63)
* type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
*
- * More than one command byte may be generated before the device byte
- * Only when we have both, a correct keypress is generated
+ * Each signal from the remote control can generate one or more command
+ * bytes and one or more device bytes. For the repeated bytes, the
+ * highest bit (X) is set. The first command byte is always generated
+ * before the first device byte. Other than that, no specific order
+ * seems to apply.
+ *
+ * Only when we have a command and device byte, a keypress is
+ * generated.
*/
+ if (ir_debug)
+ printk("budget_ci: received byte 0x%02x\n", command);
+
+ /* Is this a repeated byte? */
+ if (command & 0x80)
+ return;
+
/* Is this a RC5 command byte? */
if (command & 0x40) {
- if (ir_debug)
- printk("budget_ci: received command byte 0x%02x\n", command);
+ state = 1;
ir_key = command & 0x3f;
return;
}
/* It's a RC5 device byte */
- if (ir_debug)
- printk("budget_ci: received device byte 0x%02x\n", command);
+ if (!state)
+ return;
+ state = 0;
device = command & 0x1f;
toggle = command & 0x20;
@@ -223,7 +237,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
switch (budget_ci->budget.dev->pci->subsystem_device) {
case 0x100c:
case 0x100f:
- case 0x1010:
case 0x1011:
case 0x1012:
case 0x1017:
@@ -236,6 +249,16 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
else
budget_ci->ir.rc5_device = rc5_device;
break;
+ case 0x1010:
+ /* for the Technotrend 1500 bundled remote */
+ ir_input_init(input_dev, &budget_ci->ir.state,
+ IR_TYPE_RC5, ir_codes_tt_1500);
+
+ if (rc5_device < 0)
+ budget_ci->ir.rc5_device = IR_DEVICE_ANY;
+ else
+ budget_ci->ir.rc5_device = rc5_device;
+ break;
default:
/* unknown remote */
ir_input_init(input_dev, &budget_ci->ir.state,
@@ -869,6 +892,17 @@ static struct tda1004x_config philips_tdm1316l_config = {
.request_firmware = philips_tdm1316l_request_firmware,
};
+static struct tda1004x_config philips_tdm1316l_config_invert = {
+
+ .demod_address = 0x8,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
+ .request_firmware = philips_tdm1316l_request_firmware,
+};
+
static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
@@ -1092,9 +1126,8 @@ static void frontend_init(struct budget_ci *budget_ci)
case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
budget_ci->tuner_pll_address = 0x60;
- philips_tdm1316l_config.invert = 1;
budget_ci->budget.dvb_frontend =
- dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+ dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index bd6e7baae2e..78c98b08997 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -20,8 +20,6 @@
*
*/
-#include <linux/mutex.h>
-
#include <linux/list.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -35,6 +33,8 @@
#include <linux/init.h>
#include <linux/input.h>
+#include <linux/mutex.h>
+
#include "dmxdev.h"
#include "dvb_demux.h"
#include "dvb_filter.h"
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 19d45cc940b..9f1addae692 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -180,136 +180,163 @@ static int az_setfreq(struct az_device *dev, unsigned long frequency)
return 0;
}
-static int az_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+static int vidioc_querycap (struct file *file, void *priv,
+ struct v4l2_capability *v)
+{
+ strlcpy(v->driver, "radio-aztech", sizeof (v->driver));
+ strlcpy(v->card, "Aztech Radio", sizeof (v->card));
+ sprintf(v->bus_info,"ISA");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+ return 0;
+}
+
+static int vidioc_g_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *v)
{
struct video_device *dev = video_devdata(file);
struct az_device *az = dev->priv;
- switch(cmd)
- {
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *v = arg;
- memset(v,0,sizeof(*v));
- strlcpy(v->driver, "radio-aztech", sizeof (v->driver));
- strlcpy(v->card, "Aztech Radio", sizeof (v->card));
- sprintf(v->bus_info,"ISA");
- v->version = RADIO_VERSION;
- v->capabilities = V4L2_CAP_TUNER;
+ if (v->index > 0)
+ return -EINVAL;
- return 0;
- }
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *v = arg;
-
- if (v->index > 0)
- return -EINVAL;
-
- memset(v,0,sizeof(*v));
- strcpy(v->name, "FM");
- v->type = V4L2_TUNER_RADIO;
-
- v->rangelow=(87*16000);
- v->rangehigh=(108*16000);
- v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
- v->capability=V4L2_TUNER_CAP_LOW;
- if(az_getstereo(az))
- v->audmode = V4L2_TUNER_MODE_STEREO;
- else
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal=0xFFFF*az_getsigstr(az);
+ strcpy(v->name, "FM");
+ v->type = V4L2_TUNER_RADIO;
- return 0;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *v = arg;
+ v->rangelow=(87*16000);
+ v->rangehigh=(108*16000);
+ v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+ v->capability=V4L2_TUNER_CAP_LOW;
+ if(az_getstereo(az))
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->signal=0xFFFF*az_getsigstr(az);
- if (v->index > 0)
- return -EINVAL;
+ return 0;
+}
- return 0;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
- az->curfreq = f->frequency;
- az_setfreq(az, az->curfreq);
- return 0;
- }
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
+static int vidioc_s_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *v)
+{
+ if (v->index > 0)
+ return -EINVAL;
- f->type = V4L2_TUNER_RADIO;
- f->frequency = az->curfreq;
+ return 0;
+}
- return 0;
- }
+static int vidioc_g_audio (struct file *file, void *priv,
+ struct v4l2_audio *a)
+{
+ if (a->index > 1)
+ return -EINVAL;
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
- if (qc->id && qc->id == radio_qctrl[i].id) {
- memcpy(qc, &(radio_qctrl[i]),
- sizeof(*qc));
- return (0);
- }
- }
- return -EINVAL;
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl= arg;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (az->curvol==0)
- ctrl->value=1;
- else
- ctrl->value=0;
- return (0);
- case V4L2_CID_AUDIO_VOLUME:
- ctrl->value=az->curvol * 6554;
- return (0);
- }
- return -EINVAL;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl= arg;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value) {
- az_setvol(az,0);
- } else {
- az_setvol(az,az->curvol);
- }
- return (0);
- case V4L2_CID_AUDIO_VOLUME:
- az_setvol(az,ctrl->value);
- return (0);
- }
- return -EINVAL;
+ strcpy(a->name, "Radio");
+ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+ if (i != 0)
+ return -EINVAL;
+ return 0;
+}
+
+
+static int vidioc_s_audio (struct file *file, void *priv,
+ struct v4l2_audio *a)
+{
+ if (a->index != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct video_device *dev = video_devdata(file);
+ struct az_device *az = dev->priv;
+
+ az->curfreq = f->frequency;
+ az_setfreq(az, az->curfreq);
+ return 0;
+}
+
+static int vidioc_g_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct video_device *dev = video_devdata(file);
+ struct az_device *az = dev->priv;
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = az->curfreq;
+
+ return 0;
+}
+
+static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]),
+ sizeof(*qc));
+ return (0);
}
+ }
+ return -EINVAL;
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct video_device *dev = video_devdata(file);
+ struct az_device *az = dev->priv;
- default:
- return v4l_compat_translate_ioctl(inode,file,cmd,arg,
- az_do_ioctl);
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (az->curvol==0)
+ ctrl->value=1;
+ else
+ ctrl->value=0;
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value=az->curvol * 6554;
+ return (0);
}
+ return -EINVAL;
}
-static int az_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
{
- return video_usercopy(inode, file, cmd, arg, az_do_ioctl);
+ struct video_device *dev = video_devdata(file);
+ struct az_device *az = dev->priv;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value) {
+ az_setvol(az,0);
+ } else {
+ az_setvol(az,az->curvol);
+ }
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ az_setvol(az,ctrl->value);
+ return (0);
+ }
+ return -EINVAL;
}
static struct az_device aztech_unit;
@@ -318,20 +345,35 @@ static const struct file_operations aztech_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
- .ioctl = az_ioctl,
+ .ioctl = video_ioctl2,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
static struct video_device aztech_radio=
{
- .owner = THIS_MODULE,
- .name = "Aztech radio",
- .type = VID_TYPE_TUNER,
- .hardware = 0,
- .fops = &aztech_fops,
+ .owner = THIS_MODULE,
+ .name = "Aztech radio",
+ .type = VID_TYPE_TUNER,
+ .hardware = 0,
+ .fops = &aztech_fops,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
};
+module_param_named(debug,aztech_radio.debug, int, 0644);
+MODULE_PARM_DESC(debug,"activates debug info");
+
static int __init aztech_init(void)
{
if(io==-1)
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 05e5aa77025..74976cba869 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -89,14 +89,6 @@ static struct v4l2_queryctrl radio_qctrl[] = {
#define GEMTEK_PCI_RANGE_HIGH (108*16000)
#endif
-#ifndef TRUE
-#define TRUE (1)
-#endif
-
-#ifndef FALSE
-#define FALSE (0)
-#endif
-
struct gemtek_pci_card {
struct video_device *videodev;
@@ -146,12 +138,12 @@ static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
static inline void gemtek_pci_nil( u32 port, u8 *last_byte )
{
- __gemtek_pci_cmd( 0x00, port, last_byte, FALSE );
+ __gemtek_pci_cmd( 0x00, port, last_byte, false );
}
static inline void gemtek_pci_cmd( u16 cmd, u32 port, u8 *last_byte )
{
- __gemtek_pci_cmd( cmd, port, last_byte, TRUE );
+ __gemtek_pci_cmd( cmd, port, last_byte, true );
}
static void gemtek_pci_setfrequency( struct gemtek_pci_card *card, unsigned long frequency )
@@ -184,14 +176,14 @@ static void gemtek_pci_setfrequency( struct gemtek_pci_card *card, unsigned long
static inline void gemtek_pci_mute( struct gemtek_pci_card *card )
{
outb( 0x1f, card->iobase );
- card->mute = TRUE;
+ card->mute = true;
}
static inline void gemtek_pci_unmute( struct gemtek_pci_card *card )
{
if ( card->mute ) {
gemtek_pci_setfrequency( card, card->current_frequency );
- card->mute = FALSE;
+ card->mute = false;
}
}
@@ -259,7 +251,7 @@ static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
gemtek_pci_setfrequency( card, f->frequency );
card->current_frequency = f->frequency;
- card->mute = FALSE;
+ card->mute = false;
return 0;
}
case VIDIOC_QUERYCTRL:
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index 6beeb74004b..8e184cfc1c9 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -27,7 +27,9 @@
* BUGS:
* - card unmutes if you change frequency
*
- * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
+ * (c) 2006, 2007 by Mauro Carvalho Chehab <mchehab@infradead.org>:
+ * - Conversion to V4L2 API
+ * - Uses video_ioctl2 for parsing and to add debug support
*/
@@ -43,10 +45,18 @@
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
-#define DRIVER_VERSION "0.76"
+#define DRIVER_VERSION "0.77"
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
-#define RADIO_VERSION KERNEL_VERSION(0,7,6)
+#define RADIO_VERSION KERNEL_VERSION(0,7,7)
+
+static struct video_device maxiradio_radio;
+
+#define dprintk(num, fmt, arg...) \
+ do { \
+ if (maxiradio_radio.debug >= num) \
+ printk(KERN_DEBUG "%s: " fmt, \
+ maxiradio_radio.name, ## arg); } while (0)
static struct v4l2_queryctrl radio_qctrl[] = {
{
@@ -81,30 +91,21 @@ module_param(radio_nr, int, 0);
#define FREQ_IF 171200 /* 10.7*16000 */
#define FREQ_STEP 200 /* 12.5*16 */
-#define FREQ2BITS(x) ((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\
- /(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */
+/* (x==fmhz*16*1000) -> bits */
+#define FREQ2BITS(x) ((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1)) \
+ /(FREQ_STEP<<2))<<2)
#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF)
-static int radio_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
-
static const struct file_operations maxiradio_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
- .ioctl = radio_ioctl,
+ .ioctl = video_ioctl2,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
-static struct video_device maxiradio_radio =
-{
- .owner = THIS_MODULE,
- .name = "Maxi Radio FM2000 radio",
- .type = VID_TYPE_TUNER,
- .fops = &maxiradio_fops,
-};
static struct radio_device
{
@@ -116,12 +117,14 @@ static struct radio_device
unsigned long freq;
struct mutex lock;
-} radio_unit = {0, 0, 0, 0, };
-
+} radio_unit = {
+ .muted =1,
+ .freq = FREQ_LO,
+};
static void outbit(unsigned long bit, __u16 io)
{
- if(bit != 0)
+ if (bit != 0)
{
outb( power|wren|data ,io); udelay(4);
outb( power|wren|data|clk ,io); udelay(4);
@@ -137,14 +140,20 @@ static void outbit(unsigned long bit, __u16 io)
static void turn_power(__u16 io, int p)
{
- if(p != 0) outb(power, io); else outb(0,io);
+ if (p != 0) {
+ dprintk(1, "Radio powered on\n");
+ outb(power, io);
+ } else {
+ dprintk(1, "Radio powered off\n");
+ outb(0,io);
+ }
}
-
-static void set_freq(__u16 io, __u32 data)
+static void set_freq(__u16 io, __u32 freq)
{
unsigned long int si;
int bl;
+ int data = FREQ2BITS(freq);
/* TEA5757 shift register bits (see pdf) */
@@ -163,161 +172,225 @@ static void set_freq(__u16 io, __u32 data)
outbit(0,io); // 16 search level
si = 0x8000;
- for(bl = 1; bl <= 16 ; bl++) { outbit(data & si,io); si >>=1; }
+ for (bl = 1; bl <= 16 ; bl++) {
+ outbit(data & si,io);
+ si >>=1;
+ }
- outb(power,io);
+ dprintk(1, "Radio freq set to %d.%02d MHz\n",
+ freq / 16000,
+ freq % 16000 * 100 / 16000);
+
+ turn_power(io, 1);
}
static int get_stereo(__u16 io)
{
- outb(power,io); udelay(4);
+ outb(power,io);
+ udelay(4);
+
return !(inb(io) & mo_st);
}
static int get_tune(__u16 io)
{
- outb(power+clk,io); udelay(4);
+ outb(power+clk,io);
+ udelay(4);
+
return !(inb(io) & mo_st);
}
-static inline int radio_function(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+static int vidioc_querycap (struct file *file, void *priv,
+ struct v4l2_capability *v)
+{
+ strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver));
+ strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card));
+ sprintf(v->bus_info,"ISA");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+
+ return 0;
+}
+
+static int vidioc_g_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *v)
{
struct video_device *dev = video_devdata(file);
struct radio_device *card=dev->priv;
- switch(cmd) {
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *v = arg;
- memset(v,0,sizeof(*v));
- strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver));
- strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card));
- sprintf(v->bus_info,"ISA");
- v->version = RADIO_VERSION;
- v->capabilities = V4L2_CAP_TUNER;
+ if (v->index > 0)
+ return -EINVAL;
- return 0;
- }
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *v = arg;
+ memset(v,0,sizeof(*v));
+ strcpy(v->name, "FM");
+ v->type = V4L2_TUNER_RADIO;
- if (v->index > 0)
- return -EINVAL;
+ v->rangelow=FREQ_LO;
+ v->rangehigh=FREQ_HI;
+ v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+ v->capability=V4L2_TUNER_CAP_LOW;
+ if(get_stereo(card->io))
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->signal=0xffff*get_tune(card->io);
- memset(v,0,sizeof(*v));
- strcpy(v->name, "FM");
- v->type = V4L2_TUNER_RADIO;
+ return 0;
+}
- v->rangelow=FREQ_LO;
- v->rangehigh=FREQ_HI;
- v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
- v->capability=V4L2_TUNER_CAP_LOW;
- if(get_stereo(card->io))
- v->audmode = V4L2_TUNER_MODE_STEREO;
- else
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal=0xffff*get_tune(card->io);
+static int vidioc_s_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *v)
+{
+ if (v->index > 0)
+ return -EINVAL;
- return 0;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *v = arg;
+ return 0;
+}
- if (v->index > 0)
- return -EINVAL;
+static int vidioc_g_audio (struct file *file, void *priv,
+ struct v4l2_audio *a)
+{
+ if (a->index > 1)
+ return -EINVAL;
- return 0;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
+ strcpy(a->name, "FM");
+ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+}
- if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
- return -EINVAL;
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+ *i = 0;
- card->freq = f->frequency;
- set_freq(card->io, FREQ2BITS(card->freq));
- msleep(125);
- return 0;
- }
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
+ return 0;
+}
- f->type = V4L2_TUNER_RADIO;
- f->frequency = card->freq;
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+ if (i != 0)
+ return -EINVAL;
- return 0;
- }
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
- if (qc->id && qc->id == radio_qctrl[i].id) {
- memcpy(qc, &(radio_qctrl[i]),
- sizeof(*qc));
- return (0);
- }
- }
- return -EINVAL;
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl= arg;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value=card->muted;
- return (0);
- }
- return -EINVAL;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl= arg;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- card->muted = ctrl->value;
- if(card->muted)
- turn_power(card->io, 0);
- else
- set_freq(card->io, FREQ2BITS(card->freq));
- return 0;
- }
- return -EINVAL;
- }
+ return 0;
+}
+
+
+static int vidioc_s_audio (struct file *file, void *priv,
+ struct v4l2_audio *a)
+{
+ if (a->index != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct video_device *dev = video_devdata(file);
+ struct radio_device *card=dev->priv;
- default:
- return v4l_compat_translate_ioctl(inode,file,cmd,arg,
- radio_function);
+ if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) {
+ dprintk(1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n",
+ f->frequency / 16000,
+ f->frequency % 16000 * 100 / 16000,
+ FREQ_LO / 16000, FREQ_HI / 16000);
+ return -EINVAL;
}
+
+ card->freq = f->frequency;
+ set_freq(card->io, card->freq);
+ msleep(125);
+
+ return 0;
}
-static int radio_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int vidioc_g_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
{
struct video_device *dev = video_devdata(file);
struct radio_device *card=dev->priv;
- int ret;
- mutex_lock(&card->lock);
- ret = video_usercopy(inode, file, cmd, arg, radio_function);
- mutex_unlock(&card->lock);
- return ret;
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = card->freq;
+
+ dprintk(4, "radio freq is %d.%02d MHz",
+ f->frequency / 16000,
+ f->frequency % 16000 * 100 / 16000);
+
+ return 0;
}
-MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
-MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
-MODULE_LICENSE("GPL");
+static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
+ return (0);
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct video_device *dev = video_devdata(file);
+ struct radio_device *card=dev->priv;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value=card->muted;
+ return (0);
+ }
+
+ return -EINVAL;
+}
+
+static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct video_device *dev = video_devdata(file);
+ struct radio_device *card=dev->priv;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ card->muted = ctrl->value;
+ if(card->muted)
+ turn_power(card->io, 0);
+ else
+ set_freq(card->io, card->freq);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static struct video_device maxiradio_radio =
+{
+ .owner = THIS_MODULE,
+ .name = "Maxi Radio FM2000 radio",
+ .type = VID_TYPE_TUNER,
+ .fops = &maxiradio_fops,
+
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+};
static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -334,7 +407,7 @@ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_d
mutex_init(&radio_unit.lock);
maxiradio_radio.priv = &radio_unit;
- if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
+ if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
printk("radio-maxiradio: can't register device!");
goto err_out_free_region;
}
@@ -389,3 +462,10 @@ static void __exit maxiradio_radio_exit(void)
module_init(maxiradio_radio_init);
module_exit(maxiradio_radio_exit);
+
+MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
+MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
+MODULE_LICENSE("GPL");
+
+module_param_named(debug,maxiradio_radio.debug, int, 0644);
+MODULE_PARM_DESC(debug,"activates debug info");
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 57357db31b8..7a6105153f2 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -342,7 +342,7 @@ endmenu # encoder / decoder chips
config VIDEO_VIVI
tristate "Virtual Video Driver"
- depends on VIDEO_V4L2 && !SPARC32 && !SPARC64
+ depends on VIDEO_V4L2 && !SPARC32 && !SPARC64 && PCI
select VIDEO_BUF
default n
---help---
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 9b1f3f06bb7..44ccaed40b4 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -113,4 +113,3 @@ obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/
obj-$(CONFIG_VIDEO_VIVI) += vivi.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-extra-cflags-$(CONFIG_VIDEO_V4L1_COMPAT) += -DCONFIG_VIDEO_V4L1_COMPAT
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 21ebe8f1381..6addc42df04 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -307,6 +307,7 @@ static struct CARD {
{ 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" },
{ 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" },
{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" },
+ { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" },
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
{ 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini "},
@@ -578,14 +579,9 @@ struct tvcard bttv_tvcards[] = {
.svhs = 2,
.gpiomask = 0x01fe00,
.muxsel = { 2, 3, 1, 1 },
- #if 0
- /* old */
- .gpiomux = { 0x01c000, 0, 0x018000, 0x014000, 0x002000 },
- #else
/* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
.gpiomux = { 0x001e00, 0, 0x018000, 0x014000 },
.gpiomute = 0x002000,
- #endif
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
@@ -894,15 +890,10 @@ struct tvcard bttv_tvcards[] = {
.tuner = 0,
.svhs = 2,
.muxsel = { 2, 3, 1, 1, 0 }, /* TV, CVid, SVid, CVid over SVid connector */
- #if 0
- .gpiomask = 0xc33000,
- .gpiomux = { 0x422000,0x1000,0x0000,0x620000,0x800000 },
- #else
/* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
.gpiomask = 0xb33000,
.gpiomux = { 0x122000,0x1000,0x0000,0x620000 },
.gpiomute = 0x800000,
- #endif
/* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
gpio23 -- hef4052:nEnable (0x800000)
gpio12 -- hef4052:A1
@@ -1937,11 +1928,6 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 4,
.audio_inputs = 1,
.tuner = -1,
- #if 0 /* TODO ... */
- .svhs = OSPREY540_SVID_ANALOG,
- .muxsel = { [OSPREY540_COMP_ANALOG] = 2,
- [OSPREY540_SVID_ANALOG] = 3, },
- #endif
.pll = PLL_28,
.tuner_type = -1,
.tuner_addr = ADDR_UNSET,
@@ -1949,10 +1935,6 @@ struct tvcard bttv_tvcards[] = {
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
- #if 0 /* TODO ... */
- .muxsel_hook = osprey_540_muxsel,
- .picture_hook = osprey_540_set_picture,
- #endif
},
/* ---- card 0x5C ---------------------------------- */
@@ -2627,9 +2609,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_radio = 0,
- #if 0
- .has_remote = 1,
- #endif
},
[BTTV_BOARD_SUPER_TV] = {
/* Rick C <cryptdragoon@gmail.com> */
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 41fd09d7d11..5720b77ac9a 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -9,6 +9,10 @@
some v4l2 code lines are taken from Justin's bttv2 driver which is
(c) 2000 Justin Schoeman <justin@suntiger.ee.up.ac.za>
+ Cropping and overscan support
+ Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
+ Sponsored by OPQ Systems AB
+
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
@@ -64,6 +68,7 @@ static unsigned int radio[BTTV_MAX];
static unsigned int irq_debug;
static unsigned int gbuffers = 8;
static unsigned int gbufsize = 0x208000;
+static unsigned int reset_crop = 1;
static int video_nr = -1;
static int radio_nr = -1;
@@ -103,6 +108,7 @@ module_param(radio_nr, int, 0444);
module_param(vbi_nr, int, 0444);
module_param(gbuffers, int, 0444);
module_param(gbufsize, int, 0444);
+module_param(reset_crop, int, 0444);
module_param(v4l2, int, 0644);
module_param(bigendian, int, 0644);
@@ -129,6 +135,8 @@ MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
+MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default "
+ "is 1 (yes) for compatibility with older applications");
MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
@@ -192,6 +200,33 @@ static u8 SRAM_Table[][60] =
}
};
+/* minhdelayx1 first video pixel we can capture on a line and
+ hdelayx1 start of active video, both relative to rising edge of
+ /HRESET pulse (0H) in 1 / fCLKx1.
+ swidth width of active video and
+ totalwidth total line width, both in 1 / fCLKx1.
+ sqwidth total line width in square pixels.
+ vdelay start of active video in 2 * field lines relative to
+ trailing edge of /VRESET pulse (VDELAY register).
+ sheight height of active video in 2 * field lines.
+ videostart0 ITU-R frame line number of the line corresponding
+ to vdelay in the first field. */
+#define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth, \
+ vdelay, sheight, videostart0) \
+ .cropcap.bounds.left = minhdelayx1, \
+ /* * 2 because vertically we count field lines times two, */ \
+ /* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */ \
+ .cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \
+ /* 4 is a safety margin at the end of the line. */ \
+ .cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4, \
+ .cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY, \
+ .cropcap.defrect.left = hdelayx1, \
+ .cropcap.defrect.top = (videostart0) * 2, \
+ .cropcap.defrect.width = swidth, \
+ .cropcap.defrect.height = sheight, \
+ .cropcap.pixelaspect.numerator = totalwidth, \
+ .cropcap.pixelaspect.denominator = sqwidth,
+
const struct bttv_tvnorm bttv_tvnorms[] = {
/* PAL-BDGHI */
/* max. active video is actually 922, but 924 is divisible by 4 and 3! */
@@ -210,11 +245,26 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.hdelayx1 = 186,
.hactivex1 = 924,
.vdelay = 0x20,
- .vbipack = 255,
+ .vbipack = 255, /* min (2048 / 4, 0x1ff) & 0xff */
.sram = 0,
/* ITU-R frame line number of the first VBI line
- we can capture, of the first and second field. */
- .vbistart = { 7,320 },
+ we can capture, of the first and second field.
+ The last line is determined by cropcap.bounds. */
+ .vbistart = { 7, 320 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 186,
+ /* Should be (768 * 1135 + 944 / 2) / 944.
+ cropcap.defrect is used for image width
+ checks, so we keep the old value 924. */
+ /* swidth */ 924,
+ /* totalwidth */ 1135,
+ /* sqwidth */ 944,
+ /* vdelay */ 0x20,
+ /* sheight */ 576,
+ /* videostart0 */ 23)
+ /* bt878 (and bt848?) can capture another
+ line below active video. */
+ .cropcap.bounds.height = (576 + 2) + 0x20 - 2,
},{
.v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
.name = "NTSC",
@@ -229,9 +279,18 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.hdelayx1 = 128,
.hactivex1 = 910,
.vdelay = 0x1a,
- .vbipack = 144,
+ .vbipack = 144, /* min (1600 / 4, 0x1ff) & 0xff */
.sram = 1,
.vbistart = { 10, 273 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 128,
+ /* Should be (640 * 910 + 780 / 2) / 780? */
+ /* swidth */ 768,
+ /* totalwidth */ 910,
+ /* sqwidth */ 780,
+ /* vdelay */ 0x1a,
+ /* sheight */ 480,
+ /* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_SECAM,
.name = "SECAM",
@@ -249,6 +308,14 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vbipack = 255,
.sram = 0, /* like PAL, correct? */
.vbistart = { 7, 320 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 186,
+ /* swidth */ 924,
+ /* totalwidth */ 1135,
+ /* sqwidth */ 944,
+ /* vdelay */ 0x20,
+ /* sheight */ 576,
+ /* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_PAL_Nc,
.name = "PAL-Nc",
@@ -266,6 +333,14 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vbipack = 144,
.sram = -1,
.vbistart = { 7, 320 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 130,
+ /* swidth */ (640 * 910 + 780 / 2) / 780,
+ /* totalwidth */ 910,
+ /* sqwidth */ 780,
+ /* vdelay */ 0x1a,
+ /* sheight */ 576,
+ /* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_PAL_M,
.name = "PAL-M",
@@ -283,6 +358,14 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vbipack = 144,
.sram = -1,
.vbistart = { 10, 273 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 135,
+ /* swidth */ (640 * 910 + 780 / 2) / 780,
+ /* totalwidth */ 910,
+ /* sqwidth */ 780,
+ /* vdelay */ 0x1a,
+ /* sheight */ 480,
+ /* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_PAL_N,
.name = "PAL-N",
@@ -299,7 +382,15 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x20,
.vbipack = 144,
.sram = -1,
- .vbistart = { 7, 320},
+ .vbistart = { 7, 320 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 186,
+ /* swidth */ (768 * 1135 + 944 / 2) / 944,
+ /* totalwidth */ 1135,
+ /* sqwidth */ 944,
+ /* vdelay */ 0x20,
+ /* sheight */ 576,
+ /* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_NTSC_M_JP,
.name = "NTSC-JP",
@@ -316,7 +407,15 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x16,
.vbipack = 144,
.sram = -1,
- .vbistart = {10, 273},
+ .vbistart = { 10, 273 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 135,
+ /* swidth */ (640 * 910 + 780 / 2) / 780,
+ /* totalwidth */ 910,
+ /* sqwidth */ 780,
+ /* vdelay */ 0x16,
+ /* sheight */ 480,
+ /* videostart0 */ 23)
},{
/* that one hopefully works with the strange timing
* which video recorders produce when playing a NTSC
@@ -338,6 +437,14 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vtotal = 524,
.sram = -1,
.vbistart = { 10, 273 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 186,
+ /* swidth */ 924,
+ /* totalwidth */ 1135,
+ /* sqwidth */ 944,
+ /* vdelay */ 0x1a,
+ /* sheight */ 480,
+ /* videostart0 */ 23)
}
};
static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
@@ -678,25 +785,89 @@ static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
/* ----------------------------------------------------------------------- */
/* resource management */
+/*
+ RESOURCE_ allocated by freed by
+
+ VIDEO_READ bttv_read 1) bttv_read 2)
+
+ VIDEO_STREAM VIDIOC_STREAMON VIDIOC_STREAMOFF
+ VIDIOC_QBUF 1) bttv_release
+ VIDIOCMCAPTURE 1)
+
+ OVERLAY VIDIOCCAPTURE on VIDIOCCAPTURE off
+ VIDIOC_OVERLAY on VIDIOC_OVERLAY off
+ 3) bttv_release
+
+ VBI VIDIOC_STREAMON VIDIOC_STREAMOFF
+ VIDIOC_QBUF 1) bttv_release
+ bttv_read, bttv_poll 1) 4)
+
+ 1) The resource must be allocated when we enter buffer prepare functions
+ and remain allocated while buffers are in the DMA queue.
+ 2) This is a single frame read.
+ 3) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when
+ RESOURCE_OVERLAY is allocated.
+ 4) This is a continuous read, implies VIDIOC_STREAMON.
+
+ Note this driver permits video input and standard changes regardless if
+ resources are allocated.
+*/
+
+#define VBI_RESOURCES (RESOURCE_VBI)
+#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \
+ RESOURCE_VIDEO_STREAM | \
+ RESOURCE_OVERLAY)
+
static
int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
{
+ int xbits; /* mutual exclusive resources */
+
if (fh->resources & bit)
/* have it already allocated */
return 1;
+ xbits = bit;
+ if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM))
+ xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;
+
/* is it free? */
- mutex_lock(&btv->reslock);
- if (btv->resources & bit) {
+ mutex_lock(&btv->lock);
+ if (btv->resources & xbits) {
/* no, someone else uses it */
- mutex_unlock(&btv->reslock);
- return 0;
+ goto fail;
+ }
+
+ if ((bit & VIDEO_RESOURCES)
+ && 0 == (btv->resources & VIDEO_RESOURCES)) {
+ /* Do crop - use current, don't - use default parameters. */
+ __s32 top = btv->crop[!!fh->do_crop].rect.top;
+
+ if (btv->vbi_end > top)
+ goto fail;
+
+ /* We cannot capture the same line as video and VBI data.
+ Claim scan lines crop[].rect.top to bottom. */
+ btv->crop_start = top;
+ } else if (bit & VBI_RESOURCES) {
+ __s32 end = fh->vbi_fmt.end;
+
+ if (end > btv->crop_start)
+ goto fail;
+
+ /* Claim scan lines above fh->vbi_fmt.end. */
+ btv->vbi_end = end;
}
+
/* it's free, grab it */
fh->resources |= bit;
btv->resources |= bit;
- mutex_unlock(&btv->reslock);
+ mutex_unlock(&btv->lock);
return 1;
+
+ fail:
+ mutex_unlock(&btv->lock);
+ return 0;
}
static
@@ -711,6 +882,35 @@ int locked_btres(struct bttv *btv, int bit)
return (btv->resources & bit);
}
+/* Call with btv->lock down. */
+static void
+disclaim_vbi_lines(struct bttv *btv)
+{
+ btv->vbi_end = 0;
+}
+
+/* Call with btv->lock down. */
+static void
+disclaim_video_lines(struct bttv *btv)
+{
+ const struct bttv_tvnorm *tvnorm;
+ u8 crop;
+
+ tvnorm = &bttv_tvnorms[btv->tvnorm];
+ btv->crop_start = tvnorm->cropcap.bounds.top
+ + tvnorm->cropcap.bounds.height;
+
+ /* VBI capturing ends at VDELAY, start of video capturing, no
+ matter how many lines the VBI RISC program expects. When video
+ capturing is off, it shall no longer "preempt" VBI capturing,
+ so we set VDELAY to maximum. */
+ crop = btread(BT848_E_CROP) | 0xc0;
+ btwrite(crop, BT848_E_CROP);
+ btwrite(0xfe, BT848_E_VDELAY_LO);
+ btwrite(crop, BT848_O_CROP);
+ btwrite(0xfe, BT848_O_VDELAY_LO);
+}
+
static
void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
{
@@ -718,10 +918,19 @@ void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
/* trying to free ressources not allocated by us ... */
printk("bttv: BUG! (btres)\n");
}
- mutex_lock(&btv->reslock);
+ mutex_lock(&btv->lock);
fh->resources &= ~bits;
btv->resources &= ~bits;
- mutex_unlock(&btv->reslock);
+
+ bits = btv->resources;
+
+ if (0 == (bits & VIDEO_RESOURCES))
+ disclaim_video_lines(btv);
+
+ if (0 == (bits & VBI_RESOURCES))
+ disclaim_vbi_lines(btv);
+
+ mutex_unlock(&btv->lock);
}
/* ----------------------------------------------------------------------- */
@@ -1030,6 +1239,36 @@ i2c_vidiocschan(struct bttv *btv)
bttv_tda9880_setnorm(btv,btv->tvnorm);
}
+static void
+bttv_crop_calc_limits(struct bttv_crop *c)
+{
+ /* Scale factor min. 1:1, max. 16:1. Min. image size
+ 48 x 32. Scaled width must be a multiple of 4. */
+
+ if (1) {
+ /* For bug compatibility with VIDIOCGCAP and image
+ size checks in earlier driver versions. */
+ c->min_scaled_width = 48;
+ c->min_scaled_height = 32;
+ } else {
+ c->min_scaled_width =
+ (max(48, c->rect.width >> 4) + 3) & ~3;
+ c->min_scaled_height =
+ max(32, c->rect.height >> 4);
+ }
+
+ c->max_scaled_width = c->rect.width & ~3;
+ c->max_scaled_height = c->rect.height;
+}
+
+static void
+bttv_crop_reset(struct bttv_crop *c, int norm)
+{
+ c->rect = bttv_tvnorms[norm].cropcap.defrect;
+ bttv_crop_calc_limits(c);
+}
+
+/* Call with btv->lock down. */
static int
set_tvnorm(struct bttv *btv, unsigned int norm)
{
@@ -1038,9 +1277,24 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
if (norm < 0 || norm >= BTTV_TVNORMS)
return -EINVAL;
- btv->tvnorm = norm;
tvnorm = &bttv_tvnorms[norm];
+ if (btv->tvnorm < 0 ||
+ btv->tvnorm >= BTTV_TVNORMS ||
+ 0 != memcmp(&bttv_tvnorms[btv->tvnorm].cropcap,
+ &tvnorm->cropcap,
+ sizeof (tvnorm->cropcap))) {
+ bttv_crop_reset(&btv->crop[0], norm);
+ btv->crop[1] = btv->crop[0]; /* current = default */
+
+ if (0 == (btv->resources & VIDEO_RESOURCES)) {
+ btv->crop_start = tvnorm->cropcap.bounds.top
+ + tvnorm->cropcap.bounds.height;
+ }
+ }
+
+ btv->tvnorm = norm;
+
btwrite(tvnorm->adelay, BT848_ADELAY);
btwrite(tvnorm->bdelay, BT848_BDELAY);
btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
@@ -1057,6 +1311,7 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
return 0;
}
+/* Call with btv->lock down. */
static void
set_input(struct bttv *btv, unsigned int input)
{
@@ -1459,13 +1714,13 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
btv->loop_irq |= 1;
bttv_set_dma(btv, 0x03);
spin_unlock_irqrestore(&btv->s_lock,flags);
- if (NULL == new)
- free_btres(btv,fh,RESOURCE_OVERLAY);
if (NULL != old) {
dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
bttv_dma_free(&fh->cap,btv, old);
kfree(old);
}
+ if (NULL == new)
+ free_btres(btv,fh,RESOURCE_OVERLAY);
dprintk("switch_overlay: done\n");
return retval;
}
@@ -1479,7 +1734,10 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
unsigned int width, unsigned int height,
enum v4l2_field field)
{
+ struct bttv_fh *fh = q->priv_data;
int redo_dma_risc = 0;
+ struct bttv_crop c;
+ int norm;
int rc;
/* check settings */
@@ -1491,12 +1749,52 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
if (width*height > buf->vb.bsize)
return -EINVAL;
buf->vb.size = buf->vb.bsize;
+
+ /* Make sure tvnorm and vbi_end remain consistent
+ until we're done. */
+ mutex_lock(&btv->lock);
+
+ norm = btv->tvnorm;
+
+ /* In this mode capturing always starts at defrect.top
+ (default VDELAY), ignoring cropping parameters. */
+ if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) {
+ mutex_unlock(&btv->lock);
+ return -EINVAL;
+ }
+
+ mutex_unlock(&btv->lock);
+
+ c.rect = bttv_tvnorms[norm].cropcap.defrect;
} else {
- if (width < 48 ||
- height < 32 ||
- width > bttv_tvnorms[btv->tvnorm].swidth ||
- height > bttv_tvnorms[btv->tvnorm].sheight)
+ mutex_lock(&btv->lock);
+
+ norm = btv->tvnorm;
+ c = btv->crop[!!fh->do_crop];
+
+ mutex_unlock(&btv->lock);
+
+ if (width < c.min_scaled_width ||
+ width > c.max_scaled_width ||
+ height < c.min_scaled_height)
return -EINVAL;
+
+ switch (field) {
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ case V4L2_FIELD_ALTERNATE:
+ /* btv->crop counts frame lines. Max. scale
+ factor is 16:1 for frames, 8:1 for fields. */
+ if (height * 2 > c.max_scaled_height)
+ return -EINVAL;
+ break;
+
+ default:
+ if (height > c.max_scaled_height)
+ return -EINVAL;
+ break;
+ }
+
buf->vb.size = (width * height * fmt->depth) >> 3;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
@@ -1505,12 +1803,17 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
/* alloc + fill struct bttv_buffer (if changed) */
if (buf->vb.width != width || buf->vb.height != height ||
buf->vb.field != field ||
- buf->tvnorm != btv->tvnorm || buf->fmt != fmt) {
+ buf->tvnorm != norm || buf->fmt != fmt ||
+ buf->crop.top != c.rect.top ||
+ buf->crop.left != c.rect.left ||
+ buf->crop.width != c.rect.width ||
+ buf->crop.height != c.rect.height) {
buf->vb.width = width;
buf->vb.height = height;
buf->vb.field = field;
- buf->tvnorm = btv->tvnorm;
+ buf->tvnorm = norm;
buf->fmt = fmt;
+ buf->crop = c.rect;
redo_dma_risc = 1;
}
@@ -1577,7 +1880,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
struct bttv_fh *fh = q->priv_data;
- bttv_dma_free(&fh->cap,fh->btv,buf);
+ bttv_dma_free(q,fh->btv,buf);
}
static struct videobuf_queue_ops bttv_video_qops = {
@@ -1939,11 +2242,179 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
return 0;
}
-static int verify_window(const struct bttv_tvnorm *tvn,
- struct v4l2_window *win, int fixup)
+/* Given cropping boundaries b and the scaled width and height of a
+ single field or frame, which must not exceed hardware limits, this
+ function adjusts the cropping parameters c. */
+static void
+bttv_crop_adjust (struct bttv_crop * c,
+ const struct v4l2_rect * b,
+ __s32 width,
+ __s32 height,
+ enum v4l2_field field)
+{
+ __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field);
+ __s32 max_left;
+ __s32 max_top;
+
+ if (width < c->min_scaled_width) {
+ /* Max. hor. scale factor 16:1. */
+ c->rect.width = width * 16;
+ } else if (width > c->max_scaled_width) {
+ /* Min. hor. scale factor 1:1. */
+ c->rect.width = width;
+
+ max_left = b->left + b->width - width;
+ max_left = min(max_left, (__s32) MAX_HDELAY);
+ if (c->rect.left > max_left)
+ c->rect.left = max_left;
+ }
+
+ if (height < c->min_scaled_height) {
+ /* Max. vert. scale factor 16:1, single fields 8:1. */
+ c->rect.height = height * 16;
+ } else if (frame_height > c->max_scaled_height) {
+ /* Min. vert. scale factor 1:1.
+ Top and height count field lines times two. */
+ c->rect.height = (frame_height + 1) & ~1;
+
+ max_top = b->top + b->height - c->rect.height;
+ if (c->rect.top > max_top)
+ c->rect.top = max_top;
+ }
+
+ bttv_crop_calc_limits(c);
+}
+
+/* Returns an error if scaling to a frame or single field with the given
+ width and height is not possible with the current cropping parameters
+ and width aligned according to width_mask. If adjust_size is TRUE the
+ function may adjust the width and/or height instead, rounding width
+ to (width + width_bias) & width_mask. If adjust_crop is TRUE it may
+ also adjust the current cropping parameters to get closer to the
+ desired image size. */
+static int
+limit_scaled_size (struct bttv_fh * fh,
+ __s32 * width,
+ __s32 * height,
+ enum v4l2_field field,
+ unsigned int width_mask,
+ unsigned int width_bias,
+ int adjust_size,
+ int adjust_crop)
+{
+ struct bttv *btv = fh->btv;
+ const struct v4l2_rect *b;
+ struct bttv_crop *c;
+ __s32 min_width;
+ __s32 min_height;
+ __s32 max_width;
+ __s32 max_height;
+ int rc;
+
+ BUG_ON((int) width_mask >= 0 ||
+ width_bias >= (unsigned int) -width_mask);
+
+ /* Make sure tvnorm, vbi_end and the current cropping parameters
+ remain consistent until we're done. */
+ mutex_lock(&btv->lock);
+
+ b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
+
+ /* Do crop - use current, don't - use default parameters. */
+ c = &btv->crop[!!fh->do_crop];
+
+ if (fh->do_crop
+ && adjust_size
+ && adjust_crop
+ && !locked_btres(btv, VIDEO_RESOURCES)) {
+ min_width = 48;
+ min_height = 32;
+
+ /* We cannot scale up. When the scaled image is larger
+ than crop.rect we adjust the crop.rect as required
+ by the V4L2 spec, hence cropcap.bounds are our limit. */
+ max_width = min(b->width, (__s32) MAX_HACTIVE);
+ max_height = b->height;
+
+ /* We cannot capture the same line as video and VBI data.
+ Note btv->vbi_end is really a minimum, see
+ bttv_vbi_try_fmt(). */
+ if (btv->vbi_end > b->top) {
+ max_height -= btv->vbi_end - b->top;
+ rc = -EBUSY;
+ if (min_height > max_height)
+ goto fail;
+ }
+ } else {
+ rc = -EBUSY;
+ if (btv->vbi_end > c->rect.top)
+ goto fail;
+
+ min_width = c->min_scaled_width;
+ min_height = c->min_scaled_height;
+ max_width = c->max_scaled_width;
+ max_height = c->max_scaled_height;
+
+ adjust_crop = 0;
+ }
+
+ min_width = (min_width - width_mask - 1) & width_mask;
+ max_width = max_width & width_mask;
+
+ /* Max. scale factor is 16:1 for frames, 8:1 for fields. */
+ min_height = min_height;
+ /* Min. scale factor is 1:1. */
+ max_height >>= !V4L2_FIELD_HAS_BOTH(field);
+
+ if (adjust_size) {
+ *width = clamp(*width, min_width, max_width);
+ *height = clamp(*height, min_height, max_height);
+
+ /* Round after clamping to avoid overflow. */
+ *width = (*width + width_bias) & width_mask;
+
+ if (adjust_crop) {
+ bttv_crop_adjust(c, b, *width, *height, field);
+
+ if (btv->vbi_end > c->rect.top) {
+ /* Move the crop window out of the way. */
+ c->rect.top = btv->vbi_end;
+ }
+ }
+ } else {
+ rc = -EINVAL;
+ if (*width < min_width ||
+ *height < min_height ||
+ *width > max_width ||
+ *height > max_height ||
+ 0 != (*width & ~width_mask))
+ goto fail;
+ }
+
+ rc = 0; /* success */
+
+ fail:
+ mutex_unlock(&btv->lock);
+
+ return rc;
+}
+
+/* Returns an error if the given overlay window dimensions are not
+ possible with the current cropping parameters. If adjust_size is
+ TRUE the function may adjust the window width and/or height
+ instead, however it always rounds the horizontal position and
+ width as btcx_align() does. If adjust_crop is TRUE the function
+ may also adjust the current cropping parameters to get closer
+ to the desired window size. */
+static int
+verify_window (struct bttv_fh * fh,
+ struct v4l2_window * win,
+ int adjust_size,
+ int adjust_crop)
{
enum v4l2_field field;
- int maxw, maxh;
+ unsigned int width_mask;
+ int rc;
if (win->w.width < 48 || win->w.height < 32)
return -EINVAL;
@@ -1951,32 +2422,52 @@ static int verify_window(const struct bttv_tvnorm *tvn,
return -EINVAL;
field = win->field;
- maxw = tvn->swidth;
- maxh = tvn->sheight;
if (V4L2_FIELD_ANY == field) {
- field = (win->w.height > maxh/2)
+ __s32 height2;
+
+ height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1;
+ field = (win->w.height > height2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_TOP;
}
switch (field) {
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
- maxh = maxh / 2;
- break;
case V4L2_FIELD_INTERLACED:
break;
default:
return -EINVAL;
}
- if (!fixup && (win->w.width > maxw || win->w.height > maxh))
+ /* 4-byte alignment. */
+ if (NULL == fh->ovfmt)
return -EINVAL;
+ width_mask = ~0;
+ switch (fh->ovfmt->depth) {
+ case 8:
+ case 24:
+ width_mask = ~3;
+ break;
+ case 16:
+ width_mask = ~1;
+ break;
+ case 32:
+ break;
+ default:
+ BUG();
+ }
+
+ win->w.width -= win->w.left & ~width_mask;
+ win->w.left = (win->w.left - width_mask - 1) & width_mask;
+
+ rc = limit_scaled_size(fh, &win->w.width, &win->w.height,
+ field, width_mask,
+ /* width_bias: round down */ 0,
+ adjust_size, adjust_crop);
+ if (0 != rc)
+ return rc;
- if (win->w.width > maxw)
- win->w.width = maxw;
- if (win->w.height > maxh)
- win->w.height = maxh;
win->field = field;
return 0;
}
@@ -1991,7 +2482,9 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
return -EINVAL;
if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
return -EINVAL;
- retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup);
+ retval = verify_window(fh, win,
+ /* adjust_size */ fixup,
+ /* adjust_crop */ fixup);
if (0 != retval)
return retval;
@@ -2048,6 +2541,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
struct bttv_buffer *new;
new = videobuf_alloc(sizeof(*new));
+ new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
retval = bttv_switch_overlay(btv,fh,new);
}
@@ -2080,7 +2574,7 @@ static int bttv_resource(struct bttv_fh *fh)
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- res = RESOURCE_VIDEO;
+ res = RESOURCE_VIDEO_STREAM;
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
res = RESOURCE_VBI;
@@ -2138,7 +2632,7 @@ static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
f->fmt.win.field = fh->ov.field;
return 0;
case V4L2_BUF_TYPE_VBI_CAPTURE:
- bttv_vbi_get_fmt(fh,f);
+ bttv_vbi_get_fmt(fh, &f->fmt.vbi);
return 0;
default:
return -EINVAL;
@@ -2146,35 +2640,35 @@ static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
}
static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
- struct v4l2_format *f)
+ struct v4l2_format *f, int adjust_crop)
{
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
{
const struct bttv_format *fmt;
enum v4l2_field field;
- unsigned int maxw,maxh;
+ __s32 width, height;
+ int rc;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
if (NULL == fmt)
return -EINVAL;
- /* fixup format */
- maxw = bttv_tvnorms[btv->tvnorm].swidth;
- maxh = bttv_tvnorms[btv->tvnorm].sheight;
field = f->fmt.pix.field;
- if (V4L2_FIELD_ANY == field)
- field = (f->fmt.pix.height > maxh/2)
+ if (V4L2_FIELD_ANY == field) {
+ __s32 height2;
+
+ height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+ field = (f->fmt.pix.height > height2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_BOTTOM;
+ }
if (V4L2_FIELD_SEQ_BT == field)
field = V4L2_FIELD_SEQ_TB;
switch (field) {
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
case V4L2_FIELD_ALTERNATE:
- maxh = maxh/2;
- break;
case V4L2_FIELD_INTERLACED:
break;
case V4L2_FIELD_SEQ_TB:
@@ -2185,28 +2679,29 @@ static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
return -EINVAL;
}
+ width = f->fmt.pix.width;
+ height = f->fmt.pix.height;
+
+ rc = limit_scaled_size(fh, &width, &height, field,
+ /* width_mask: 4 pixels */ ~3,
+ /* width_bias: nearest */ 2,
+ /* adjust_size */ 1,
+ adjust_crop);
+ if (0 != rc)
+ return rc;
+
/* update data for the application */
f->fmt.pix.field = field;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.height < 32)
- f->fmt.pix.height = 32;
- if (f->fmt.pix.width > maxw)
- f->fmt.pix.width = maxw;
- if (f->fmt.pix.height > maxh)
- f->fmt.pix.height = maxh;
- pix_format_set_size (&f->fmt.pix, fmt,
- f->fmt.pix.width & ~3,
- f->fmt.pix.height);
+ pix_format_set_size(&f->fmt.pix, fmt, width, height);
return 0;
}
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- return verify_window(&bttv_tvnorms[btv->tvnorm],
- &f->fmt.win, 1);
+ return verify_window(fh, &f->fmt.win,
+ /* adjust_size */ 1,
+ /* adjust_crop */ 0);
case V4L2_BUF_TYPE_VBI_CAPTURE:
- bttv_vbi_try_fmt(fh,f);
- return 0;
+ return bttv_vbi_try_fmt(fh, &f->fmt.vbi);
default:
return -EINVAL;
}
@@ -2225,7 +2720,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
retval = bttv_switch_type(fh,f->type);
if (0 != retval)
return retval;
- retval = bttv_try_fmt(fh,btv,f);
+ retval = bttv_try_fmt(fh,btv,f, /* adjust_crop */ 1);
if (0 != retval)
return retval;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
@@ -2254,12 +2749,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
retval = bttv_switch_type(fh,f->type);
if (0 != retval)
return retval;
- if (locked_btres(fh->btv, RESOURCE_VBI))
- return -EBUSY;
- bttv_vbi_try_fmt(fh,f);
- bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
- bttv_vbi_get_fmt(fh,f);
- return 0;
+ return bttv_vbi_set_fmt(fh, &f->fmt.vbi);
default:
return -EINVAL;
}
@@ -2517,6 +3007,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (*on) {
fh->ov.tvnorm = btv->tvnorm;
new = videobuf_alloc(sizeof(*new));
+ new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
} else {
new = NULL;
@@ -2551,10 +3042,16 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
struct video_mmap *vm = arg;
struct bttv_buffer *buf;
enum v4l2_field field;
+ __s32 height2;
+ int res;
if (vm->frame >= VIDEO_MAX_FRAME)
return -EINVAL;
+ res = bttv_resource(fh);
+ if (!check_alloc_btres(btv, fh, res))
+ return -EBUSY;
+
mutex_lock(&fh->cap.lock);
retval = -EINVAL;
buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
@@ -2566,7 +3063,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
buf->vb.state == STATE_ACTIVE)
goto fh_unlock_and_return;
- field = (vm->height > bttv_tvnorms[btv->tvnorm].sheight/2)
+ height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+ field = (vm->height > height2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_BOTTOM;
retval = bttv_prepare_buffer(&fh->cap,btv,buf,
@@ -2613,54 +3111,17 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
}
case VIDIOCGVBIFMT:
- {
- struct vbi_format *fmt = (void *) arg;
- struct v4l2_format fmt2;
-
if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
if (0 != retval)
return retval;
}
- bttv_vbi_get_fmt(fh, &fmt2);
-
- memset(fmt,0,sizeof(*fmt));
- fmt->sampling_rate = fmt2.fmt.vbi.sampling_rate;
- fmt->samples_per_line = fmt2.fmt.vbi.samples_per_line;
- fmt->sample_format = VIDEO_PALETTE_RAW;
- fmt->start[0] = fmt2.fmt.vbi.start[0];
- fmt->count[0] = fmt2.fmt.vbi.count[0];
- fmt->start[1] = fmt2.fmt.vbi.start[1];
- fmt->count[1] = fmt2.fmt.vbi.count[1];
- if (fmt2.fmt.vbi.flags & V4L2_VBI_UNSYNC)
- fmt->flags |= VBI_UNSYNC;
- if (fmt2.fmt.vbi.flags & V4L2_VBI_INTERLACED)
- fmt->flags |= VBI_INTERLACED;
- return 0;
- }
- case VIDIOCSVBIFMT:
- {
- struct vbi_format *fmt = (void *) arg;
- struct v4l2_format fmt2;
- retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
- if (0 != retval)
- return retval;
- bttv_vbi_get_fmt(fh, &fmt2);
-
- if (fmt->sampling_rate != fmt2.fmt.vbi.sampling_rate ||
- fmt->samples_per_line != fmt2.fmt.vbi.samples_per_line ||
- fmt->sample_format != VIDEO_PALETTE_RAW ||
- fmt->start[0] != fmt2.fmt.vbi.start[0] ||
- fmt->start[1] != fmt2.fmt.vbi.start[1] ||
- fmt->count[0] != fmt->count[1] ||
- fmt->count[0] < 1 ||
- fmt->count[0] > 32 /* VBI_MAXLINES */)
- return -EINVAL;
+ /* fall through */
- bttv_vbi_setlines(fh,btv,fmt->count[0]);
- return 0;
- }
+ case VIDIOCSVBIFMT:
+ return v4l_compat_translate_ioctl(inode, file, cmd,
+ arg, bttv_do_ioctl);
case BTTV_VERSION:
case VIDIOCGFREQ:
@@ -2753,7 +3214,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_TRY_FMT:
{
struct v4l2_format *f = arg;
- return bttv_try_fmt(fh,btv,f);
+ return bttv_try_fmt(fh,btv,f, /* adjust_crop */ 0);
}
case VIDIOC_G_FMT:
{
@@ -2792,16 +3253,23 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
return -EINVAL;
- mutex_lock(&fh->cap.lock);
retval = -EINVAL;
if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
- if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
- goto fh_unlock_and_return;
- if (fb->fmt.height > bttv_tvnorms[btv->tvnorm].sheight)
- goto fh_unlock_and_return;
+ __s32 width = fb->fmt.width;
+ __s32 height = fb->fmt.height;
+
+ retval = limit_scaled_size(fh, &width, &height,
+ V4L2_FIELD_INTERLACED,
+ /* width_mask */ ~3,
+ /* width_bias */ 2,
+ /* adjust_size */ 0,
+ /* adjust_crop */ 0);
+ if (0 != retval)
+ return retval;
}
/* ok, accept it */
+ mutex_lock(&fh->cap.lock);
btv->fbuf.base = fb->base;
btv->fbuf.fmt.width = fb->fmt.width;
btv->fbuf.fmt.height = fb->fmt.height;
@@ -2828,6 +3296,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
struct bttv_buffer *new;
new = videobuf_alloc(sizeof(*new));
+ new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
retval = bttv_switch_overlay(btv,fh,new);
}
@@ -2843,7 +3312,13 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
return videobuf_querybuf(bttv_queue(fh),arg);
case VIDIOC_QBUF:
+ {
+ int res = bttv_resource(fh);
+
+ if (!check_alloc_btres(btv, fh, res))
+ return -EBUSY;
return videobuf_qbuf(bttv_queue(fh),arg);
+ }
case VIDIOC_DQBUF:
return videobuf_dqbuf(bttv_queue(fh),arg,
@@ -2942,6 +3417,122 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
}
+ case VIDIOC_CROPCAP:
+ {
+ struct v4l2_cropcap *cap = arg;
+ enum v4l2_buf_type type;
+
+ type = cap->type;
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+ return -EINVAL;
+
+ *cap = bttv_tvnorms[btv->tvnorm].cropcap;
+ cap->type = type;
+
+ return 0;
+ }
+ case VIDIOC_G_CROP:
+ {
+ struct v4l2_crop * crop = arg;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+ return -EINVAL;
+
+ /* No fh->do_crop = 1; because btv->crop[1] may be
+ inconsistent with fh->width or fh->height and apps
+ do not expect a change here. */
+
+ crop->c = btv->crop[!!fh->do_crop].rect;
+
+ return 0;
+ }
+ case VIDIOC_S_CROP:
+ {
+ struct v4l2_crop *crop = arg;
+ const struct v4l2_rect *b;
+ struct bttv_crop c;
+ __s32 b_left;
+ __s32 b_top;
+ __s32 b_right;
+ __s32 b_bottom;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+ return -EINVAL;
+
+ retval = v4l2_prio_check(&btv->prio,&fh->prio);
+ if (0 != retval)
+ return retval;
+
+ /* Make sure tvnorm, vbi_end and the current cropping
+ parameters remain consistent until we're done. Note
+ read() may change vbi_end in check_alloc_btres(). */
+ mutex_lock(&btv->lock);
+
+ retval = -EBUSY;
+
+ if (locked_btres(fh->btv, VIDEO_RESOURCES))
+ goto btv_unlock_and_return;
+
+ b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
+
+ b_left = b->left;
+ b_right = b_left + b->width;
+ b_bottom = b->top + b->height;
+
+ b_top = max(b->top, btv->vbi_end);
+ if (b_top + 32 >= b_bottom)
+ goto btv_unlock_and_return;
+
+ /* Min. scaled size 48 x 32. */
+ c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
+ c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
+
+ c.rect.width = clamp(crop->c.width,
+ 48, b_right - c.rect.left);
+
+ c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
+ /* Top and height must be a multiple of two. */
+ c.rect.top = (c.rect.top + 1) & ~1;
+
+ c.rect.height = clamp(crop->c.height,
+ 32, b_bottom - c.rect.top);
+ c.rect.height = (c.rect.height + 1) & ~1;
+
+ bttv_crop_calc_limits(&c);
+
+ btv->crop[1] = c;
+
+ mutex_unlock(&btv->lock);
+
+ fh->do_crop = 1;
+
+ mutex_lock(&fh->cap.lock);
+
+ if (fh->width < c.min_scaled_width) {
+ fh->width = c.min_scaled_width;
+ btv->init.width = c.min_scaled_width;
+ } else if (fh->width > c.max_scaled_width) {
+ fh->width = c.max_scaled_width;
+ btv->init.width = c.max_scaled_width;
+ }
+
+ if (fh->height < c.min_scaled_height) {
+ fh->height = c.min_scaled_height;
+ btv->init.height = c.min_scaled_height;
+ } else if (fh->height > c.max_scaled_height) {
+ fh->height = c.max_scaled_height;
+ btv->init.height = c.max_scaled_height;
+ }
+
+ mutex_unlock(&fh->cap.lock);
+
+ return 0;
+ }
+
case VIDIOC_ENUMSTD:
case VIDIOC_G_STD:
case VIDIOC_S_STD:
@@ -2963,6 +3554,10 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
fh_unlock_and_return:
mutex_unlock(&fh->cap.lock);
return retval;
+
+ btv_unlock_and_return:
+ mutex_unlock(&btv->lock);
+ return retval;
}
static int bttv_ioctl(struct inode *inode, struct file *file,
@@ -2972,8 +3567,26 @@ static int bttv_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case BTTV_VBISIZE:
+ {
+ const struct bttv_tvnorm *tvnorm;
+
+ tvnorm = fh->vbi_fmt.tvnorm;
+
+ if (fh->vbi_fmt.fmt.start[0] != tvnorm->vbistart[0] ||
+ fh->vbi_fmt.fmt.start[1] != tvnorm->vbistart[1] ||
+ fh->vbi_fmt.fmt.count[0] != fh->vbi_fmt.fmt.count[1]) {
+ /* BTTV_VBISIZE cannot express these parameters,
+ however open() resets the paramters to defaults
+ and apps shouldn't call BTTV_VBISIZE after
+ VIDIOC_S_FMT. */
+ return -EINVAL;
+ }
+
bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
- return fh->lines * 2 * 2048;
+ return (fh->vbi_fmt.fmt.count[0] * 2
+ * fh->vbi_fmt.fmt.samples_per_line);
+ }
+
default:
return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
}
@@ -2992,10 +3605,14 @@ static ssize_t bttv_read(struct file *file, char __user *data,
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (locked_btres(fh->btv,RESOURCE_VIDEO))
+ if (!check_alloc_btres(fh->btv, fh, RESOURCE_VIDEO_READ)) {
+ /* VIDEO_READ in use by another fh,
+ or VIDEO_STREAM by any fh. */
return -EBUSY;
+ }
retval = videobuf_read_one(&fh->cap, data, count, ppos,
file->f_flags & O_NONBLOCK);
+ free_btres(fh->btv, fh, RESOURCE_VIDEO_READ);
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
@@ -3021,7 +3638,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
return videobuf_poll_stream(file, &fh->vbi, wait);
}
- if (check_btres(fh,RESOURCE_VIDEO)) {
+ if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
/* streaming capture */
if (list_empty(&fh->cap.stream))
return POLLERR;
@@ -3031,7 +3648,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
mutex_lock(&fh->cap.lock);
if (NULL == fh->cap.read_buf) {
/* need to capture a new frame */
- if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
+ if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM)) {
mutex_unlock(&fh->cap.lock);
return POLLERR;
}
@@ -3117,8 +3734,23 @@ static int bttv_open(struct inode *inode, struct file *file)
i2c_vidiocschan(btv);
btv->users++;
- if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
- bttv_vbi_setlines(fh,btv,16);
+
+ /* The V4L2 spec requires one global set of cropping parameters
+ which only change on request. These are stored in btv->crop[1].
+ However for compatibility with V4L apps and cropping unaware
+ V4L2 apps we now reset the cropping parameters as seen through
+ this fh, which is to say VIDIOC_G_CROP and scaling limit checks
+ will use btv->crop[0], the default cropping parameters for the
+ current video standard, and VIDIOC_S_FMT will not implicitely
+ change the cropping parameters until VIDIOC_S_CROP has been
+ called. */
+ fh->do_crop = !reset_crop; /* module parameter */
+
+ /* Likewise there should be one global set of VBI capture
+ parameters, but for compatibility with V4L apps and earlier
+ driver versions each fh has its own parameters. */
+ bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
+
bttv_field_count(btv);
return 0;
}
@@ -3133,14 +3765,17 @@ static int bttv_release(struct inode *inode, struct file *file)
bttv_switch_overlay(btv,fh,NULL);
/* stop video capture */
- if (check_btres(fh, RESOURCE_VIDEO)) {
+ if (check_btres(fh, RESOURCE_VIDEO_STREAM)) {
videobuf_streamoff(&fh->cap);
- free_btres(btv,fh,RESOURCE_VIDEO);
+ free_btres(btv,fh,RESOURCE_VIDEO_STREAM);
}
if (fh->cap.read_buf) {
buffer_release(&fh->cap,fh->cap.read_buf);
kfree(fh->cap.read_buf);
}
+ if (check_btres(fh, RESOURCE_VIDEO_READ)) {
+ free_btres(btv, fh, RESOURCE_VIDEO_READ);
+ }
/* stop vbi capture */
if (check_btres(fh, RESOURCE_VBI)) {
@@ -3997,7 +4632,6 @@ static int __devinit bttv_probe(struct pci_dev *dev,
/* initialize structs / fill in defaults */
mutex_init(&btv->lock);
- mutex_init(&btv->reslock);
spin_lock_init(&btv->s_lock);
spin_lock_init(&btv->gpio_lock);
init_waitqueue_head(&btv->gpioq);
@@ -4095,7 +4729,6 @@ static int __devinit bttv_probe(struct pci_dev *dev,
btv->init.fmt = format_by_palette(VIDEO_PALETTE_RGB24);
btv->init.width = 320;
btv->init.height = 240;
- btv->init.lines = 16;
btv->input = 0;
/* initialize hardware */
@@ -4130,6 +4763,10 @@ static int __devinit bttv_probe(struct pci_dev *dev,
bt848_sat(btv,32768);
audio_mute(btv, 1);
set_input(btv,0);
+ bttv_crop_reset(&btv->crop[0], btv->tvnorm);
+ btv->crop[1] = btv->crop[0]; /* current = default */
+ disclaim_vbi_lines(btv);
+ disclaim_video_lines(btv);
}
/* add subdevices */
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index cbc012f71f5..6f74c8042bc 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -36,13 +36,18 @@ module_param(repeat_delay, int, 0644);
static int repeat_period = 33;
module_param(repeat_period, int, 0644);
+static int ir_rc5_remote_gap = 885;
+module_param(ir_rc5_remote_gap, int, 0644);
+static int ir_rc5_key_timeout = 200;
+module_param(ir_rc5_key_timeout, int, 0644);
+
#define DEVNAME "bttv-input"
/* ---------------------------------------------------------------------- */
static void ir_handle_key(struct bttv *btv)
{
- struct bttv_ir *ir = btv->remote;
+ struct card_ir *ir = btv->remote;
u32 gpio,data;
/* read gpio value */
@@ -72,7 +77,7 @@ static void ir_handle_key(struct bttv *btv)
void bttv_input_irq(struct bttv *btv)
{
- struct bttv_ir *ir = btv->remote;
+ struct card_ir *ir = btv->remote;
if (!ir->polling)
ir_handle_key(btv);
@@ -81,65 +86,21 @@ void bttv_input_irq(struct bttv *btv)
static void bttv_input_timer(unsigned long data)
{
struct bttv *btv = (struct bttv*)data;
- struct bttv_ir *ir = btv->remote;
- unsigned long timeout;
+ struct card_ir *ir = btv->remote;
ir_handle_key(btv);
- timeout = jiffies + (ir->polling * HZ / 1000);
- mod_timer(&ir->timer, timeout);
+ mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
}
/* ---------------------------------------------------------------*/
-static int rc5_remote_gap = 885;
-module_param(rc5_remote_gap, int, 0644);
-static int rc5_key_timeout = 200;
-module_param(rc5_key_timeout, int, 0644);
-
-#define RC5_START(x) (((x)>>12)&3)
-#define RC5_TOGGLE(x) (((x)>>11)&1)
-#define RC5_ADDR(x) (((x)>>6)&31)
-#define RC5_INSTR(x) ((x)&63)
-
-/* decode raw bit pattern to RC5 code */
-static u32 rc5_decode(unsigned int code)
-{
- unsigned int org_code = code;
- unsigned int pair;
- unsigned int rc5 = 0;
- int i;
-
- code = (code << 1) | 1;
- for (i = 0; i < 14; ++i) {
- pair = code & 0x3;
- code >>= 2;
-
- rc5 <<= 1;
- switch (pair) {
- case 0:
- case 2:
- break;
- case 1:
- rc5 |= 1;
- break;
- case 3:
- dprintk(KERN_WARNING "bad code: %x\n", org_code);
- return 0;
- }
- }
- dprintk(KERN_WARNING "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
- "instr=%x\n", rc5, org_code, RC5_START(rc5),
- RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
- return rc5;
-}
-
static int bttv_rc5_irq(struct bttv *btv)
{
- struct bttv_ir *ir = btv->remote;
+ struct card_ir *ir = btv->remote;
struct timeval tv;
u32 gpio;
u32 gap;
- unsigned long current_jiffies, timeout;
+ unsigned long current_jiffies;
/* read gpio port */
gpio = bttv_gpio_read(&btv->c);
@@ -165,8 +126,8 @@ static int bttv_rc5_irq(struct bttv *btv)
/* only if in the code (otherwise spurious IRQ or timer
late) */
if (ir->last_bit < 28) {
- ir->last_bit = (gap - rc5_remote_gap / 2) /
- rc5_remote_gap;
+ ir->last_bit = (gap - ir_rc5_remote_gap / 2) /
+ ir_rc5_remote_gap;
ir->code |= 1 << ir->last_bit;
}
/* starting new code */
@@ -176,8 +137,8 @@ static int bttv_rc5_irq(struct bttv *btv)
ir->base_time = tv;
ir->last_bit = 0;
- timeout = current_jiffies + (500 + 30 * HZ) / 1000;
- mod_timer(&ir->timer_end, timeout);
+ mod_timer(&ir->timer_end,
+ current_jiffies + msecs_to_jiffies(30));
}
/* toggle GPIO pin 4 to reset the irq */
@@ -186,96 +147,28 @@ static int bttv_rc5_irq(struct bttv *btv)
return 1;
}
-
-static void bttv_rc5_timer_end(unsigned long data)
-{
- struct bttv_ir *ir = (struct bttv_ir *)data;
- struct timeval tv;
- unsigned long current_jiffies, timeout;
- u32 gap;
-
- /* get time */
- current_jiffies = jiffies;
- do_gettimeofday(&tv);
-
- /* avoid overflow with gap >1s */
- if (tv.tv_sec - ir->base_time.tv_sec > 1) {
- gap = 200000;
- } else {
- gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
- tv.tv_usec - ir->base_time.tv_usec;
- }
-
- /* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */
- if (gap < 28000) {
- dprintk(KERN_WARNING "spurious timer_end\n");
- return;
- }
-
- ir->active = 0;
- if (ir->last_bit < 20) {
- /* ignore spurious codes (caused by light/other remotes) */
- dprintk(KERN_WARNING "short code: %x\n", ir->code);
- } else {
- u32 rc5 = rc5_decode(ir->code);
-
- /* two start bits? */
- if (RC5_START(rc5) != 3) {
- dprintk(KERN_WARNING "rc5 start bits invalid: %u\n", RC5_START(rc5));
-
- /* right address? */
- } else if (RC5_ADDR(rc5) == 0x0) {
- u32 toggle = RC5_TOGGLE(rc5);
- u32 instr = RC5_INSTR(rc5);
-
- /* Good code, decide if repeat/repress */
- if (toggle != RC5_TOGGLE(ir->last_rc5) ||
- instr != RC5_INSTR(ir->last_rc5)) {
- dprintk(KERN_WARNING "instruction %x, toggle %x\n", instr,
- toggle);
- ir_input_nokey(ir->dev, &ir->ir);
- ir_input_keydown(ir->dev, &ir->ir, instr,
- instr);
- }
-
- /* Set/reset key-up timer */
- timeout = current_jiffies + (500 + rc5_key_timeout
- * HZ) / 1000;
- mod_timer(&ir->timer_keyup, timeout);
-
- /* Save code for repeat test */
- ir->last_rc5 = rc5;
- }
- }
-}
-
-static void bttv_rc5_timer_keyup(unsigned long data)
-{
- struct bttv_ir *ir = (struct bttv_ir *)data;
-
- dprintk(KERN_DEBUG "key released\n");
- ir_input_nokey(ir->dev, &ir->ir);
-}
-
/* ---------------------------------------------------------------------- */
-static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir)
+static void bttv_ir_start(struct bttv *btv, struct card_ir *ir)
{
if (ir->polling) {
- init_timer(&ir->timer);
- ir->timer.function = bttv_input_timer;
- ir->timer.data = (unsigned long)btv;
+ setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv);
ir->timer.expires = jiffies + HZ;
add_timer(&ir->timer);
} else if (ir->rc5_gpio) {
/* set timer_end for code completion */
init_timer(&ir->timer_end);
- ir->timer_end.function = bttv_rc5_timer_end;
+ ir->timer_end.function = ir_rc5_timer_end;
ir->timer_end.data = (unsigned long)ir;
init_timer(&ir->timer_keyup);
- ir->timer_keyup.function = bttv_rc5_timer_keyup;
+ ir->timer_keyup.function = ir_rc5_timer_keyup;
ir->timer_keyup.data = (unsigned long)ir;
+ ir->shift_by = 1;
+ ir->start = 3;
+ ir->addr = 0x0;
+ ir->rc5_key_timeout = ir_rc5_key_timeout;
+ ir->rc5_remote_gap = ir_rc5_remote_gap;
}
}
@@ -299,7 +192,7 @@ static void bttv_ir_stop(struct bttv *btv)
int bttv_input_init(struct bttv *btv)
{
- struct bttv_ir *ir;
+ struct card_ir *ir;
IR_KEYTAB_TYPE *ir_codes = NULL;
struct input_dev *input_dev;
int ir_type = IR_TYPE_OTHER;
diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
index afcfe71e379..e7104d9cb4b 100644
--- a/drivers/media/video/bt8xx/bttv-risc.c
+++ b/drivers/media/video/bt8xx/bttv-risc.c
@@ -43,7 +43,8 @@ int
bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
struct scatterlist *sglist,
unsigned int offset, unsigned int bpl,
- unsigned int padding, unsigned int lines)
+ unsigned int padding, unsigned int skip_lines,
+ unsigned int store_lines)
{
u32 instructions,line,todo;
struct scatterlist *sg;
@@ -54,9 +55,11 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
one write per scan line + sync + jump (all 2 dwords). padding
can cause next bpl to start close to a page border. First DMA
region may be smaller than PAGE_SIZE */
- instructions = 1 + ((bpl + padding) * lines) / PAGE_SIZE + lines;
- instructions += 2;
- if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0)
+ instructions = skip_lines * 4;
+ instructions += (1 + ((bpl + padding) * store_lines)
+ / PAGE_SIZE + store_lines) * 8;
+ instructions += 2 * 8;
+ if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0)
return rc;
/* sync instruction */
@@ -64,11 +67,16 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
*(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
*(rp++) = cpu_to_le32(0);
+ while (skip_lines-- > 0) {
+ *(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL |
+ BT848_RISC_EOL | bpl);
+ }
+
/* scan lines */
sg = sglist;
- for (line = 0; line < lines; line++) {
+ for (line = 0; line < store_lines; line++) {
if ((btv->opt_vcr_hack) &&
- (line >= (lines - VCR_HACK_LINES)))
+ (line >= (store_lines - VCR_HACK_LINES)))
continue;
while (offset && offset >= sg_dma_len(sg)) {
offset -= sg_dma_len(sg);
@@ -130,7 +138,8 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
/* estimate risc mem: worst case is one write per page border +
one write per scan line (5 dwords)
plus sync + jump (2 dwords) */
- instructions = (ybpl * ylines * 2) / PAGE_SIZE + ylines;
+ instructions = ((3 + (ybpl + ypadding) * ylines * 2)
+ / PAGE_SIZE) + ylines;
instructions += 2;
if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
return rc;
@@ -317,10 +326,10 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
/* ---------------------------------------------------------- */
static void
-bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
- int width, int height, int interleaved, int norm)
+bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,
+ int width, int height, int interleaved,
+ const struct bttv_tvnorm *tvnorm)
{
- const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm];
u32 xsf, sr;
int vdelay;
@@ -361,6 +370,62 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
}
static void
+bttv_calc_geo (struct bttv * btv,
+ struct bttv_geometry * geo,
+ unsigned int width,
+ unsigned int height,
+ int both_fields,
+ const struct bttv_tvnorm * tvnorm,
+ const struct v4l2_rect * crop)
+{
+ unsigned int c_width;
+ unsigned int c_height;
+ u32 sr;
+
+ if ((crop->left == tvnorm->cropcap.defrect.left
+ && crop->top == tvnorm->cropcap.defrect.top
+ && crop->width == tvnorm->cropcap.defrect.width
+ && crop->height == tvnorm->cropcap.defrect.height
+ && width <= tvnorm->swidth /* see PAL-Nc et al */)
+ || bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
+ bttv_calc_geo_old(btv, geo, width, height,
+ both_fields, tvnorm);
+ return;
+ }
+
+ /* For bug compatibility the image size checks permit scale
+ factors > 16. See bttv_crop_calc_limits(). */
+ c_width = min((unsigned int) crop->width, width * 16);
+ c_height = min((unsigned int) crop->height, height * 16);
+
+ geo->width = width;
+ geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096;
+ /* Even to store Cb first, odd for Cr. */
+ geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1;
+
+ geo->sheight = c_height;
+ geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY;
+ sr = c_height >> !both_fields;
+ sr = (sr * 512U + (height >> 1)) / height - 512;
+ geo->vscale = (0x10000UL - sr) & 0x1fff;
+ geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0;
+ geo->vtotal = tvnorm->vtotal;
+
+ geo->crop = (((geo->width >> 8) & 0x03) |
+ ((geo->hdelay >> 6) & 0x0c) |
+ ((geo->sheight >> 4) & 0x30) |
+ ((geo->vdelay >> 2) & 0xc0));
+
+ if (btv->opt_combfilter) {
+ geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
+ geo->comb = (width < 769) ? 1 : 0;
+ } else {
+ geo->vtc = 0;
+ geo->comb = 0;
+ }
+}
+
+static void
bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
{
int off = odd ? 0x80 : 0x00;
@@ -522,16 +587,51 @@ int
bttv_buffer_activate_vbi(struct bttv *btv,
struct bttv_buffer *vbi)
{
- /* vbi capture */
+ struct btcx_riscmem *top;
+ struct btcx_riscmem *bottom;
+ int top_irq_flags;
+ int bottom_irq_flags;
+
+ top = NULL;
+ bottom = NULL;
+ top_irq_flags = 0;
+ bottom_irq_flags = 0;
+
if (vbi) {
+ unsigned int crop, vdelay;
+
vbi->vb.state = STATE_ACTIVE;
list_del(&vbi->vb.queue);
- bttv_risc_hook(btv, RISC_SLOT_O_VBI, &vbi->top, 0);
- bttv_risc_hook(btv, RISC_SLOT_E_VBI, &vbi->bottom, 4);
- } else {
- bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0);
- bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0);
+
+ /* VDELAY is start of video, end of VBI capturing. */
+ crop = btread(BT848_E_CROP);
+ vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2);
+
+ if (vbi->geo.vdelay > vdelay) {
+ vdelay = vbi->geo.vdelay & 0xfe;
+ crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0);
+
+ btwrite(vdelay, BT848_E_VDELAY_LO);
+ btwrite(crop, BT848_E_CROP);
+ btwrite(vdelay, BT848_O_VDELAY_LO);
+ btwrite(crop, BT848_O_CROP);
+ }
+
+ if (vbi->vbi_count[0] > 0) {
+ top = &vbi->top;
+ top_irq_flags = 4;
+ }
+
+ if (vbi->vbi_count[1] > 0) {
+ top_irq_flags = 0;
+ bottom = &vbi->bottom;
+ bottom_irq_flags = 4;
+ }
}
+
+ bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags);
+ bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags);
+
return 0;
}
@@ -611,28 +711,31 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
int bpf = bpl * (buf->vb.height >> 1);
bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
- V4L2_FIELD_HAS_BOTH(buf->vb.field),buf->tvnorm);
+ V4L2_FIELD_HAS_BOTH(buf->vb.field),
+ tvnorm,&buf->crop);
switch (buf->vb.field) {
case V4L2_FIELD_TOP:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
- 0,bpl,0,buf->vb.height);
+ /* offset */ 0,bpl,
+ /* padding */ 0,/* skip_lines */ 0,
+ buf->vb.height);
break;
case V4L2_FIELD_BOTTOM:
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
- 0,bpl,0,buf->vb.height);
+ 0,bpl,0,0,buf->vb.height);
break;
case V4L2_FIELD_INTERLACED:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
- 0,bpl,bpl,buf->vb.height >> 1);
+ 0,bpl,bpl,0,buf->vb.height >> 1);
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
- bpl,bpl,bpl,buf->vb.height >> 1);
+ bpl,bpl,bpl,0,buf->vb.height >> 1);
break;
case V4L2_FIELD_SEQ_TB:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
- 0,bpl,0,buf->vb.height >> 1);
+ 0,bpl,0,0,buf->vb.height >> 1);
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
- bpf,bpl,0,buf->vb.height >> 1);
+ bpf,bpl,0,0,buf->vb.height >> 1);
break;
default:
BUG();
@@ -662,7 +765,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
switch (buf->vb.field) {
case V4L2_FIELD_TOP:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
- buf->vb.height,0,buf->tvnorm);
+ buf->vb.height,/* both_fields */ 0,
+ tvnorm,&buf->crop);
bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist,
0,buf->vb.width,0,buf->vb.height,
uoffset,voffset,buf->fmt->hshift,
@@ -670,7 +774,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
break;
case V4L2_FIELD_BOTTOM:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
- buf->vb.height,0,buf->tvnorm);
+ buf->vb.height,0,
+ tvnorm,&buf->crop);
bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist,
0,buf->vb.width,0,buf->vb.height,
uoffset,voffset,buf->fmt->hshift,
@@ -678,7 +783,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
break;
case V4L2_FIELD_INTERLACED:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
- buf->vb.height,1,buf->tvnorm);
+ buf->vb.height,1,
+ tvnorm,&buf->crop);
lines = buf->vb.height >> 1;
ypadding = buf->vb.width;
cpadding = buf->vb.width >> buf->fmt->hshift;
@@ -700,7 +806,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
break;
case V4L2_FIELD_SEQ_TB:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
- buf->vb.height,1,buf->tvnorm);
+ buf->vb.height,1,
+ tvnorm,&buf->crop);
lines = buf->vb.height >> 1;
ypadding = buf->vb.width;
cpadding = buf->vb.width >> buf->fmt->hshift;
@@ -731,11 +838,12 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
/* build risc code */
buf->vb.field = V4L2_FIELD_SEQ_TB;
bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
- 1,buf->tvnorm);
+ 1,tvnorm,&buf->crop);
bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
- 0, RAW_BPL, 0, RAW_LINES);
+ /* offset */ 0, RAW_BPL, /* padding */ 0,
+ /* skip_lines */ 0, RAW_LINES);
bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
- buf->vb.size/2 , RAW_BPL, 0, RAW_LINES);
+ buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
}
/* copy format info */
@@ -761,7 +869,8 @@ bttv_overlay_risc(struct bttv *btv,
/* calculate geometry */
bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
- V4L2_FIELD_HAS_BOTH(ov->field), ov->tvnorm);
+ V4L2_FIELD_HAS_BOTH(ov->field),
+ &bttv_tvnorms[ov->tvnorm],&buf->crop);
/* build risc code */
switch (ov->field) {
diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c
index 6fc6b026005..93e35de5a18 100644
--- a/drivers/media/video/bt8xx/bttv-vbi.c
+++ b/drivers/media/video/bt8xx/bttv-vbi.c
@@ -5,6 +5,9 @@
(c) 2002 Gerd Knorr <kraxel@bytesex.org>
+ Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
+ Sponsored by OPQ Systems AB
+
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
@@ -41,8 +44,15 @@
to be about 244. */
#define VBI_OFFSET 244
+/* 2048 for compatibility with earlier driver versions. The driver
+ really stores 1024 + tvnorm->vbipack * 4 samples per line in the
+ buffer. Note tvnorm->vbipack is <= 0xFF (limit of VBIPACK_LO + HI
+ is 0x1FF DWORDs) and VBI read()s store a frame counter in the last
+ four bytes of the VBI image. */
+#define VBI_BPL 2048
+
+/* Compatibility. */
#define VBI_DEFLINES 16
-#define VBI_MAXLINES 32
static unsigned int vbibufs = 4;
static unsigned int vbi_debug = 0;
@@ -58,21 +68,12 @@ MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)");
#define dprintk(fmt, arg...) if (vbi_debug) \
printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->c.nr , ## arg)
+#define IMAGE_SIZE(fmt) \
+ (((fmt)->count[0] + (fmt)->count[1]) * (fmt)->samples_per_line)
+
/* ----------------------------------------------------------------------- */
/* vbi risc code + mm */
-static int
-vbi_buffer_risc(struct bttv *btv, struct bttv_buffer *buf, int lines)
-{
- int bpl = 2048;
-
- bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
- 0, bpl-4, 4, lines);
- bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
- lines * bpl, bpl-4, 4, lines);
- return 0;
-}
-
static int vbi_buffer_setup(struct videobuf_queue *q,
unsigned int *count, unsigned int *size)
{
@@ -81,8 +82,16 @@ static int vbi_buffer_setup(struct videobuf_queue *q,
if (0 == *count)
*count = vbibufs;
- *size = fh->lines * 2 * 2048;
- dprintk("setup: lines=%d\n",fh->lines);
+
+ *size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
+
+ dprintk("setup: samples=%u start=%d,%d count=%u,%u\n",
+ fh->vbi_fmt.fmt.samples_per_line,
+ fh->vbi_fmt.fmt.start[0],
+ fh->vbi_fmt.fmt.start[1],
+ fh->vbi_fmt.fmt.count[0],
+ fh->vbi_fmt.fmt.count[1]);
+
return 0;
}
@@ -93,18 +102,93 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
struct bttv_fh *fh = q->priv_data;
struct bttv *btv = fh->btv;
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
+ const struct bttv_tvnorm *tvnorm;
+ unsigned int skip_lines0, skip_lines1, min_vdelay;
+ int redo_dma_risc;
int rc;
- buf->vb.size = fh->lines * 2 * 2048;
+ buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
+ tvnorm = fh->vbi_fmt.tvnorm;
+
+ /* There's no VBI_VDELAY register, RISC must skip the lines
+ we don't want. With default parameters we skip zero lines
+ as earlier driver versions did. The driver permits video
+ standard changes while capturing, so we use vbi_fmt.tvnorm
+ instead of btv->tvnorm to skip zero lines after video
+ standard changes as well. */
+
+ skip_lines0 = 0;
+ skip_lines1 = 0;
+
+ if (fh->vbi_fmt.fmt.count[0] > 0)
+ skip_lines0 = max(0, (fh->vbi_fmt.fmt.start[0]
+ - tvnorm->vbistart[0]));
+ if (fh->vbi_fmt.fmt.count[1] > 0)
+ skip_lines1 = max(0, (fh->vbi_fmt.fmt.start[1]
+ - tvnorm->vbistart[1]));
+
+ redo_dma_risc = 0;
+
+ if (buf->vbi_skip[0] != skip_lines0 ||
+ buf->vbi_skip[1] != skip_lines1 ||
+ buf->vbi_count[0] != fh->vbi_fmt.fmt.count[0] ||
+ buf->vbi_count[1] != fh->vbi_fmt.fmt.count[1]) {
+ buf->vbi_skip[0] = skip_lines0;
+ buf->vbi_skip[1] = skip_lines1;
+ buf->vbi_count[0] = fh->vbi_fmt.fmt.count[0];
+ buf->vbi_count[1] = fh->vbi_fmt.fmt.count[1];
+ redo_dma_risc = 1;
+ }
+
if (STATE_NEEDS_INIT == buf->vb.state) {
+ redo_dma_risc = 1;
if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
goto fail;
- if (0 != (rc = vbi_buffer_risc(btv,buf,fh->lines)))
- goto fail;
}
+
+ if (redo_dma_risc) {
+ unsigned int bpl, padding, offset;
+
+ bpl = 2044; /* max. vbipack */
+ padding = VBI_BPL - bpl;
+
+ if (fh->vbi_fmt.fmt.count[0] > 0) {
+ rc = bttv_risc_packed(btv, &buf->top,
+ buf->vb.dma.sglist,
+ /* offset */ 0, bpl,
+ padding, skip_lines0,
+ fh->vbi_fmt.fmt.count[0]);
+ if (0 != rc)
+ goto fail;
+ }
+
+ if (fh->vbi_fmt.fmt.count[1] > 0) {
+ offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL;
+
+ rc = bttv_risc_packed(btv, &buf->bottom,
+ buf->vb.dma.sglist,
+ offset, bpl,
+ padding, skip_lines1,
+ fh->vbi_fmt.fmt.count[1]);
+ if (0 != rc)
+ goto fail;
+ }
+ }
+
+ /* VBI capturing ends at VDELAY, start of video capturing,
+ no matter where the RISC program ends. VDELAY minimum is 2,
+ bounds.top is the corresponding first field line number
+ times two. VDELAY counts half field lines. */
+ min_vdelay = MIN_VDELAY;
+ if (fh->vbi_fmt.end >= tvnorm->cropcap.bounds.top)
+ min_vdelay += fh->vbi_fmt.end - tvnorm->cropcap.bounds.top;
+
+ /* For bttv_buffer_activate_vbi(). */
+ buf->geo.vdelay = min_vdelay;
+
buf->vb.state = STATE_PREPARED;
buf->vb.field = field;
dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
@@ -140,7 +224,7 @@ static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
dprintk("free %p\n",vb);
- bttv_dma_free(&fh->cap,fh->btv,buf);
+ bttv_dma_free(q,fh->btv,buf);
}
struct videobuf_queue_ops bttv_vbi_qops = {
@@ -152,69 +236,215 @@ struct videobuf_queue_ops bttv_vbi_qops = {
/* ----------------------------------------------------------------------- */
-void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines)
+static int
+try_fmt (struct v4l2_vbi_format * f,
+ const struct bttv_tvnorm * tvnorm,
+ __s32 crop_start)
{
- int vdelay;
-
- if (lines < 1)
- lines = 1;
- if (lines > VBI_MAXLINES)
- lines = VBI_MAXLINES;
- fh->lines = lines;
-
- vdelay = btread(BT848_E_VDELAY_LO);
- if (vdelay < lines*2) {
- vdelay = lines*2;
- btwrite(vdelay,BT848_E_VDELAY_LO);
- btwrite(vdelay,BT848_O_VDELAY_LO);
+ __s32 min_start, max_start, max_end, f2_offset;
+ unsigned int i;
+
+ /* For compatibility with earlier driver versions we must pretend
+ the VBI and video capture window may overlap. In reality RISC
+ magic aborts VBI capturing at the first line of video capturing,
+ leaving the rest of the buffer unchanged, usually all zero.
+ VBI capturing must always start before video capturing. >> 1
+ because cropping counts field lines times two. */
+ min_start = tvnorm->vbistart[0];
+ max_start = (crop_start >> 1) - 1;
+ max_end = (tvnorm->cropcap.bounds.top
+ + tvnorm->cropcap.bounds.height) >> 1;
+
+ if (min_start > max_start)
+ return -EBUSY;
+
+ BUG_ON(max_start >= max_end);
+
+ f->sampling_rate = tvnorm->Fsc;
+ f->samples_per_line = VBI_BPL;
+ f->sample_format = V4L2_PIX_FMT_GREY;
+ f->offset = VBI_OFFSET;
+
+ f2_offset = tvnorm->vbistart[1] - tvnorm->vbistart[0];
+
+ for (i = 0; i < 2; ++i) {
+ if (0 == f->count[i]) {
+ /* No data from this field. We leave f->start[i]
+ alone because VIDIOCSVBIFMT is w/o and EINVALs
+ when a driver does not support exactly the
+ requested parameters. */
+ } else {
+ s64 start, count;
+
+ start = clamp(f->start[i], min_start, max_start);
+ /* s64 to prevent overflow. */
+ count = (s64) f->start[i] + f->count[i] - start;
+ f->start[i] = start;
+ f->count[i] = clamp(count, (s64) 1,
+ max_end - start);
+ }
+
+ min_start += f2_offset;
+ max_start += f2_offset;
+ max_end += f2_offset;
}
+
+ if (0 == (f->count[0] | f->count[1])) {
+ /* As in earlier driver versions. */
+ f->start[0] = tvnorm->vbistart[0];
+ f->start[1] = tvnorm->vbistart[1];
+ f->count[0] = 1;
+ f->count[1] = 1;
+ }
+
+ f->flags = 0;
+
+ f->reserved[0] = 0;
+ f->reserved[1] = 0;
+
+ return 0;
}
-void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f)
+int
+bttv_vbi_try_fmt (struct bttv_fh * fh,
+ struct v4l2_vbi_format * f)
{
+ struct bttv *btv = fh->btv;
const struct bttv_tvnorm *tvnorm;
- s64 count0,count1,count;
+ __s32 crop_start;
- tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
- f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
- f->fmt.vbi.sampling_rate = tvnorm->Fsc;
- f->fmt.vbi.samples_per_line = 2048;
- f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- f->fmt.vbi.offset = VBI_OFFSET;
- f->fmt.vbi.flags = 0;
-
- /* s64 to prevent overflow. */
- count0 = (s64) f->fmt.vbi.start[0] + f->fmt.vbi.count[0]
- - tvnorm->vbistart[0];
- count1 = (s64) f->fmt.vbi.start[1] + f->fmt.vbi.count[1]
- - tvnorm->vbistart[1];
- count = clamp (max (count0, count1), (s64) 1, (s64) VBI_MAXLINES);
-
- f->fmt.vbi.start[0] = tvnorm->vbistart[0];
- f->fmt.vbi.start[1] = tvnorm->vbistart[1];
- f->fmt.vbi.count[0] = count;
- f->fmt.vbi.count[1] = count;
-
- f->fmt.vbi.reserved[0] = 0;
- f->fmt.vbi.reserved[1] = 0;
+ mutex_lock(&btv->lock);
+
+ tvnorm = &bttv_tvnorms[btv->tvnorm];
+ crop_start = btv->crop_start;
+
+ mutex_unlock(&btv->lock);
+
+ return try_fmt(f, tvnorm, crop_start);
}
-void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
+int
+bttv_vbi_set_fmt (struct bttv_fh * fh,
+ struct v4l2_vbi_format * f)
{
+ struct bttv *btv = fh->btv;
const struct bttv_tvnorm *tvnorm;
+ __s32 start1, end;
+ int rc;
+
+ mutex_lock(&btv->lock);
+
+ rc = -EBUSY;
+ if (fh->resources & RESOURCE_VBI)
+ goto fail;
+
+ tvnorm = &bttv_tvnorms[btv->tvnorm];
+
+ rc = try_fmt(f, tvnorm, btv->crop_start);
+ if (0 != rc)
+ goto fail;
+
+ start1 = f->start[1] - tvnorm->vbistart[1] + tvnorm->vbistart[0];
+
+ /* First possible line of video capturing. Should be
+ max(f->start[0] + f->count[0], start1 + f->count[1]) * 2
+ when capturing both fields. But for compatibility we must
+ pretend the VBI and video capture window may overlap,
+ so end = start + 1, the lowest possible value, times two
+ because vbi_fmt.end counts field lines times two. */
+ end = max(f->start[0], start1) * 2 + 2;
+
+ mutex_lock(&fh->vbi.lock);
+
+ fh->vbi_fmt.fmt = *f;
+ fh->vbi_fmt.tvnorm = tvnorm;
+ fh->vbi_fmt.end = end;
+
+ mutex_unlock(&fh->vbi.lock);
+
+ rc = 0;
+
+ fail:
+ mutex_unlock(&btv->lock);
+
+ return rc;
+}
+
+void
+bttv_vbi_get_fmt (struct bttv_fh * fh,
+ struct v4l2_vbi_format * f)
+{
+ const struct bttv_tvnorm *tvnorm;
+
+ *f = fh->vbi_fmt.fmt;
tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
- memset(f,0,sizeof(*f));
- f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
- f->fmt.vbi.sampling_rate = tvnorm->Fsc;
- f->fmt.vbi.samples_per_line = 2048;
- f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- f->fmt.vbi.offset = VBI_OFFSET;
- f->fmt.vbi.start[0] = tvnorm->vbistart[0];
- f->fmt.vbi.start[1] = tvnorm->vbistart[1];
- f->fmt.vbi.count[0] = fh->lines;
- f->fmt.vbi.count[1] = fh->lines;
- f->fmt.vbi.flags = 0;
+
+ if (tvnorm != fh->vbi_fmt.tvnorm) {
+ __s32 max_end;
+ unsigned int i;
+
+ /* As in vbi_buffer_prepare() this imitates the
+ behaviour of earlier driver versions after video
+ standard changes, with default parameters anyway. */
+
+ max_end = (tvnorm->cropcap.bounds.top
+ + tvnorm->cropcap.bounds.height) >> 1;
+
+ f->sampling_rate = tvnorm->Fsc;
+
+ for (i = 0; i < 2; ++i) {
+ __s32 new_start;
+
+ new_start = f->start[i]
+ + tvnorm->vbistart[i]
+ - fh->vbi_fmt.tvnorm->vbistart[i];
+
+ f->start[i] = min(new_start, max_end - 1);
+ f->count[i] = min((__s32) f->count[i],
+ max_end - f->start[i]);
+
+ max_end += tvnorm->vbistart[1]
+ - tvnorm->vbistart[0];
+ }
+ }
+}
+
+void
+bttv_vbi_fmt_reset (struct bttv_vbi_fmt * f,
+ int norm)
+{
+ const struct bttv_tvnorm *tvnorm;
+ unsigned int real_samples_per_line;
+ unsigned int real_count;
+
+ tvnorm = &bttv_tvnorms[norm];
+
+ f->fmt.sampling_rate = tvnorm->Fsc;
+ f->fmt.samples_per_line = VBI_BPL;
+ f->fmt.sample_format = V4L2_PIX_FMT_GREY;
+ f->fmt.offset = VBI_OFFSET;
+ f->fmt.start[0] = tvnorm->vbistart[0];
+ f->fmt.start[1] = tvnorm->vbistart[1];
+ f->fmt.count[0] = VBI_DEFLINES;
+ f->fmt.count[1] = VBI_DEFLINES;
+ f->fmt.flags = 0;
+ f->fmt.reserved[0] = 0;
+ f->fmt.reserved[1] = 0;
+
+ /* For compatibility the buffer size must be 2 * VBI_DEFLINES *
+ VBI_BPL regardless of the current video standard. */
+ real_samples_per_line = 1024 + tvnorm->vbipack * 4;
+ real_count = ((tvnorm->cropcap.defrect.top >> 1)
+ - tvnorm->vbistart[0]);
+
+ BUG_ON(real_samples_per_line > VBI_BPL);
+ BUG_ON(real_count > VBI_DEFLINES);
+
+ f->tvnorm = tvnorm;
+
+ /* See bttv_vbi_fmt_set(). */
+ f->end = tvnorm->vbistart[0] * 2 + 2;
}
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index f9c9e3c4d11..5491acbdaf6 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -197,33 +197,6 @@ struct bttv_core {
struct bttv;
-struct bttv_ir {
- struct input_dev *dev;
- struct ir_input_state ir;
- char name[32];
- char phys[32];
-
- /* Usual gpio signalling */
-
- u32 mask_keycode;
- u32 mask_keydown;
- u32 mask_keyup;
- u32 polling;
- u32 last_gpio;
- struct work_struct work;
- struct timer_list timer;
-
- /* RC5 gpio */
- u32 rc5_gpio;
- struct timer_list timer_end; /* timer_end for code completion */
- struct timer_list timer_keyup; /* timer_end for key release */
- u32 last_rc5; /* last good rc5 code */
- u32 last_bit; /* last raw bit seen */
- u32 code; /* raw code under construction */
- struct timeval base_time; /* time of last seen code */
- int active; /* building raw code */
-};
-
struct tvcard
{
char *name;
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index 311c4c541e0..ad79b8d5343 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -26,7 +26,7 @@
#define _BTTVP_H_
#include <linux/version.h>
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,16)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,17)
#include <linux/types.h>
#include <linux/wait.h>
@@ -66,14 +66,22 @@
#define RISC_SLOT_LOOP 14
#define RESOURCE_OVERLAY 1
-#define RESOURCE_VIDEO 2
+#define RESOURCE_VIDEO_STREAM 2
#define RESOURCE_VBI 4
+#define RESOURCE_VIDEO_READ 8
#define RAW_LINES 640
#define RAW_BPL 1024
#define UNSET (-1U)
+/* Min. value in VDELAY register. */
+#define MIN_VDELAY 2
+/* Even to get Cb first, odd for Cr. */
+#define MAX_HDELAY (0x3FF & -2)
+/* Limits scaled width, which must be a multiple of 4. */
+#define MAX_HACTIVE (0x3FF & -4)
+
#define clamp(x, low, high) min (max (low, x), high)
/* ---------------------------------------------------------- */
@@ -92,8 +100,13 @@ struct bttv_tvnorm {
u16 vtotal;
int sram;
/* ITU-R frame line number of the first VBI line we can
- capture, of the first and second field. */
+ capture, of the first and second field. The last possible line
+ is determined by cropcap.bounds. */
u16 vbistart[2];
+ /* Horizontally this counts fCLKx1 samples following the leading
+ edge of the horizontal sync pulse, vertically ITU-R frame line
+ numbers of the first field times two (2, 4, 6, ... 524 or 624). */
+ struct v4l2_cropcap cropcap;
};
extern const struct bttv_tvnorm bttv_tvnorms[];
@@ -128,6 +141,9 @@ struct bttv_buffer {
struct bttv_geometry geo;
struct btcx_riscmem top;
struct btcx_riscmem bottom;
+ struct v4l2_rect crop;
+ unsigned int vbi_skip[2];
+ unsigned int vbi_count[2];
};
struct bttv_buffer_set {
@@ -146,6 +162,34 @@ struct bttv_overlay {
int setup_ok;
};
+struct bttv_vbi_fmt {
+ struct v4l2_vbi_format fmt;
+
+ /* fmt.start[] and count[] refer to this video standard. */
+ const struct bttv_tvnorm *tvnorm;
+
+ /* Earliest possible start of video capturing with this
+ v4l2_vbi_format, in struct bttv_crop.rect units. */
+ __s32 end;
+};
+
+/* bttv-vbi.c */
+void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm);
+
+struct bttv_crop {
+ /* A cropping rectangle in struct bttv_tvnorm.cropcap units. */
+ struct v4l2_rect rect;
+
+ /* Scaled image size limits with this crop rect. Divide
+ max_height, but not min_height, by two when capturing
+ single fields. See also bttv_crop_reset() and
+ bttv_crop_adjust() in bttv-driver.c. */
+ __s32 min_scaled_width;
+ __s32 min_scaled_height;
+ __s32 max_scaled_width;
+ __s32 max_scaled_height;
+};
+
struct bttv_fh {
struct bttv *btv;
int resources;
@@ -160,13 +204,19 @@ struct bttv_fh {
int width;
int height;
- /* current settings */
+ /* video overlay */
const struct bttv_format *ovfmt;
struct bttv_overlay ov;
- /* video overlay */
+ /* Application called VIDIOC_S_CROP. */
+ int do_crop;
+
+ /* vbi capture */
struct videobuf_queue vbi;
- int lines;
+ /* Current VBI capture window as seen through this fh (cannot
+ be global for compatibility with earlier drivers). Protected
+ by struct bttv.lock and struct bttv_fh.vbi.lock. */
+ struct bttv_vbi_fmt vbi_fmt;
};
/* ---------------------------------------------------------- */
@@ -176,7 +226,8 @@ struct bttv_fh {
int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
struct scatterlist *sglist,
unsigned int offset, unsigned int bpl,
- unsigned int pitch, unsigned int lines);
+ unsigned int pitch, unsigned int skip_lines,
+ unsigned int store_lines);
/* control dma register + risc main loop */
void bttv_set_dma(struct bttv *btv, int override);
@@ -202,9 +253,9 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
/* ---------------------------------------------------------- */
/* bttv-vbi.c */
-void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f);
-void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f);
-void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines);
+int bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
+void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
+int bttv_vbi_set_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
extern struct videobuf_queue_ops bttv_vbi_qops;
@@ -233,7 +284,6 @@ extern int fini_bttv_i2c(struct bttv *btv);
#define d2printk if (bttv_debug >= 2) printk
#define BTTV_MAX_FBUF 0x208000
-#define VBIBUF_SIZE (2048*VBI_MAXLINES*2)
#define BTTV_TIMEOUT (HZ/2) /* 0.5 seconds */
#define BTTV_FREE_IDLE (HZ) /* one second */
@@ -308,13 +358,12 @@ struct bttv {
/* infrared remote */
int has_remote;
- struct bttv_ir *remote;
+ struct card_ir *remote;
/* locking */
spinlock_t s_lock;
struct mutex lock;
int resources;
- struct mutex reslock;
#ifdef VIDIOC_G_PRIORITY
struct v4l2_prio_state prio;
#endif
@@ -384,6 +433,21 @@ struct bttv {
unsigned int users;
struct bttv_fh init;
+
+ /* Default (0) and current (1) video capturing and overlay
+ cropping parameters in bttv_tvnorm.cropcap units. Protected
+ by bttv.lock. */
+ struct bttv_crop crop[2];
+
+ /* Earliest possible start of video capturing in
+ bttv_tvnorm.cropcap line units. Set by check_alloc_btres()
+ and free_btres(). Protected by bttv.lock. */
+ __s32 vbi_end;
+
+ /* Latest possible end of VBI capturing (= crop[x].rect.top when
+ VIDEO_RESOURCES are locked). Set by check_alloc_btres()
+ and free_btres(). Protected by bttv.lock. */
+ __s32 crop_start;
};
/* our devices */
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index 4dae8925667..710c11a6829 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -1022,7 +1022,7 @@ static ssize_t cafe_v4l_read(struct file *filp,
char __user *buffer, size_t len, loff_t *pos)
{
struct cafe_camera *cam = filp->private_data;
- int ret;
+ int ret = 0;
/*
* Perhaps we're in speculative read mode and already
@@ -1195,7 +1195,7 @@ static int cafe_vidioc_reqbufs(struct file *filp, void *priv,
struct v4l2_requestbuffers *req)
{
struct cafe_camera *cam = filp->private_data;
- int ret;
+ int ret = 0; /* Silence warning */
/*
* Make sure it's something we can do. User pointers could be
@@ -1251,8 +1251,6 @@ static int cafe_vidioc_reqbufs(struct file *filp, void *priv,
if (cam->n_sbufs == 0) /* no luck at all - ret already set */
kfree(cam->sb_bufs);
- else
- ret = 0;
req->count = cam->n_sbufs; /* In case of partial success */
out:
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index 7e8d5ef58b6..78c9699eafb 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -1350,13 +1350,13 @@ out:
static void create_proc_cpia_cam(struct cam_data *cam)
{
- char name[7];
+ char name[5 + 1 + 10 + 1];
struct proc_dir_entry *ent;
if (!cpia_proc_root || !cam)
return;
- sprintf(name, "video%d", cam->vdev.minor);
+ snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
if (!ent)
@@ -1376,12 +1376,12 @@ static void create_proc_cpia_cam(struct cam_data *cam)
static void destroy_proc_cpia_cam(struct cam_data *cam)
{
- char name[7];
+ char name[5 + 1 + 10 + 1];
if (!cam || !cam->proc_entry)
return;
- sprintf(name, "video%d", cam->vdev.minor);
+ snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
remove_proc_entry(name, cpia_proc_root);
cam->proc_entry = NULL;
}
@@ -3153,8 +3153,7 @@ static int reset_camera(struct cam_data *cam)
static void put_cam(struct cpia_camera_ops* ops)
{
- if (ops->owner)
- module_put(ops->owner);
+ module_put(ops->owner);
}
/* ------------------------- V4L interface --------------------- */
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
index 2f5ca71e026..d60cd5ecf82 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/video/cx2341x.c
@@ -56,7 +56,6 @@ const u32 cx2341x_mpeg_ctrls[] = {
V4L2_CID_MPEG_VIDEO_B_FRAMES,
V4L2_CID_MPEG_VIDEO_GOP_SIZE,
V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
- V4L2_CID_MPEG_VIDEO_PULLDOWN,
V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
V4L2_CID_MPEG_VIDEO_BITRATE,
V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
@@ -118,9 +117,6 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
ctrl->value = params->video_gop_closure;
break;
- case V4L2_CID_MPEG_VIDEO_PULLDOWN:
- ctrl->value = params->video_pulldown;
- break;
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
ctrl->value = params->video_bitrate_mode;
break;
@@ -231,9 +227,6 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
params->video_gop_closure = ctrl->value;
break;
- case V4L2_CID_MPEG_VIDEO_PULLDOWN:
- params->video_pulldown = ctrl->value;
- break;
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
/* MPEG-1 only allows CBR */
if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
@@ -679,7 +672,6 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
.video_b_frames = 2,
.video_gop_size = 12,
.video_gop_closure = 1,
- .video_pulldown = 0,
.video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
.video_bitrate = 6000000,
.video_bitrate_peak = 8000000,
@@ -783,10 +775,6 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
if (err) return err;
}
- if (old == NULL || old->video_pulldown != new->video_pulldown) {
- err = cx2341x_api(priv, func, CX2341X_ENC_SET_3_2_PULLDOWN, 1, new->video_pulldown);
- if (err) return err;
- }
if (old == NULL || old->audio_properties != new->audio_properties) {
err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
if (err) return err;
@@ -888,11 +876,10 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
printk(", Peak %d", p->video_bitrate_peak);
}
printk("\n");
- printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n",
+ printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n",
prefix,
p->video_gop_size, p->video_b_frames,
- p->video_gop_closure ? "" : "No ",
- p->video_pulldown ? "" : "No ");
+ p->video_gop_closure ? "" : "No ");
if (p->video_temporal_decimation) {
printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
prefix, p->video_temporal_decimation);
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 7bb7589a07c..774d2536555 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -628,25 +628,19 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
#ifdef CONFIG_VIDEO_ADV_DEBUG
/* ioctls to allow direct access to the
* cx25840 registers for testing */
- case VIDIOC_INT_G_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
{
struct v4l2_register *reg = arg;
- if (reg->i2c_id != I2C_DRIVERID_CX25840)
- return -EINVAL;
- reg->val = cx25840_read(client, reg->reg & 0x0fff);
- break;
- }
-
- case VIDIOC_INT_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
-
- if (reg->i2c_id != I2C_DRIVERID_CX25840)
+ if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ reg->val = cx25840_read(client, reg->reg & 0x0fff);
+ else
+ cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
break;
}
#endif
@@ -893,9 +887,11 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
return 0;
}
+ /* Note: revision '(device_id & 0x0f) == 2' was never built. The
+ marking skips from 0x1 == 22 to 0x3 == 23. */
v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
(device_id & 0xfff0) >> 4,
- (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3,
+ (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f),
address << 1, adapter->name);
i2c_set_clientdata(client, state);
@@ -907,13 +903,13 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
state->vbi_line_offset = 8;
state->id = id;
+ i2c_attach_client(client);
+
if (state->is_cx25836)
cx25836_initialize(client);
else
cx25840_initialize(client, 1);
- i2c_attach_client(client);
-
return 0;
}
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c
index 1958d4016ea..0e86b9d033a 100644
--- a/drivers/media/video/cx25840/cx25840-firmware.c
+++ b/drivers/media/video/cx25840/cx25840-firmware.c
@@ -37,7 +37,7 @@
*/
#define FWSEND 48
-#define FWDEV(x) &((x)->adapter->dev)
+#define FWDEV(x) &((x)->dev)
static char *firmware = FWFILE;
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
index 639c3b659d0..532cee35eb3 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -12,8 +12,3 @@ obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o
EXTRA_CFLAGS += -Idrivers/media/video
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
-
-extra-cflags-$(CONFIG_VIDEO_BUF_DVB) += -DHAVE_VIDEO_BUF_DVB=1
-extra-cflags-$(CONFIG_VIDEO_CX88_VP3054)+= -DHAVE_VP3054_I2C=1
-
-EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index 9a7a2996f20..b0466b88f52 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -6,6 +6,9 @@
* (c) 2004 Jelle Foks <jelle@foks.8m.com>
* (c) 2004 Gerd Knorr <kraxel@bytesex.org>
*
+ * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ * - video_ioctl2 conversion
+ *
* Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
*
* This program is free software; you can redistribute it and/or modify
@@ -53,7 +56,8 @@ MODULE_PARM_DESC(debug,"enable debug messages [blackbird]");
/* ------------------------------------------------------------------ */
-#define BLACKBIRD_FIRM_IMAGE_SIZE 256*1024
+#define OLD_BLACKBIRD_FIRM_IMAGE_SIZE 262144
+#define BLACKBIRD_FIRM_IMAGE_SIZE 376836
/* defines below are from ivtv-driver.h */
@@ -401,7 +405,7 @@ static int blackbird_find_mailbox(struct cx8802_dev *dev)
u32 value;
int i;
- for (i = 0; i < BLACKBIRD_FIRM_IMAGE_SIZE; i++) {
+ for (i = 0; i < dev->fw_size; i++) {
memory_read(dev->core, i, &value);
if (value == signature[signaturecnt])
signaturecnt++;
@@ -449,12 +453,15 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
return -1;
}
- if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) {
- dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d)\n",
- firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE);
+ if ((firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) &&
+ (firmware->size != OLD_BLACKBIRD_FIRM_IMAGE_SIZE)) {
+ dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d or %d)\n",
+ firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE,
+ OLD_BLACKBIRD_FIRM_IMAGE_SIZE);
release_firmware(firmware);
return -1;
}
+ dev->fw_size = firmware->size;
if (0 != memcmp(firmware->data, magic, 8)) {
dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\n");
@@ -520,7 +527,7 @@ static void blackbird_codec_settings(struct cx8802_dev *dev)
dev->params.width = dev->width;
dev->params.height = dev->height;
- dev->params.is_50hz = (dev->core->tvnorm->id & V4L2_STD_625_50) != 0;
+ dev->params.is_50hz = (dev->core->tvnorm & V4L2_STD_625_50) != 0;
cx2341x_update(dev, blackbird_mbox_func, NULL, &dev->params);
}
@@ -710,8 +717,13 @@ static int blackbird_queryctrl(struct cx8802_dev *dev, struct v4l2_queryctrl *qc
return 0;
}
-static int blackbird_querymenu(struct cx8802_dev *dev, struct v4l2_querymenu *qmenu)
+/* ------------------------------------------------------------------ */
+/* IOCTL Handlers */
+
+static int vidioc_querymenu (struct file *file, void *priv,
+ struct v4l2_querymenu *qmenu)
{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
struct v4l2_queryctrl qctrl;
qctrl.id = qmenu->id;
@@ -719,221 +731,347 @@ static int blackbird_querymenu(struct cx8802_dev *dev, struct v4l2_querymenu *qm
return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
}
-/* ------------------------------------------------------------------ */
+static int vidioc_querycap (struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
+ struct cx88_core *core = dev->core;
-static int mpeg_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+ strcpy(cap->driver, "cx88_blackbird");
+ strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card));
+ sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
+ cap->version = CX88_VERSION_CODE;
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+ if (UNSET != core->tuner_type)
+ cap->capabilities |= V4L2_CAP_TUNER;
+ return 0;
+}
+
+static int vidioc_enum_fmt_cap (struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
{
- struct cx8802_fh *fh = file->private_data;
- struct cx8802_dev *dev = fh->dev;
+ if (f->index != 0)
+ return -EINVAL;
+
+ strlcpy(f->description, "MPEG", sizeof(f->description));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->pixelformat = V4L2_PIX_FMT_MPEG;
+ return 0;
+}
+
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx8802_fh *fh = priv;
+ struct cx8802_dev *dev = fh->dev;
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.width = dev->width;
+ f->fmt.pix.height = dev->height;
+ f->fmt.pix.field = fh->mpegq.field;
+ dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+ dev->width, dev->height, fh->mpegq.field );
+ return 0;
+}
+
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx8802_fh *fh = priv;
+ struct cx8802_dev *dev = fh->dev;
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
+ f->fmt.pix.colorspace = 0;
+ dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+ dev->width, dev->height, fh->mpegq.field );
+ return 0;
+}
+
+static int vidioc_s_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx8802_fh *fh = priv;
+ struct cx8802_dev *dev = fh->dev;
struct cx88_core *core = dev->core;
- if (debug > 1)
- v4l_print_ioctl(core->name,cmd);
-
- switch (cmd) {
-
- /* --- capabilities ------------------------------------------ */
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = arg;
-
- memset(cap,0,sizeof(*cap));
- strcpy(cap->driver, "cx88_blackbird");
- strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card));
- sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
- cap->version = CX88_VERSION_CODE;
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- 0;
- if (UNSET != core->tuner_type)
- cap->capabilities |= V4L2_CAP_TUNER;
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
+ f->fmt.pix.colorspace = 0;
+ dev->width = f->fmt.pix.width;
+ dev->height = f->fmt.pix.height;
+ fh->mpegq.field = f->fmt.pix.field;
+ cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+ blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+ f->fmt.pix.height, f->fmt.pix.width);
+ dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field );
+ return 0;
+}
- return 0;
- }
+static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
+{
+ struct cx8802_fh *fh = priv;
+ return (videobuf_reqbufs(&fh->mpegq, p));
+}
- /* --- capture ioctls ---------------------------------------- */
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *f = arg;
- int index;
-
- index = f->index;
- if (index != 0)
- return -EINVAL;
-
- memset(f,0,sizeof(*f));
- f->index = index;
- strlcpy(f->description, "MPEG", sizeof(f->description));
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->pixelformat = V4L2_PIX_FMT_MPEG;
- return 0;
- }
- case VIDIOC_G_FMT:
- {
- struct v4l2_format *f = arg;
-
- memset(f,0,sizeof(*f));
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */
- f->fmt.pix.colorspace = 0;
- f->fmt.pix.width = dev->width;
- f->fmt.pix.height = dev->height;
- f->fmt.pix.field = fh->mpegq.field;
- dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
- dev->width, dev->height, fh->mpegq.field );
- return 0;
- }
- case VIDIOC_TRY_FMT:
- {
- struct v4l2_format *f = arg;
-
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
- f->fmt.pix.colorspace = 0;
- dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
- dev->width, dev->height, fh->mpegq.field );
- return 0;
- }
- case VIDIOC_S_FMT:
- {
- struct v4l2_format *f = arg;
-
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
- f->fmt.pix.colorspace = 0;
- dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
- f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field );
- return 0;
- }
+static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8802_fh *fh = priv;
+ return (videobuf_querybuf(&fh->mpegq, p));
+}
- /* --- streaming capture ------------------------------------- */
- case VIDIOC_REQBUFS:
- return videobuf_reqbufs(&fh->mpegq, arg);
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8802_fh *fh = priv;
+ return (videobuf_qbuf(&fh->mpegq, p));
+}
- case VIDIOC_QUERYBUF:
- return videobuf_querybuf(&fh->mpegq, arg);
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8802_fh *fh = priv;
+ return (videobuf_dqbuf(&fh->mpegq, p,
+ file->f_flags & O_NONBLOCK));
+}
- case VIDIOC_QBUF:
- return videobuf_qbuf(&fh->mpegq, arg);
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct cx8802_fh *fh = priv;
+ return videobuf_streamon(&fh->mpegq);
+}
- case VIDIOC_DQBUF:
- return videobuf_dqbuf(&fh->mpegq, arg,
- file->f_flags & O_NONBLOCK);
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct cx8802_fh *fh = priv;
+ return videobuf_streamoff(&fh->mpegq);
+}
- case VIDIOC_STREAMON:
- return videobuf_streamon(&fh->mpegq);
+static int vidioc_g_mpegcomp (struct file *file, void *fh,
+ struct v4l2_mpeg_compression *f)
+{
+ printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
+ "Replace with VIDIOC_G_EXT_CTRLS!");
+ memcpy(f,&default_mpeg_params,sizeof(*f));
+ return 0;
+}
- case VIDIOC_STREAMOFF:
- return videobuf_streamoff(&fh->mpegq);
+static int vidioc_s_mpegcomp (struct file *file, void *fh,
+ struct v4l2_mpeg_compression *f)
+{
+ printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
+ "Replace with VIDIOC_S_EXT_CTRLS!");
+ return 0;
+}
- /* --- mpeg compression -------------------------------------- */
- case VIDIOC_G_MPEGCOMP:
- {
- struct v4l2_mpeg_compression *f = arg;
+static int vidioc_g_ext_ctrls (struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
- printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
- "Replace with VIDIOC_G_EXT_CTRLS!");
- memcpy(f,&default_mpeg_params,sizeof(*f));
- return 0;
- }
- case VIDIOC_S_MPEGCOMP:
- printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
- "Replace with VIDIOC_S_EXT_CTRLS!");
- return 0;
- case VIDIOC_G_EXT_CTRLS:
- {
- struct v4l2_ext_controls *f = arg;
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ return cx2341x_ext_ctrls(&dev->params, f, VIDIOC_G_EXT_CTRLS);
+}
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
- return cx2341x_ext_ctrls(&dev->params, f, cmd);
- }
- case VIDIOC_S_EXT_CTRLS:
- case VIDIOC_TRY_EXT_CTRLS:
- {
- struct v4l2_ext_controls *f = arg;
- struct cx2341x_mpeg_params p;
- int err;
-
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
- p = dev->params;
- err = cx2341x_ext_ctrls(&p, f, cmd);
- if (err == 0 && cmd == VIDIOC_S_EXT_CTRLS) {
- err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p);
- dev->params = p;
- }
- return err;
- }
- case VIDIOC_S_FREQUENCY:
- {
- blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
- BLACKBIRD_END_NOW,
- BLACKBIRD_MPEG_CAPTURE,
- BLACKBIRD_RAW_BITS_NONE);
-
- cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook);
-
- blackbird_initialize_codec(dev);
- cx88_set_scale(dev->core, dev->width, dev->height,
- fh->mpegq.field);
- return 0;
+static int vidioc_s_ext_ctrls (struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
+ struct cx2341x_mpeg_params p;
+ int err;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ p = dev->params;
+ err = cx2341x_ext_ctrls(&p, f, VIDIOC_S_EXT_CTRLS);
+ if (!err) {
+ err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p);
+ dev->params = p;
}
- case VIDIOC_LOG_STATUS:
- {
- char name[32 + 2];
-
- snprintf(name, sizeof(name), "%s/2", core->name);
- printk("%s/2: ============ START LOG STATUS ============\n",
- core->name);
- cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL);
- cx2341x_log_status(&dev->params, name);
- printk("%s/2: ============= END LOG STATUS =============\n",
- core->name);
+ return err;
+}
+
+static int vidioc_try_ext_ctrls (struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
+ struct cx2341x_mpeg_params p;
+ int err;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ p = dev->params;
+ err = cx2341x_ext_ctrls(&p, f, VIDIOC_TRY_EXT_CTRLS);
+
+ return err;
+}
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx8802_fh *fh = priv;
+ struct cx8802_dev *dev = fh->dev;
+ struct cx88_core *core = dev->core;
+
+ blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+ BLACKBIRD_END_NOW,
+ BLACKBIRD_MPEG_CAPTURE,
+ BLACKBIRD_RAW_BITS_NONE);
+ cx88_set_freq (core,f);
+ blackbird_initialize_codec(dev);
+ cx88_set_scale(dev->core, dev->width, dev->height,
+ fh->mpegq.field);
+ return 0;
+}
+
+static int vidioc_log_status (struct file *file, void *priv)
+{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
+ struct cx88_core *core = dev->core;
+ char name[32 + 2];
+
+ snprintf(name, sizeof(name), "%s/2", core->name);
+ printk("%s/2: ============ START LOG STATUS ============\n",
+ core->name);
+ cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL);
+ cx2341x_log_status(&dev->params, name);
+ printk("%s/2: ============= END LOG STATUS =============\n",
+ core->name);
+ return 0;
+}
+
+static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *qctrl)
+{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
+
+ if (blackbird_queryctrl(dev, qctrl) == 0)
return 0;
- }
- case VIDIOC_QUERYMENU:
- return blackbird_querymenu(dev, arg);
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *c = arg;
- if (blackbird_queryctrl(dev, c) == 0)
- return 0;
- return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl);
- }
+ qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+ if (unlikely(qctrl->id == 0))
+ return -EINVAL;
+ return cx8800_ctrl_query(qctrl);
+}
- default:
- return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook);
- }
+static int vidioc_enum_input (struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ return cx88_enum_input (core,i);
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ return
+ cx88_get_control(core,ctl);
+}
+
+static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ return
+ cx88_set_control(core,ctl);
+}
+
+static int vidioc_g_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx8802_fh *fh = priv;
+ struct cx88_core *core = fh->dev->core;
+
+ if (unlikely(UNSET == core->tuner_type))
+ return -EINVAL;
+
+ f->type = V4L2_TUNER_ANALOG_TV;
+ f->frequency = core->freq;
+ cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
+
+ return 0;
+}
+
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+
+ *i = core->input;
+ return 0;
+}
+
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+
+ if (i >= 4)
+ return -EINVAL;
+
+ mutex_lock(&core->lock);
+ cx88_newstation(core);
+ cx88_video_mux(core,i);
+ mutex_unlock(&core->lock);
return 0;
}
-int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg);
-unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
+static int vidioc_g_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ u32 reg;
+
+ if (unlikely(UNSET == core->tuner_type))
+ return -EINVAL;
+
+ strcpy(t->name, "Television");
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->rangehigh = 0xffffffffUL;
+
+ cx88_get_stereo(core ,t);
+ reg = cx_read(MO_DEVICE_STATUS);
+ t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
+ return 0;
+}
-static unsigned int mpeg_translate_ioctl(unsigned int cmd)
+static int vidioc_s_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
{
- return cmd;
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+
+ if (UNSET == core->tuner_type)
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
+
+ cx88_set_stereo(core, t->audmode, 1);
+ return 0;
}
-static int mpeg_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
{
- cmd = cx88_ioctl_translator( cmd );
- return video_usercopy(inode, file, cmd, arg, cx88_ioctl_hook);
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+
+ mutex_lock(&core->lock);
+ cx88_set_tvnorm(core,*id);
+ mutex_unlock(&core->lock);
+ return 0;
}
+/* FIXME: cx88_ioctl_hook not implemented */
+
static int mpeg_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
@@ -1059,17 +1197,47 @@ static const struct file_operations mpeg_fops =
.read = mpeg_read,
.poll = mpeg_poll,
.mmap = mpeg_mmap,
- .ioctl = mpeg_ioctl,
+ .ioctl = video_ioctl2,
.llseek = no_llseek,
};
static struct video_device cx8802_mpeg_template =
{
- .name = "cx8802",
- .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES|VID_TYPE_MPEG_ENCODER,
- .hardware = 0,
- .fops = &mpeg_fops,
- .minor = -1,
+ .name = "cx8802",
+ .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES|VID_TYPE_MPEG_ENCODER,
+ .fops = &mpeg_fops,
+ .minor = -1,
+ .vidioc_querymenu = vidioc_querymenu,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
+ .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
+ .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
+ .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_g_mpegcomp = vidioc_g_mpegcomp,
+ .vidioc_s_mpegcomp = vidioc_s_mpegcomp,
+ .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
+ .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
+ .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_log_status = vidioc_log_status,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_s_std = vidioc_s_std,
+ .tvnorms = CX88_NORMS,
+ .current_norm = V4L2_STD_NTSC_M,
};
/* ------------------------------------------------------------------ */
@@ -1164,7 +1332,9 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
cx2341x_fill_defaults(&dev->params);
dev->params.port = CX2341X_PORT_STREAMING;
- if (core->tvnorm->id & V4L2_STD_525_60) {
+ cx8802_mpeg_template.current_norm = core->tvnorm;
+
+ if (core->tvnorm & V4L2_STD_525_60) {
dev->height = 480;
} else {
dev->height = 576;
@@ -1178,6 +1348,11 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
blackbird_register_video(dev);
/* initial device configuration: needed ? */
+ mutex_lock(&dev->core->lock);
+// init_controls(core);
+ cx88_set_tvnorm(core,core->tvnorm);
+ cx88_video_mux(core,0);
+ mutex_unlock(&dev->core->lock);
return 0;
@@ -1212,8 +1387,6 @@ static int blackbird_init(void)
printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
#endif
- cx88_ioctl_hook = mpeg_do_ioctl;
- cx88_ioctl_translator = mpeg_translate_ioctl;
return cx8802_register_driver(&cx8802_blackbird_driver);
}
@@ -1225,8 +1398,8 @@ static void blackbird_fini(void)
module_init(blackbird_init);
module_exit(blackbird_fini);
-EXPORT_SYMBOL(cx88_ioctl_hook);
-EXPORT_SYMBOL(cx88_ioctl_translator);
+module_param_named(video_debug,cx8802_mpeg_template.debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages [video]");
/* ----------------------------------------------------------- */
/*
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 434b78ab37d..65e9d8096b7 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -764,6 +764,12 @@ struct cx88_board cx88_boards[] = {
.input = {{
.type = CX88_VMUX_DVB,
.vmux = 0,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 2,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
}},
.mpeg = CX88_MPEG_DVB,
},
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index 18997361c75..d86813be56d 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -5,6 +5,11 @@
*
* (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
*
+ * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ * - Multituner support
+ * - video_ioctl2 conversion
+ * - PAL/M fixes
+ *
* 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
@@ -631,30 +636,30 @@ int cx88_reset(struct cx88_core *core)
/* ------------------------------------------------------------------ */
-static unsigned int inline norm_swidth(struct cx88_tvnorm *norm)
+static unsigned int inline norm_swidth(v4l2_std_id norm)
{
- return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
+ return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
}
-static unsigned int inline norm_hdelay(struct cx88_tvnorm *norm)
+static unsigned int inline norm_hdelay(v4l2_std_id norm)
{
- return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
+ return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
}
-static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm)
+static unsigned int inline norm_vdelay(v4l2_std_id norm)
{
- return (norm->id & V4L2_STD_625_50) ? 0x24 : 0x18;
+ return (norm & V4L2_STD_625_50) ? 0x24 : 0x18;
}
-static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
+static unsigned int inline norm_fsc8(v4l2_std_id norm)
{
- if (norm->id & V4L2_STD_PAL_M)
+ if (norm & V4L2_STD_PAL_M)
return 28604892; // 3.575611 MHz
- if (norm->id & (V4L2_STD_PAL_Nc))
+ if (norm & (V4L2_STD_PAL_Nc))
return 28656448; // 3.582056 MHz
- if (norm->id & V4L2_STD_NTSC) // All NTSC/M and variants
+ if (norm & V4L2_STD_NTSC) // All NTSC/M and variants
return 28636360; // 3.57954545 MHz +/- 10 Hz
/* SECAM have also different sub carrier for chroma,
@@ -666,20 +671,20 @@ static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
return 35468950; // 4.43361875 MHz +/- 5 Hz
}
-static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
+static unsigned int inline norm_htotal(v4l2_std_id norm)
{
unsigned int fsc4=norm_fsc8(norm)/2;
/* returns 4*FSC / vtotal / frames per seconds */
- return (norm->id & V4L2_STD_625_50) ?
+ return (norm & V4L2_STD_625_50) ?
((fsc4+312)/625+12)/25 :
((fsc4+262)/525*1001+15000)/30000;
}
-static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
+static unsigned int inline norm_vbipack(v4l2_std_id norm)
{
- return (norm->id & V4L2_STD_625_50) ? 511 : 400;
+ return (norm & V4L2_STD_625_50) ? 511 : 400;
}
int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
@@ -692,7 +697,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
V4L2_FIELD_HAS_TOP(field) ? "T" : "",
V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
- core->tvnorm->name);
+ v4l2_norm_to_name(core->tvnorm));
if (!V4L2_FIELD_HAS_BOTH(field))
height *= 2;
@@ -729,7 +734,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
// setup filters
value = 0;
value |= (1 << 19); // CFILT (default)
- if (core->tvnorm->id & V4L2_STD_SECAM) {
+ if (core->tvnorm & V4L2_STD_SECAM) {
value |= (1 << 15);
value |= (1 << 16);
}
@@ -826,36 +831,36 @@ int cx88_stop_audio_dma(struct cx88_core *core)
static int set_tvaudio(struct cx88_core *core)
{
- struct cx88_tvnorm *norm = core->tvnorm;
+ v4l2_std_id norm = core->tvnorm;
if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
return 0;
- if (V4L2_STD_PAL_BG & norm->id) {
+ if (V4L2_STD_PAL_BG & norm) {
core->tvaudio = WW_BG;
- } else if (V4L2_STD_PAL_DK & norm->id) {
+ } else if (V4L2_STD_PAL_DK & norm) {
core->tvaudio = WW_DK;
- } else if (V4L2_STD_PAL_I & norm->id) {
+ } else if (V4L2_STD_PAL_I & norm) {
core->tvaudio = WW_I;
- } else if (V4L2_STD_SECAM_L & norm->id) {
+ } else if (V4L2_STD_SECAM_L & norm) {
core->tvaudio = WW_L;
- } else if (V4L2_STD_SECAM_DK & norm->id) {
+ } else if (V4L2_STD_SECAM_DK & norm) {
core->tvaudio = WW_DK;
- } else if ((V4L2_STD_NTSC_M & norm->id) ||
- (V4L2_STD_PAL_M & norm->id)) {
+ } else if ((V4L2_STD_NTSC_M & norm) ||
+ (V4L2_STD_PAL_M & norm)) {
core->tvaudio = WW_BTSC;
- } else if (V4L2_STD_NTSC_M_JP & norm->id) {
+ } else if (V4L2_STD_NTSC_M_JP & norm) {
core->tvaudio = WW_EIAJ;
} else {
printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
- core->name, norm->name);
+ core->name, v4l2_norm_to_name(core->tvnorm));
core->tvaudio = 0;
return 0;
}
@@ -874,7 +879,7 @@ static int set_tvaudio(struct cx88_core *core)
-int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
+int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
{
u32 fsc8;
u32 adc_clock;
@@ -882,6 +887,7 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
u32 step_db,step_dr;
u64 tmp64;
u32 bdelay,agcdelay,htotal;
+ u32 cxiformat, cxoformat;
core->tvnorm = norm;
fsc8 = norm_fsc8(norm);
@@ -890,23 +896,51 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
step_db = fsc8;
step_dr = fsc8;
- if (norm->id & V4L2_STD_SECAM) {
+ if (norm & V4L2_STD_NTSC_M_JP) {
+ cxiformat = VideoFormatNTSCJapan;
+ cxoformat = 0x181f0008;
+ } else if (norm & V4L2_STD_NTSC_443) {
+ cxiformat = VideoFormatNTSC443;
+ cxoformat = 0x181f0008;
+ } else if (norm & V4L2_STD_PAL_M) {
+ cxiformat = VideoFormatPALM;
+ cxoformat = 0x1c1f0008;
+ } else if (norm & V4L2_STD_PAL_N) {
+ cxiformat = VideoFormatPALN;
+ cxoformat = 0x1c1f0008;
+ } else if (norm & V4L2_STD_PAL_Nc) {
+ cxiformat = VideoFormatPALNC;
+ cxoformat = 0x1c1f0008;
+ } else if (norm & V4L2_STD_PAL_60) {
+ cxiformat = VideoFormatPAL60;
+ cxoformat = 0x181f0008;
+ } else if (norm & V4L2_STD_NTSC) {
+ cxiformat = VideoFormatNTSC;
+ cxoformat = 0x181f0008;
+ } else if (norm & V4L2_STD_SECAM) {
step_db = 4250000 * 8;
step_dr = 4406250 * 8;
+
+ cxiformat = VideoFormatSECAM;
+ cxoformat = 0x181f0008;
+ } else { /* PAL */
+ cxiformat = VideoFormatPAL;
+ cxoformat = 0x181f0008;
}
dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
- norm->name, fsc8, adc_clock, vdec_clock, step_db, step_dr);
+ v4l2_norm_to_name(core->tvnorm), fsc8, adc_clock, vdec_clock,
+ step_db, step_dr);
set_pll(core,2,vdec_clock);
dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n",
- norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
- cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);
+ cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
+ cx_andor(MO_INPUT_FORMAT, 0xf, cxiformat);
// FIXME: as-is from DScaler
dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
- norm->cxoformat, cx_read(MO_OUTPUT_FORMAT));
- cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);
+ cxoformat, cx_read(MO_OUTPUT_FORMAT));
+ cx_write(MO_OUTPUT_FORMAT, cxoformat);
// MO_SCONV_REG = adc clock / video dec clock * 2^17
tmp64 = adc_clock * (u64)(1 << 17);
@@ -955,7 +989,7 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
set_tvaudio(core);
// tell i2c chips
- cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
+ cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm);
// done
return 0;
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 8b203354fcc..4f556028577 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -35,7 +35,7 @@
#include "mt352.h"
#include "mt352_priv.h"
-#ifdef HAVE_VP3054_I2C
+#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
# include "cx88-vp3054-i2c.h"
#endif
#include "zl10353.h"
@@ -200,7 +200,7 @@ static struct mt352_config dvico_fusionhdtv_dual = {
.demod_init = dvico_dual_demod_init,
};
-#ifdef HAVE_VP3054_I2C
+#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
{
static u8 clock_config [] = { 0x89, 0x38, 0x38 };
@@ -543,7 +543,7 @@ static int dvb_register(struct cx8802_dev *dev)
}
break;
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
-#ifdef HAVE_VP3054_I2C
+#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
dev->core->pll_addr = 0x61;
dev->core->pll_desc = &dvb_pll_fmd1216me;
dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
@@ -793,7 +793,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB))
goto fail_core;
-#ifdef HAVE_VP3054_I2C
+#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
err = vp3054_i2c_probe(dev);
if (0 != err)
goto fail_core;
@@ -822,7 +822,7 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv)
/* dvb */
videobuf_dvb_unregister(&dev->dvb);
-#ifdef HAVE_VP3054_I2C
+#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
vp3054_i2c_remove(dev);
#endif
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 88af23a9387..9830d5c4392 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -145,6 +145,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
if (0 != core->i2c_rc)
return;
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
if ( (core->dvbdev) && (core->dvbdev->dvb.frontend) ) {
if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
@@ -154,6 +155,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
} else
+#endif
i2c_clients_command(&core->i2c_adap, cmd, arg);
}
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 063df03dcf2..97ef421dd09 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -797,55 +797,6 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
Add some code here later.
*/
-# if 0
- t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
- V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
- t->rxsubchans = V4L2_TUNER_SUB_MONO;
- t->audmode = V4L2_TUNER_MODE_MONO;
-
- switch (core->tvaudio) {
- case WW_BTSC:
- t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP;
- t->rxsubchans = V4L2_TUNER_SUB_STEREO;
- if (1 == pilot) {
- /* SAP */
- t->rxsubchans |= V4L2_TUNER_SUB_SAP;
- }
- break;
- case WW_A2_BG:
- case WW_A2_DK:
- case WW_A2_M:
- if (1 == pilot) {
- /* stereo */
- t->rxsubchans =
- V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- if (0 == mode)
- t->audmode = V4L2_TUNER_MODE_STEREO;
- }
- if (2 == pilot) {
- /* dual language -- FIXME */
- t->rxsubchans =
- V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
- t->audmode = V4L2_TUNER_MODE_LANG1;
- }
- break;
- case WW_NICAM_BGDKL:
- if (0 == mode) {
- t->audmode = V4L2_TUNER_MODE_STEREO;
- t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
- }
- break;
- case WW_SYSTEM_L_AM:
- if (0x0 == mode && !(cx_read(AUD_INIT) & 0x04)) {
- t->audmode = V4L2_TUNER_MODE_STEREO;
- t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
- }
- break;
- default:
- /* nothing */
- break;
- }
-# endif
return;
}
diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c
index aa2a6977009..86c1cf8334b 100644
--- a/drivers/media/video/cx88/cx88-vbi.c
+++ b/drivers/media/video/cx88/cx88-vbi.c
@@ -21,9 +21,11 @@ MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
/* ------------------------------------------------------------------ */
-void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f)
+int cx8800_vbi_fmt (struct file *file, void *priv,
+ struct v4l2_format *f)
{
- memset(&f->fmt.vbi,0,sizeof(f->fmt.vbi));
+ struct cx8800_fh *fh = priv;
+ struct cx8800_dev *dev = fh->dev;
f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
@@ -31,18 +33,19 @@ void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f)
f->fmt.vbi.count[0] = VBI_LINE_COUNT;
f->fmt.vbi.count[1] = VBI_LINE_COUNT;
- if (dev->core->tvnorm->id & V4L2_STD_525_60) {
+ if (dev->core->tvnorm & V4L2_STD_525_60) {
/* ntsc */
f->fmt.vbi.sampling_rate = 28636363;
f->fmt.vbi.start[0] = 10;
f->fmt.vbi.start[1] = 273;
- } else if (dev->core->tvnorm->id & V4L2_STD_625_50) {
+ } else if (dev->core->tvnorm & V4L2_STD_625_50) {
/* pal */
f->fmt.vbi.sampling_rate = 35468950;
f->fmt.vbi.start[0] = 7 -1;
f->fmt.vbi.start[1] = 319 -1;
}
+ return 0;
}
static int cx8800_start_vbi_dma(struct cx8800_dev *dev,
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index c86a7e06235..bdfe2af7012 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -1,3 +1,4 @@
+
/*
*
* device driver for Conexant 2388x based TV cards
@@ -5,6 +6,11 @@
*
* (c) 2003-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
*
+ * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ * - Multituner support
+ * - video_ioctl2 conversion
+ * - PAL/M fixes
+ *
* 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
@@ -80,65 +86,6 @@ static LIST_HEAD(cx8800_devlist);
/* ------------------------------------------------------------------- */
/* static data */
-static struct cx88_tvnorm tvnorms[] = {
- {
- .name = "NTSC-M",
- .id = V4L2_STD_NTSC_M,
- .cxiformat = VideoFormatNTSC,
- .cxoformat = 0x181f0008,
- },{
- .name = "NTSC-JP",
- .id = V4L2_STD_NTSC_M_JP,
- .cxiformat = VideoFormatNTSCJapan,
- .cxoformat = 0x181f0008,
- },{
- .name = "PAL-BG",
- .id = V4L2_STD_PAL_BG,
- .cxiformat = VideoFormatPAL,
- .cxoformat = 0x181f0008,
- },{
- .name = "PAL-DK",
- .id = V4L2_STD_PAL_DK,
- .cxiformat = VideoFormatPAL,
- .cxoformat = 0x181f0008,
- },{
- .name = "PAL-I",
- .id = V4L2_STD_PAL_I,
- .cxiformat = VideoFormatPAL,
- .cxoformat = 0x181f0008,
- },{
- .name = "PAL-M",
- .id = V4L2_STD_PAL_M,
- .cxiformat = VideoFormatPALM,
- .cxoformat = 0x1c1f0008,
- },{
- .name = "PAL-N",
- .id = V4L2_STD_PAL_N,
- .cxiformat = VideoFormatPALN,
- .cxoformat = 0x1c1f0008,
- },{
- .name = "PAL-Nc",
- .id = V4L2_STD_PAL_Nc,
- .cxiformat = VideoFormatPALNC,
- .cxoformat = 0x1c1f0008,
- },{
- .name = "PAL-60",
- .id = V4L2_STD_PAL_60,
- .cxiformat = VideoFormatPAL60,
- .cxoformat = 0x181f0008,
- },{
- .name = "SECAM-L",
- .id = V4L2_STD_SECAM_L,
- .cxiformat = VideoFormatSECAM,
- .cxoformat = 0x181f0008,
- },{
- .name = "SECAM-DK",
- .id = V4L2_STD_SECAM_DK,
- .cxiformat = VideoFormatSECAM,
- .cxoformat = 0x181f0008,
- }
-};
-
static struct cx8800_fmt formats[] = {
{
.name = "8 bpp, gray",
@@ -364,14 +311,6 @@ int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl)
}
EXPORT_SYMBOL(cx8800_ctrl_query);
-static int cx88_queryctrl(struct v4l2_queryctrl *qctrl)
-{
- qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
- if (qctrl->id == 0)
- return -EINVAL;
- return cx8800_ctrl_query(qctrl);
-}
-
/* ------------------------------------------------------------------- */
/* resource management */
@@ -424,8 +363,7 @@ void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits)
/* ------------------------------------------------------------------ */
-/* static int video_mux(struct cx8800_dev *dev, unsigned int input) */
-static int video_mux(struct cx88_core *core, unsigned int input)
+int cx88_video_mux(struct cx88_core *core, unsigned int input)
{
/* struct cx88_core *core = dev->core; */
@@ -464,6 +402,7 @@ static int video_mux(struct cx88_core *core, unsigned int input)
}
return 0;
}
+EXPORT_SYMBOL(cx88_video_mux);
/* ------------------------------------------------------------------ */
@@ -944,19 +883,18 @@ video_mmap(struct file *file, struct vm_area_struct * vma)
}
/* ------------------------------------------------------------------ */
+/* VIDEO CTRL IOCTLS */
-/* static int get_control(struct cx8800_dev *dev, struct v4l2_control *ctl) */
-static int get_control(struct cx88_core *core, struct v4l2_control *ctl)
+int cx88_get_control (struct cx88_core *core, struct v4l2_control *ctl)
{
- /* struct cx88_core *core = dev->core; */
- struct cx88_ctrl *c = NULL;
+ struct cx88_ctrl *c = NULL;
u32 value;
int i;
for (i = 0; i < CX8800_CTLS; i++)
if (cx8800_ctls[i].v.id == ctl->id)
c = &cx8800_ctls[i];
- if (NULL == c)
+ if (unlikely(NULL == c))
return -EINVAL;
value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg);
@@ -977,20 +915,20 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl)
value,c->mask, c->sreg ? " [shadowed]" : "");
return 0;
}
+EXPORT_SYMBOL(cx88_get_control);
-/* static int set_control(struct cx8800_dev *dev, struct v4l2_control *ctl) */
-static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
+int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
{
- /* struct cx88_core *core = dev->core; */
struct cx88_ctrl *c = NULL;
u32 value,mask;
int i;
+
for (i = 0; i < CX8800_CTLS; i++) {
if (cx8800_ctls[i].v.id == ctl->id) {
c = &cx8800_ctls[i];
}
}
- if (NULL == c)
+ if (unlikely(NULL == c))
return -EINVAL;
if (ctl->value < c->v.minimum)
@@ -1010,7 +948,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
value = ((ctl->value - c->off) << c->shift) & c->mask;
- if (core->tvnorm->id & V4L2_STD_SECAM) {
+ if (core->tvnorm & V4L2_STD_SECAM) {
/* For SECAM, both U and V sat should be equal */
value=value<<8|value;
} else {
@@ -1033,6 +971,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
}
return 0;
}
+EXPORT_SYMBOL(cx88_set_control);
static void init_controls(struct cx88_core *core)
{
@@ -1042,648 +981,531 @@ static void init_controls(struct cx88_core *core)
for (i = 0; i < CX8800_CTLS; i++) {
ctrl.id=cx8800_ctls[i].v.id;
ctrl.value=cx8800_ctls[i].v.default_value;
- set_control(core, &ctrl);
+
+ cx88_set_control(core, &ctrl);
}
}
/* ------------------------------------------------------------------ */
+/* VIDEO IOCTLS */
-static int cx8800_g_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh,
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx8800_fh *fh = priv;
+
+ f->fmt.pix.width = fh->width;
+ f->fmt.pix.height = fh->height;
+ f->fmt.pix.field = fh->vidq.field;
+ f->fmt.pix.pixelformat = fh->fmt->fourcc;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fh->fmt->depth) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+ return 0;
+}
+
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
struct v4l2_format *f)
{
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
- f->fmt.pix.width = fh->width;
- f->fmt.pix.height = fh->height;
- f->fmt.pix.field = fh->vidq.field;
- f->fmt.pix.pixelformat = fh->fmt->fourcc;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fh->fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
- return 0;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- cx8800_vbi_fmt(dev, f);
- return 0;
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ struct cx8800_fmt *fmt;
+ enum v4l2_field field;
+ unsigned int maxw, maxh;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (NULL == fmt)
+ return -EINVAL;
+
+ field = f->fmt.pix.field;
+ maxw = norm_maxw(core->tvnorm);
+ maxh = norm_maxh(core->tvnorm);
+
+ if (V4L2_FIELD_ANY == field) {
+ field = (f->fmt.pix.height > maxh/2)
+ ? V4L2_FIELD_INTERLACED
+ : V4L2_FIELD_BOTTOM;
+ }
+
+ switch (field) {
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ maxh = maxh / 2;
+ break;
+ case V4L2_FIELD_INTERLACED:
+ break;
default:
return -EINVAL;
}
+
+ f->fmt.pix.field = field;
+ if (f->fmt.pix.height < 32)
+ f->fmt.pix.height = 32;
+ if (f->fmt.pix.height > maxh)
+ f->fmt.pix.height = maxh;
+ if (f->fmt.pix.width < 48)
+ f->fmt.pix.width = 48;
+ if (f->fmt.pix.width > maxw)
+ f->fmt.pix.width = maxw;
+ f->fmt.pix.width &= ~0x03;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fmt->depth) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+ return 0;
}
-static int cx8800_try_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh,
- struct v4l2_format *f)
+static int vidioc_s_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
{
- struct cx88_core *core = dev->core;
+ struct cx8800_fh *fh = priv;
+ int err = vidioc_try_fmt_cap (file,priv,f);
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- {
- struct cx8800_fmt *fmt;
- enum v4l2_field field;
- unsigned int maxw, maxh;
-
- fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- if (NULL == fmt)
- return -EINVAL;
-
- field = f->fmt.pix.field;
- maxw = norm_maxw(core->tvnorm);
- maxh = norm_maxh(core->tvnorm);
-
- if (V4L2_FIELD_ANY == field) {
- field = (f->fmt.pix.height > maxh/2)
- ? V4L2_FIELD_INTERLACED
- : V4L2_FIELD_BOTTOM;
- }
+ if (0 != err)
+ return err;
+ fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ fh->width = f->fmt.pix.width;
+ fh->height = f->fmt.pix.height;
+ fh->vidq.field = f->fmt.pix.field;
+ return 0;
+}
- switch (field) {
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- maxh = maxh / 2;
- break;
- case V4L2_FIELD_INTERLACED:
- break;
- default:
- return -EINVAL;
- }
+static int vidioc_querycap (struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev;
+ struct cx88_core *core = dev->core;
- f->fmt.pix.field = field;
- if (f->fmt.pix.height < 32)
- f->fmt.pix.height = 32;
- if (f->fmt.pix.height > maxh)
- f->fmt.pix.height = maxh;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.width > maxw)
- f->fmt.pix.width = maxw;
- f->fmt.pix.width &= ~0x03;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
+ strcpy(cap->driver, "cx8800");
+ strlcpy(cap->card, cx88_boards[core->board].name,
+ sizeof(cap->card));
+ sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
+ cap->version = CX88_VERSION_CODE;
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_VBI_CAPTURE;
+ if (UNSET != core->tuner_type)
+ cap->capabilities |= V4L2_CAP_TUNER;
+ return 0;
+}
- return 0;
- }
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- cx8800_vbi_fmt(dev, f);
- return 0;
- default:
+static int vidioc_enum_fmt_cap (struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (unlikely(f->index >= ARRAY_SIZE(formats)))
return -EINVAL;
- }
+
+ strlcpy(f->description,formats[f->index].name,sizeof(f->description));
+ f->pixelformat = formats[f->index].fourcc;
+
+ return 0;
}
-static int cx8800_s_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh,
- struct v4l2_format *f)
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
{
+ struct cx8800_fh *fh = priv;
+ struct videobuf_queue *q;
+ struct v4l2_requestbuffers req;
+ unsigned int i;
int err;
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- err = cx8800_try_fmt(dev,fh,f);
- if (0 != err)
- return err;
+ q = get_queue(fh);
+ memset(&req,0,sizeof(req));
+ req.type = q->type;
+ req.count = 8;
+ req.memory = V4L2_MEMORY_MMAP;
+ err = videobuf_reqbufs(q,&req);
+ if (err < 0)
+ return err;
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
- fh->vidq.field = f->fmt.pix.field;
- return 0;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- cx8800_vbi_fmt(dev, f);
- return 0;
- default:
- return -EINVAL;
+ mbuf->frames = req.count;
+ mbuf->size = 0;
+ for (i = 0; i < mbuf->frames; i++) {
+ mbuf->offsets[i] = q->bufs[i]->boff;
+ mbuf->size += q->bufs[i]->bsize;
}
+ return 0;
}
+#endif
-/*
- * This function is _not_ called directly, but from
- * video_generic_ioctl (and maybe others). userspace
- * copying is done already, arg is a kernel pointer.
- */
-static int video_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
+{
+ struct cx8800_fh *fh = priv;
+ return (videobuf_reqbufs(get_queue(fh), p));
+}
+
+static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8800_fh *fh = priv;
+ return (videobuf_querybuf(get_queue(fh), p));
+}
+
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8800_fh *fh = priv;
+ return (videobuf_qbuf(get_queue(fh), p));
+}
+
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8800_fh *fh = priv;
+ return (videobuf_dqbuf(get_queue(fh), p,
+ file->f_flags & O_NONBLOCK));
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
- struct cx8800_fh *fh = file->private_data;
+ struct cx8800_fh *fh = priv;
struct cx8800_dev *dev = fh->dev;
- struct cx88_core *core = dev->core;
- int err;
- if (video_debug > 1)
- v4l_print_ioctl(core->name,cmd);
- switch (cmd) {
+ if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
+ return -EINVAL;
+ if (unlikely(i != fh->type))
+ return -EINVAL;
- /* --- capabilities ------------------------------------------ */
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = arg;
-
- memset(cap,0,sizeof(*cap));
- strcpy(cap->driver, "cx8800");
- strlcpy(cap->card, cx88_boards[core->board].name,
- sizeof(cap->card));
- sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
- cap->version = CX88_VERSION_CODE;
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_VBI_CAPTURE |
- 0;
- if (UNSET != core->tuner_type)
- cap->capabilities |= V4L2_CAP_TUNER;
- return 0;
- }
+ if (unlikely(!res_get(dev,fh,get_ressource(fh))))
+ return -EBUSY;
+ return videobuf_streamon(get_queue(fh));
+}
- /* --- capture ioctls ---------------------------------------- */
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *f = arg;
- enum v4l2_buf_type type;
- unsigned int index;
-
- index = f->index;
- type = f->type;
- switch (type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (index >= ARRAY_SIZE(formats))
- return -EINVAL;
- memset(f,0,sizeof(*f));
- f->index = index;
- f->type = type;
- strlcpy(f->description,formats[index].name,sizeof(f->description));
- f->pixelformat = formats[index].fourcc;
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- case VIDIOC_G_FMT:
- {
- struct v4l2_format *f = arg;
- return cx8800_g_fmt(dev,fh,f);
- }
- case VIDIOC_S_FMT:
- {
- struct v4l2_format *f = arg;
- return cx8800_s_fmt(dev,fh,f);
- }
- case VIDIOC_TRY_FMT:
- {
- struct v4l2_format *f = arg;
- return cx8800_try_fmt(dev,fh,f);
- }
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- /* --- streaming capture ------------------------------------- */
- case VIDIOCGMBUF:
- {
- struct video_mbuf *mbuf = arg;
- struct videobuf_queue *q;
- struct v4l2_requestbuffers req;
- unsigned int i;
-
- q = get_queue(fh);
- memset(&req,0,sizeof(req));
- req.type = q->type;
- req.count = 8;
- req.memory = V4L2_MEMORY_MMAP;
- err = videobuf_reqbufs(q,&req);
- if (err < 0)
- return err;
- memset(mbuf,0,sizeof(*mbuf));
- mbuf->frames = req.count;
- mbuf->size = 0;
- for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += q->bufs[i]->bsize;
- }
- return 0;
- }
-#endif
- case VIDIOC_REQBUFS:
- return videobuf_reqbufs(get_queue(fh), arg);
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct cx8800_fh *fh = priv;
+ struct cx8800_dev *dev = fh->dev;
+ int err, res;
- case VIDIOC_QUERYBUF:
- return videobuf_querybuf(get_queue(fh), arg);
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (i != fh->type)
+ return -EINVAL;
- case VIDIOC_QBUF:
- return videobuf_qbuf(get_queue(fh), arg);
+ res = get_ressource(fh);
+ err = videobuf_streamoff(get_queue(fh));
+ if (err < 0)
+ return err;
+ res_free(dev,fh,res);
+ return 0;
+}
- case VIDIOC_DQBUF:
- return videobuf_dqbuf(get_queue(fh), arg,
- file->f_flags & O_NONBLOCK);
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- case VIDIOC_STREAMON:
- {
- int res = get_ressource(fh);
+ mutex_lock(&core->lock);
+ cx88_set_tvnorm(core,*tvnorms);
+ mutex_unlock(&core->lock);
- if (!res_get(dev,fh,res))
- return -EBUSY;
- return videobuf_streamon(get_queue(fh));
- }
- case VIDIOC_STREAMOFF:
- {
- int res = get_ressource(fh);
+ return 0;
+}
- err = videobuf_streamoff(get_queue(fh));
- if (err < 0)
- return err;
- res_free(dev,fh,res);
- return 0;
- }
- default:
- return cx88_do_ioctl( inode, file, fh->radio, core, cmd, arg, video_do_ioctl );
- }
+/* only one input in this sample driver */
+int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i)
+{
+ static const char *iname[] = {
+ [ CX88_VMUX_COMPOSITE1 ] = "Composite1",
+ [ CX88_VMUX_COMPOSITE2 ] = "Composite2",
+ [ CX88_VMUX_COMPOSITE3 ] = "Composite3",
+ [ CX88_VMUX_COMPOSITE4 ] = "Composite4",
+ [ CX88_VMUX_SVIDEO ] = "S-Video",
+ [ CX88_VMUX_TELEVISION ] = "Television",
+ [ CX88_VMUX_CABLE ] = "Cable TV",
+ [ CX88_VMUX_DVB ] = "DVB",
+ [ CX88_VMUX_DEBUG ] = "for debug only",
+ };
+ unsigned int n;
+
+ n = i->index;
+ if (n >= 4)
+ return -EINVAL;
+ if (0 == INPUT(n)->type)
+ return -EINVAL;
+ memset(i,0,sizeof(*i));
+ i->index = n;
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ strcpy(i->name,iname[INPUT(n)->type]);
+ if ((CX88_VMUX_TELEVISION == INPUT(n)->type) ||
+ (CX88_VMUX_CABLE == INPUT(n)->type))
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ i->std = CX88_NORMS;
return 0;
}
+EXPORT_SYMBOL(cx88_enum_input);
-int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
- struct cx88_core *core, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl)
+static int vidioc_enum_input (struct file *file, void *priv,
+ struct v4l2_input *i)
{
- int err;
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ return cx88_enum_input (core,i);
+}
- if (video_debug) {
- if (video_debug > 1) {
- if (_IOC_DIR(cmd) & _IOC_WRITE)
- v4l_printk_ioctl_arg("cx88(w)",cmd, arg);
- else if (!_IOC_DIR(cmd) & _IOC_READ) {
- v4l_print_ioctl("cx88", cmd);
- }
- } else
- v4l_print_ioctl(core->name,cmd);
-
- }
-
- switch (cmd) {
- /* ---------- tv norms ---------- */
- case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *e = arg;
- unsigned int i;
-
- i = e->index;
- if (i >= ARRAY_SIZE(tvnorms))
- return -EINVAL;
- err = v4l2_video_std_construct(e, tvnorms[e->index].id,
- tvnorms[e->index].name);
- e->index = i;
- if (err < 0)
- return err;
- return 0;
- }
- case VIDIOC_G_STD:
- {
- v4l2_std_id *id = arg;
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- *id = core->tvnorm->id;
- return 0;
- }
- case VIDIOC_S_STD:
- {
- v4l2_std_id *id = arg;
- unsigned int i;
+ *i = core->input;
+ return 0;
+}
- for(i = 0; i < ARRAY_SIZE(tvnorms); i++)
- if (*id & tvnorms[i].id)
- break;
- if (i == ARRAY_SIZE(tvnorms))
- return -EINVAL;
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- mutex_lock(&core->lock);
- cx88_set_tvnorm(core,&tvnorms[i]);
- mutex_unlock(&core->lock);
- return 0;
- }
+ if (i >= 4)
+ return -EINVAL;
- /* ------ input switching ---------- */
- case VIDIOC_ENUMINPUT:
- {
- static const char *iname[] = {
- [ CX88_VMUX_COMPOSITE1 ] = "Composite1",
- [ CX88_VMUX_COMPOSITE2 ] = "Composite2",
- [ CX88_VMUX_COMPOSITE3 ] = "Composite3",
- [ CX88_VMUX_COMPOSITE4 ] = "Composite4",
- [ CX88_VMUX_SVIDEO ] = "S-Video",
- [ CX88_VMUX_TELEVISION ] = "Television",
- [ CX88_VMUX_CABLE ] = "Cable TV",
- [ CX88_VMUX_DVB ] = "DVB",
- [ CX88_VMUX_DEBUG ] = "for debug only",
- };
- struct v4l2_input *i = arg;
- unsigned int n;
-
- n = i->index;
- if (n >= 4)
- return -EINVAL;
- if (0 == INPUT(n)->type)
- return -EINVAL;
- memset(i,0,sizeof(*i));
- i->index = n;
- i->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(i->name,iname[INPUT(n)->type]);
- if ((CX88_VMUX_TELEVISION == INPUT(n)->type) ||
- (CX88_VMUX_CABLE == INPUT(n)->type))
- i->type = V4L2_INPUT_TYPE_TUNER;
- for (n = 0; n < ARRAY_SIZE(tvnorms); n++)
- i->std |= tvnorms[n].id;
- return 0;
- }
- case VIDIOC_G_INPUT:
- {
- unsigned int *i = arg;
+ mutex_lock(&core->lock);
+ cx88_newstation(core);
+ cx88_video_mux(core,i);
+ mutex_unlock(&core->lock);
+ return 0;
+}
- *i = core->input;
- return 0;
- }
- case VIDIOC_S_INPUT:
- {
- unsigned int *i = arg;
- if (*i >= 4)
- return -EINVAL;
- mutex_lock(&core->lock);
- cx88_newstation(core);
- video_mux(core,*i);
- mutex_unlock(&core->lock);
- return 0;
- }
+static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *qctrl)
+{
+ qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+ if (unlikely(qctrl->id == 0))
+ return -EINVAL;
+ return cx8800_ctrl_query(qctrl);
+}
+static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ return
+ cx88_get_control(core,ctl);
+}
- /* --- controls ---------------------------------------------- */
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *c = arg;
+static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ return
+ cx88_set_control(core,ctl);
+}
- return cx88_queryctrl(c);
- }
- case VIDIOC_G_CTRL:
- return get_control(core,arg);
- case VIDIOC_S_CTRL:
- return set_control(core,arg);
+static int vidioc_g_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ u32 reg;
- /* --- tuner ioctls ------------------------------------------ */
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *t = arg;
- u32 reg;
-
- if (UNSET == core->tuner_type)
- return -EINVAL;
- if (0 != t->index)
- return -EINVAL;
-
- memset(t,0,sizeof(*t));
- strcpy(t->name, "Television");
- t->type = V4L2_TUNER_ANALOG_TV;
- t->capability = V4L2_TUNER_CAP_NORM;
- t->rangehigh = 0xffffffffUL;
-
- cx88_get_stereo(core ,t);
- reg = cx_read(MO_DEVICE_STATUS);
- t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
- return 0;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *t = arg;
+ if (unlikely(UNSET == core->tuner_type))
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
- if (UNSET == core->tuner_type)
- return -EINVAL;
- if (0 != t->index)
- return -EINVAL;
- cx88_set_stereo(core, t->audmode, 1);
- return 0;
- }
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
+ strcpy(t->name, "Television");
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->rangehigh = 0xffffffffUL;
- memset(f,0,sizeof(*f));
+ cx88_get_stereo(core ,t);
+ reg = cx_read(MO_DEVICE_STATUS);
+ t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
+ return 0;
+}
- if (UNSET == core->tuner_type)
- return -EINVAL;
+static int vidioc_s_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
- f->type = radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
- f->frequency = core->freq;
+ if (UNSET == core->tuner_type)
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
- cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
+ cx88_set_stereo(core, t->audmode, 1);
+ return 0;
+}
- return 0;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
-
- if (UNSET == core->tuner_type)
- return -EINVAL;
- if (f->tuner != 0)
- return -EINVAL;
- if (0 == radio && f->type != V4L2_TUNER_ANALOG_TV)
- return -EINVAL;
- if (1 == radio && f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
- mutex_lock(&core->lock);
- core->freq = f->frequency;
- cx88_newstation(core);
- cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);
-
- /* When changing channels it is required to reset TVAUDIO */
- msleep (10);
- cx88_set_tvaudio(core);
+static int vidioc_g_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx8800_fh *fh = priv;
+ struct cx88_core *core = fh->dev->core;
- mutex_unlock(&core->lock);
- return 0;
- }
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- /* ioctls to allow direct acces to the cx2388x registers */
- case VIDIOC_INT_G_REGISTER:
- {
- struct v4l2_register *reg = arg;
+ if (unlikely(UNSET == core->tuner_type))
+ return -EINVAL;
- if (reg->i2c_id != 0)
- return -EINVAL;
- /* cx2388x has a 24-bit register space */
- reg->val = cx_read(reg->reg&0xffffff);
- return 0;
- }
- case VIDIOC_INT_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
+ /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
+ f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+ f->frequency = core->freq;
- if (reg->i2c_id != 0)
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- cx_write(reg->reg&0xffffff, reg->val);
- return 0;
- }
-#endif
+ cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
- default:
- return v4l_compat_translate_ioctl(inode,file,cmd,arg,
- driver_ioctl);
- }
return 0;
}
-static int video_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+int cx88_set_freq (struct cx88_core *core,
+ struct v4l2_frequency *f)
{
- int retval;
+ if (unlikely(UNSET == core->tuner_type))
+ return -EINVAL;
+ if (unlikely(f->tuner != 0))
+ return -EINVAL;
- retval=video_usercopy(inode, file, cmd, arg, video_do_ioctl);
+ mutex_lock(&core->lock);
+ core->freq = f->frequency;
+ cx88_newstation(core);
+ cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);
+
+ /* When changing channels it is required to reset TVAUDIO */
+ msleep (10);
+ cx88_set_tvaudio(core);
- if (video_debug > 1) {
- if (retval < 0) {
- v4l_print_ioctl("cx88(err)", cmd);
- printk(KERN_DEBUG "cx88(err): errcode=%d\n",retval);
- } else if (_IOC_DIR(cmd) & _IOC_READ)
- v4l_printk_ioctl_arg("cx88(r)",cmd, (void *)arg);
- }
+ mutex_unlock(&core->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(cx88_set_freq);
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx8800_fh *fh = priv;
+ struct cx88_core *core = fh->dev->core;
- return retval;
+ if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
+ return -EINVAL;
+ if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
+ return -EINVAL;
+
+ return
+ cx88_set_freq (core,f);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register (struct file *file, void *fh,
+ struct v4l2_register *reg)
+{
+ struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
+
+ if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return -EINVAL;
+ /* cx2388x has a 24-bit register space */
+ reg->val = cx_read(reg->reg&0xffffff);
+ return 0;
}
+static int vidioc_s_register (struct file *file, void *fh,
+ struct v4l2_register *reg)
+{
+ struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
+
+ if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return -EINVAL;
+ cx_write(reg->reg&0xffffff, reg->val);
+ return 0;
+}
+#endif
+
+/* ----------------------------------------------------------- */
+/* RADIO ESPECIFIC IOCTLS */
/* ----------------------------------------------------------- */
-static int radio_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+static int radio_querycap (struct file *file, void *priv,
+ struct v4l2_capability *cap)
{
- struct cx8800_fh *fh = file->private_data;
- struct cx8800_dev *dev = fh->dev;
+ struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev;
struct cx88_core *core = dev->core;
- if (video_debug > 1)
- v4l_print_ioctl(core->name,cmd);
-
- switch (cmd) {
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = arg;
-
- memset(cap,0,sizeof(*cap));
- strcpy(cap->driver, "cx8800");
- strlcpy(cap->card, cx88_boards[core->board].name,
- sizeof(cap->card));
- sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
- cap->version = CX88_VERSION_CODE;
- cap->capabilities = V4L2_CAP_TUNER;
- return 0;
- }
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *t = arg;
+ strcpy(cap->driver, "cx8800");
+ strlcpy(cap->card, cx88_boards[core->board].name,
+ sizeof(cap->card));
+ sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
+ cap->version = CX88_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_TUNER;
+ return 0;
+}
- if (t->index > 0)
- return -EINVAL;
+static int radio_g_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- memset(t,0,sizeof(*t));
- strcpy(t->name, "Radio");
- t->type = V4L2_TUNER_RADIO;
+ if (unlikely(t->index > 0))
+ return -EINVAL;
- cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t);
- return 0;
- }
- case VIDIOC_ENUMINPUT:
- {
- struct v4l2_input *i = arg;
+ strcpy(t->name, "Radio");
+ t->type = V4L2_TUNER_RADIO;
- if (i->index != 0)
- return -EINVAL;
- strcpy(i->name,"Radio");
- i->type = V4L2_INPUT_TYPE_TUNER;
- return 0;
- }
- case VIDIOC_G_INPUT:
- {
- int *i = arg;
- *i = 0;
- return 0;
- }
- case VIDIOC_G_AUDIO:
- {
- struct v4l2_audio *a = arg;
+ cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t);
+ return 0;
+}
- memset(a,0,sizeof(*a));
- strcpy(a->name,"Radio");
- return 0;
- }
- case VIDIOC_G_STD:
- {
- v4l2_std_id *id = arg;
- *id = 0;
- return 0;
- }
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCSTUNER:
- {
- struct video_tuner *v = arg;
+static int radio_enum_input (struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ if (i->index != 0)
+ return -EINVAL;
+ strcpy(i->name,"Radio");
+ i->type = V4L2_INPUT_TYPE_TUNER;
- if (v->tuner) /* Only tuner 0 */
- return -EINVAL;
+ return 0;
+}
- cx88_call_i2c_clients(core,VIDIOCSTUNER,v);
- return 0;
- }
-#endif
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *t = arg;
+static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
+{
+ if (unlikely(a->index))
+ return -EINVAL;
- if (0 != t->index)
- return -EINVAL;
+ memset(a,0,sizeof(*a));
+ strcpy(a->name,"Radio");
+ return 0;
+}
- cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t);
+/* FIXME: Should add a standard for radio */
- return 0;
- }
+static int radio_s_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- case VIDIOC_S_AUDIO:
- case VIDIOC_S_INPUT:
- case VIDIOC_S_STD:
- return 0;
+ if (0 != t->index)
+ return -EINVAL;
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *c = arg;
- int i;
-
- if (c->id < V4L2_CID_BASE ||
- c->id >= V4L2_CID_LASTP1)
- return -EINVAL;
- if (c->id == V4L2_CID_AUDIO_MUTE) {
- for (i = 0; i < CX8800_CTLS; i++)
- if (cx8800_ctls[i].v.id == c->id)
- break;
- *c = cx8800_ctls[i].v;
- } else
- *c = no_ctl;
- return 0;
- }
+ cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t);
+ return 0;
+}
- case VIDIOC_G_CTRL:
- case VIDIOC_S_CTRL:
- case VIDIOC_G_FREQUENCY:
- case VIDIOC_S_FREQUENCY:
- return video_do_ioctl(inode,file,cmd,arg);
+static int radio_s_audio (struct file *file, void *fh,
+ struct v4l2_audio *a)
+{
+ return 0;
+}
- default:
- return v4l_compat_translate_ioctl(inode,file,cmd,arg,
- radio_do_ioctl);
- }
+static int radio_s_input (struct file *file, void *fh, unsigned int i)
+{
return 0;
-};
+}
-static int radio_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int radio_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *c)
{
- return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
-};
+ int i;
+
+ if (c->id < V4L2_CID_BASE ||
+ c->id >= V4L2_CID_LASTP1)
+ return -EINVAL;
+ if (c->id == V4L2_CID_AUDIO_MUTE) {
+ for (i = 0; i < CX8800_CTLS; i++)
+ if (cx8800_ctls[i].v.id == c->id)
+ break;
+ *c = cx8800_ctls[i].v;
+ } else
+ *c = no_ctl;
+ return 0;
+}
/* ----------------------------------------------------------- */
@@ -1816,27 +1638,52 @@ static const struct file_operations video_fops =
.read = video_read,
.poll = video_poll,
.mmap = video_mmap,
- .ioctl = video_ioctl,
+ .ioctl = video_ioctl2,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
+static struct video_device cx8800_vbi_template;
static struct video_device cx8800_video_template =
{
- .name = "cx8800-video",
- .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES,
- .hardware = 0,
- .fops = &video_fops,
- .minor = -1,
-};
-
-static struct video_device cx8800_vbi_template =
-{
- .name = "cx8800-vbi",
- .type = VID_TYPE_TELETEXT|VID_TYPE_TUNER,
- .hardware = 0,
- .fops = &video_fops,
- .minor = -1,
+ .name = "cx8800-video",
+ .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES,
+ .fops = &video_fops,
+ .minor = -1,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
+ .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
+ .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
+ .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
+ .vidioc_g_fmt_vbi = cx8800_vbi_fmt,
+ .vidioc_try_fmt_vbi = cx8800_vbi_fmt,
+ .vidioc_s_fmt_vbi = cx8800_vbi_fmt,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ .vidiocgmbuf = vidiocgmbuf,
+#endif
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
+ .tvnorms = CX88_NORMS,
+ .current_norm = V4L2_STD_NTSC_M,
};
static const struct file_operations radio_fops =
@@ -1844,18 +1691,30 @@ static const struct file_operations radio_fops =
.owner = THIS_MODULE,
.open = video_open,
.release = video_release,
- .ioctl = radio_ioctl,
+ .ioctl = video_ioctl2,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
static struct video_device cx8800_radio_template =
{
- .name = "cx8800-radio",
- .type = VID_TYPE_TUNER,
- .hardware = 0,
- .fops = &radio_fops,
- .minor = -1,
+ .name = "cx8800-radio",
+ .type = VID_TYPE_TUNER,
+ .hardware = 0,
+ .fops = &radio_fops,
+ .minor = -1,
+ .vidioc_querycap = radio_querycap,
+ .vidioc_g_tuner = radio_g_tuner,
+ .vidioc_enum_input = radio_enum_input,
+ .vidioc_g_audio = radio_g_audio,
+ .vidioc_s_tuner = radio_s_tuner,
+ .vidioc_s_audio = radio_s_audio,
+ .vidioc_s_input = radio_s_input,
+ .vidioc_queryctrl = radio_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
};
/* ----------------------------------------------------------- */
@@ -1890,6 +1749,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
{
struct cx8800_dev *dev;
struct cx88_core *core;
+
int err;
dev = kzalloc(sizeof(*dev),GFP_KERNEL);
@@ -1924,9 +1784,15 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
goto fail_core;
}
+ /* Initialize VBI template */
+ memcpy( &cx8800_vbi_template, &cx8800_video_template,
+ sizeof(cx8800_vbi_template) );
+ strcpy(cx8800_vbi_template.name,"cx8800-vbi");
+ cx8800_vbi_template.type = VID_TYPE_TELETEXT|VID_TYPE_TUNER;
+
/* initialize driver struct */
spin_lock_init(&dev->slock);
- core->tvnorm = tvnorms;
+ core->tvnorm = cx8800_video_template.current_norm;
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
@@ -2007,9 +1873,9 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
/* initial device configuration */
mutex_lock(&core->lock);
- cx88_set_tvnorm(core,tvnorms);
+ cx88_set_tvnorm(core,core->tvnorm);
init_controls(core);
- video_mux(core,0);
+ cx88_video_mux(core,0);
mutex_unlock(&core->lock);
/* start tvaudio thread */
@@ -2178,8 +2044,6 @@ static void cx8800_fini(void)
module_init(cx8800_init);
module_exit(cx8800_fini);
-EXPORT_SYMBOL(cx88_do_ioctl);
-
/* ----------------------------------------------------------- */
/*
* Local variables:
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index a9575ad8ca2..a4f7befda5b 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -31,7 +31,9 @@
#include <media/video-buf.h>
#include <media/cx2341x.h>
#include <media/audiochip.h>
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
#include <media/video-buf-dvb.h>
+#endif
#include "btcx-risc.h"
#include "cx88-reg.h"
@@ -50,6 +52,13 @@
/* ----------------------------------------------------------- */
/* defines and enums */
+/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
+#define CX88_NORMS (\
+ V4L2_STD_NTSC_M| V4L2_STD_NTSC_M_JP| V4L2_STD_NTSC_443 | \
+ V4L2_STD_PAL_BG| V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \
+ V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | \
+ V4L2_STD_PAL_60| V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK )
+
#define FORMAT_FLAGS_PACKED 0x01
#define FORMAT_FLAGS_PLANAR 0x02
@@ -82,22 +91,15 @@ enum cx8802_board_access {
/* ----------------------------------------------------------- */
/* tv norms */
-struct cx88_tvnorm {
- char *name;
- v4l2_std_id id;
- u32 cxiformat;
- u32 cxoformat;
-};
-
-static unsigned int inline norm_maxw(struct cx88_tvnorm *norm)
+static unsigned int inline norm_maxw(v4l2_std_id norm)
{
- return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
+ return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
}
-static unsigned int inline norm_maxh(struct cx88_tvnorm *norm)
+static unsigned int inline norm_maxh(v4l2_std_id norm)
{
- return (norm->id & V4L2_STD_625_50) ? 576 : 480;
+ return (norm & V4L2_STD_625_50) ? 576 : 480;
}
/* ----------------------------------------------------------- */
@@ -313,13 +315,15 @@ struct cx88_core {
unsigned int tuner_formats;
/* config info -- dvb */
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
struct dvb_pll_desc *pll_desc;
unsigned int pll_addr;
int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+#endif
/* state info */
struct task_struct *kthread;
- struct cx88_tvnorm *tvnorm;
+ v4l2_std_id tvnorm;
u32 tvaudio;
u32 audiomode_manual;
u32 audiomode_current;
@@ -459,13 +463,16 @@ struct cx8802_dev {
u32 mailbox;
int width;
int height;
+ int fw_size;
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
/* for dvb only */
struct videobuf_dvb dvb;
void* fe_handle;
int (*fe_release)(void *handle);
void *card_priv;
+#endif
/* for switching modulation types */
unsigned char ts_gen_cntrl;
@@ -536,7 +543,7 @@ extern void cx88_sram_channel_dump(struct cx88_core *core,
extern int cx88_set_scale(struct cx88_core *core, unsigned int width,
unsigned int height, enum v4l2_field field);
-extern int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm);
+extern int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm);
extern struct video_device *cx88_vdev_init(struct cx88_core *core,
struct pci_dev *pci,
@@ -553,7 +560,10 @@ extern int cx88_stop_audio_dma(struct cx88_core *core);
/* ----------------------------------------------------------- */
/* cx88-vbi.c */
-void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f);
+/* Can be used as g_vbi_fmt, try_vbi_fmt and s_vbi_fmt */
+int cx8800_vbi_fmt (struct file *file, void *priv,
+ struct v4l2_format *f);
+
/*
int cx8800_start_vbi_dma(struct cx8800_dev *dev,
struct cx88_dmaqueue *q,
@@ -633,19 +643,14 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state);
int cx8802_resume_common(struct pci_dev *pci_dev);
/* ----------------------------------------------------------- */
-/* cx88-video.c */
-extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
- struct cx88_core *core, unsigned int cmd,
- void *arg, v4l2_kioctl driver_ioctl);
+/* cx88-video.c*/
extern const u32 cx88_user_ctrls[];
extern int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl);
-
-/* ----------------------------------------------------------- */
-/* cx88-blackbird.c */
-/* used by cx88-ivtv ioctl emulation layer */
-extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg);
-extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
+int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i);
+int cx88_set_freq (struct cx88_core *core,struct v4l2_frequency *f);
+int cx88_get_control(struct cx88_core *core, struct v4l2_control *ctl);
+int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl);
+int cx88_video_mux(struct cx88_core *core, unsigned int input);
/*
* Local variables:
diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h
index 2e5ca403248..262f98e1240 100644
--- a/drivers/media/video/et61x251/et61x251.h
+++ b/drivers/media/video/et61x251/et61x251.h
@@ -171,10 +171,7 @@ struct et61x251_device {
struct et61x251_device*
et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
{
- if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
- return cam;
-
- return NULL;
+ return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
}
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index 49792ae8c61..a6525513cd1 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -1,7 +1,7 @@
/***************************************************************************
* V4L2 driver for ET61X[12]51 PC Camera Controllers *
* *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* 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 *
@@ -48,8 +48,8 @@
#define ET61X251_MODULE_AUTHOR "(C) 2006 Luca Risolia"
#define ET61X251_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define ET61X251_MODULE_LICENSE "GPL"
-#define ET61X251_MODULE_VERSION "1:1.02"
-#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 2)
+#define ET61X251_MODULE_VERSION "1:1.04"
+#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 4)
/*****************************************************************************/
@@ -85,7 +85,7 @@ MODULE_PARM_DESC(force_munmap,
"\ndetected camera."
"\n 0 = do not force memory unmapping"
"\n 1 = force memory unmapping (save memory)"
- "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
+ "\nDefault value is "__MODULE_STRING(ET61X251_FORCE_MUNMAP)"."
"\n");
static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] =
@@ -133,7 +133,8 @@ et61x251_request_buffers(struct et61x251_device* cam, u32 count,
cam->nbuffers = count;
while (cam->nbuffers > 0) {
- if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+ if ((buff = vmalloc_32_user(cam->nbuffers *
+ PAGE_ALIGN(imagesize))))
break;
cam->nbuffers--;
}
@@ -543,10 +544,11 @@ static int et61x251_start_transfer(struct et61x251_device* cam)
{
struct usb_device *udev = cam->usbdev;
struct urb* urb;
- const unsigned int wMaxPacketSize[] = {0, 256, 384, 512, 640, 768, 832,
- 864, 896, 920, 956, 980, 1000,
- 1022};
- const unsigned int psz = wMaxPacketSize[ET61X251_ALTERNATE_SETTING];
+ struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
+ usb_ifnum_to_if(udev, 0),
+ ET61X251_ALTERNATE_SETTING);
+ const unsigned int psz = le16_to_cpu(altsetting->
+ endpoint[0].desc.wMaxPacketSize);
s8 i, j;
int err = 0;
@@ -976,29 +978,31 @@ static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
static int et61x251_create_sysfs(struct et61x251_device* cam)
{
struct video_device *v4ldev = cam->v4ldev;
- int rc;
+ int err = 0;
+
+ if ((err = video_device_create_file(v4ldev, &class_device_attr_reg)))
+ goto err_out;
+ if ((err = video_device_create_file(v4ldev, &class_device_attr_val)))
+ goto err_reg;
- rc = video_device_create_file(v4ldev, &class_device_attr_reg);
- if (rc) goto err;
- rc = video_device_create_file(v4ldev, &class_device_attr_val);
- if (rc) goto err_reg;
if (cam->sensor.sysfs_ops) {
- rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
- if (rc) goto err_val;
- rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val);
- if (rc) goto err_i2c_reg;
+ if ((err = video_device_create_file(v4ldev,
+ &class_device_attr_i2c_reg)))
+ goto err_val;
+ if ((err = video_device_create_file(v4ldev,
+ &class_device_attr_i2c_val)))
+ goto err_i2c_reg;
}
- return 0;
-
err_i2c_reg:
+ if (cam->sensor.sysfs_ops)
video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
err_val:
video_device_remove_file(v4ldev, &class_device_attr_val);
err_reg:
video_device_remove_file(v4ldev, &class_device_attr_reg);
-err:
- return rc;
+err_out:
+ return err;
}
#endif /* CONFIG_VIDEO_ADV_DEBUG */
@@ -1767,10 +1771,10 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
- if (rect->width < 4)
- rect->width = 4;
- if (rect->height < 4)
- rect->height = 4;
+ if (rect->width < 16)
+ rect->width = 16;
+ if (rect->height < 16)
+ rect->height = 16;
if (rect->width > bounds->width)
rect->width = bounds->width;
if (rect->height > bounds->height)
@@ -1784,8 +1788,8 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
if (rect->top + rect->height > bounds->top + bounds->height)
rect->top = bounds->top+bounds->height - rect->height;
- rect->width &= ~3L;
- rect->height &= ~3L;
+ rect->width &= ~15L;
+ rect->height &= ~15L;
if (ET61X251_PRESERVE_IMGSCALE) {
/* Calculate the actual scaling factor */
@@ -1846,6 +1850,35 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
static int
+et61x251_vidioc_enum_framesizes(struct et61x251_device* cam, void __user * arg)
+{
+ struct v4l2_frmsizeenum frmsize;
+
+ if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
+ return -EFAULT;
+
+ if (frmsize.index != 0)
+ return -EINVAL;
+
+ if (frmsize.pixel_format != V4L2_PIX_FMT_ET61X251 &&
+ frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8)
+ return -EINVAL;
+
+ frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16;
+ frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16;
+ frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width;
+ frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height;
+ memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
+
+ if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+static int
et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg)
{
struct v4l2_fmtdesc fmtd;
@@ -1853,6 +1886,9 @@ et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg)
if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
return -EFAULT;
+ if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
if (fmtd.index == 0) {
strcpy(fmtd.description, "bayer rgb");
fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
@@ -1934,17 +1970,17 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
rect.width = scale * pix->width;
rect.height = scale * pix->height;
- if (rect.width < 4)
- rect.width = 4;
- if (rect.height < 4)
- rect.height = 4;
+ if (rect.width < 16)
+ rect.width = 16;
+ if (rect.height < 16)
+ rect.height = 16;
if (rect.width > bounds->left + bounds->width - rect.left)
rect.width = bounds->left + bounds->width - rect.left;
if (rect.height > bounds->top + bounds->height - rect.top)
rect.height = bounds->top + bounds->height - rect.top;
- rect.width &= ~3L;
- rect.height &= ~3L;
+ rect.width &= ~15L;
+ rect.height &= ~15L;
{ /* adjust the scaling factor */
u32 a, b;
@@ -2378,6 +2414,9 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_S_FMT:
return et61x251_vidioc_try_s_fmt(cam, cmd, arg);
+ case VIDIOC_ENUM_FRAMESIZES:
+ return et61x251_vidioc_enum_framesizes(cam, arg);
+
case VIDIOC_G_JPEGCOMP:
return et61x251_vidioc_g_jpegcomp(cam, arg);
@@ -2413,6 +2452,7 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_QUERYSTD:
case VIDIOC_ENUMSTD:
case VIDIOC_QUERYMENU:
+ case VIDIOC_ENUM_FRAMEINTERVALS:
return -EINVAL;
default:
@@ -2459,6 +2499,7 @@ static const struct file_operations et61x251_fops = {
.open = et61x251_open,
.release = et61x251_release,
.ioctl = et61x251_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.read = et61x251_read,
.poll = et61x251_poll,
.mmap = et61x251_mmap,
@@ -2497,7 +2538,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
mutex_init(&cam->dev_mutex);
DBG(2, "ET61X[12]51 PC Camera Controller detected "
- "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
+ "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
for (i = 0; et61x251_sensor_table[i]; i++) {
err = et61x251_sensor_table[i](cam);
@@ -2550,9 +2591,14 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
#ifdef CONFIG_VIDEO_ADV_DEBUG
err = et61x251_create_sysfs(cam);
- if (err)
- goto fail2;
- DBG(2, "Optional device control through 'sysfs' interface ready");
+ if (!err)
+ DBG(2, "Optional device control through 'sysfs' "
+ "interface ready");
+ else
+ DBG(2, "Failed to create 'sysfs' interface for optional "
+ "device controlling. Error #%d", err);
+#else
+ DBG(2, "Optional device control through 'sysfs' interface disabled");
#endif
usb_set_intfdata(intf, cam);
@@ -2561,13 +2607,6 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
return 0;
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-fail2:
- video_nr[dev_nr] = -1;
- dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
- mutex_unlock(&cam->dev_mutex);
- video_unregister_device(cam->v4ldev);
-#endif
fail:
if (cam) {
kfree(cam->control_buffer);
diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h
index 65edd08dc38..5fadb5de68b 100644
--- a/drivers/media/video/et61x251/et61x251_sensor.h
+++ b/drivers/media/video/et61x251/et61x251_sensor.h
@@ -1,7 +1,7 @@
/***************************************************************************
* API for image sensors connected to ET61X[12]51 PC Camera Controllers *
* *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* 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 *
@@ -82,7 +82,7 @@ enum et61x251_i2c_rsta {
ET61X251_I2C_RSTA_REPEAT = 0x01, /* repeat start */
};
-#define ET61X251_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
+#define ET61X251_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10)
struct et61x251_sensor {
char name[32];
diff --git a/drivers/media/video/et61x251/et61x251_tas5130d1b.c b/drivers/media/video/et61x251/et61x251_tas5130d1b.c
index a7d65b82b2f..b0664340984 100644
--- a/drivers/media/video/et61x251/et61x251_tas5130d1b.c
+++ b/drivers/media/video/et61x251/et61x251_tas5130d1b.c
@@ -2,7 +2,7 @@
* Plug-in for TAS5130D1B image sensor connected to the ET61X[12]51 *
* PC Camera Controllers *
* *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* 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 *
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c
index 122496f3684..379645e481c 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-audio.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c
@@ -31,7 +31,6 @@ struct pvr2_msp3400_handler {
struct pvr2_hdw *hdw;
struct pvr2_i2c_client *client;
struct pvr2_i2c_handler i2c_handler;
- struct pvr2_audio_stat astat;
unsigned long stale_mask;
};
@@ -44,13 +43,6 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt)
pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
- if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
- struct v4l2_tuner vt;
- memset(&vt,0,sizeof(vt));
- vt.audmode = hdw->audiomode_val;
- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_S_TUNER,&vt);
- }
-
route.input = MSP_INPUT_DEFAULT;
route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
switch (hdw->input_val) {
@@ -78,8 +70,7 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt)
static int check_stereo(struct pvr2_msp3400_handler *ctxt)
{
struct pvr2_hdw *hdw = ctxt->hdw;
- return (hdw->input_dirty ||
- hdw->audiomode_dirty);
+ return hdw->input_dirty;
}
@@ -99,8 +90,7 @@ static int msp3400_check(struct pvr2_msp3400_handler *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
msk = 1 << idx;
if (ctxt->stale_mask & msk) continue;
if (msp3400_ops[idx].check(ctxt)) {
@@ -116,8 +106,7 @@ static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
msk = 1 << idx;
if (!(ctxt->stale_mask & msk)) continue;
ctxt->stale_mask &= ~msk;
@@ -126,27 +115,9 @@ static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
}
-/* This reads back the current signal type */
-static int get_audio_status(struct pvr2_msp3400_handler *ctxt)
-{
- struct v4l2_tuner vt;
- int stat;
-
- memset(&vt,0,sizeof(vt));
- stat = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
- if (stat < 0) return stat;
-
- ctxt->hdw->flag_stereo = (vt.audmode & V4L2_TUNER_MODE_STEREO) != 0;
- ctxt->hdw->flag_bilingual =
- (vt.audmode & V4L2_TUNER_MODE_LANG2) != 0;
- return 0;
-}
-
-
static void pvr2_msp3400_detach(struct pvr2_msp3400_handler *ctxt)
{
ctxt->client->handler = NULL;
- ctxt->hdw->audio_stat = NULL;
kfree(ctxt);
}
@@ -169,24 +140,17 @@ static const struct pvr2_i2c_handler_functions msp3400_funcs = {
int pvr2_i2c_msp3400_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
{
struct pvr2_msp3400_handler *ctxt;
- if (hdw->audio_stat) return 0;
if (cp->handler) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
if (!ctxt) return 0;
- memset(ctxt,0,sizeof(*ctxt));
ctxt->i2c_handler.func_data = ctxt;
ctxt->i2c_handler.func_table = &msp3400_funcs;
ctxt->client = cp;
ctxt->hdw = hdw;
- ctxt->astat.ctxt = ctxt;
- ctxt->astat.status = (int (*)(void *))get_audio_status;
- ctxt->astat.detach = (void (*)(void *))pvr2_msp3400_detach;
- ctxt->stale_mask = (1 << (sizeof(msp3400_ops)/
- sizeof(msp3400_ops[0]))) - 1;
+ ctxt->stale_mask = (1 << ARRAY_SIZE(msp3400_ops)) - 1;
cp->handler = &ctxt->i2c_handler;
- hdw->audio_stat = &ctxt->astat;
pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x msp3400 V4L2 handler set up",
cp->client->addr);
return !0;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c
index cf129746205..6bbed88d786 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.c
@@ -83,9 +83,8 @@ struct pvr2_context *pvr2_context_create(
void (*setup_func)(struct pvr2_context *))
{
struct pvr2_context *mp = NULL;
- mp = kmalloc(sizeof(*mp),GFP_KERNEL);
+ mp = kzalloc(sizeof(*mp),GFP_KERNEL);
if (!mp) goto done;
- memset(mp,0,sizeof(*mp));
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp);
mp->setup_func = setup_func;
mutex_init(&mp->mutex);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index c77de859cc8..f569b00201d 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -26,6 +26,27 @@
#include <linux/mutex.h>
+static int pvr2_ctrl_range_check(struct pvr2_ctrl *cptr,int val)
+{
+ if (cptr->info->check_value) {
+ if (!cptr->info->check_value(cptr,val)) return -ERANGE;
+ } else {
+ int lim;
+ lim = cptr->info->def.type_int.min_value;
+ if (cptr->info->get_min_value) {
+ cptr->info->get_min_value(cptr,&lim);
+ }
+ if (val < lim) return -ERANGE;
+ lim = cptr->info->def.type_int.max_value;
+ if (cptr->info->get_max_value) {
+ cptr->info->get_max_value(cptr,&lim);
+ }
+ if (val > lim) return -ERANGE;
+ }
+ return 0;
+}
+
+
/* Set the given control. */
int pvr2_ctrl_set_value(struct pvr2_ctrl *cptr,int val)
{
@@ -43,17 +64,8 @@ int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val)
if (cptr->info->type == pvr2_ctl_bitmask) {
mask &= cptr->info->def.type_bitmask.valid_bits;
} else if (cptr->info->type == pvr2_ctl_int) {
- int lim;
- lim = cptr->info->def.type_int.min_value;
- if (cptr->info->get_min_value) {
- cptr->info->get_min_value(cptr,&lim);
- }
- if (val < lim) break;
- lim = cptr->info->def.type_int.max_value;
- if (cptr->info->get_max_value) {
- cptr->info->get_max_value(cptr,&lim);
- }
- if (val > lim) break;
+ ret = pvr2_ctrl_range_check(cptr,val);
+ if (ret < 0) break;
} else if (cptr->info->type == pvr2_ctl_enum) {
if (val >= cptr->info->def.type_enum.count) {
break;
@@ -498,16 +510,13 @@ int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
LOCK_TAKE(cptr->hdw->big_lock); do {
if (cptr->info->type == pvr2_ctl_int) {
ret = parse_token(ptr,len,valptr,NULL,0);
- if ((ret >= 0) &&
- ((*valptr < cptr->info->def.type_int.min_value) ||
- (*valptr > cptr->info->def.type_int.max_value))) {
- ret = -ERANGE;
+ if (ret >= 0) {
+ ret = pvr2_ctrl_range_check(cptr,*valptr);
}
if (maskptr) *maskptr = ~0;
} else if (cptr->info->type == pvr2_ctl_bool) {
- ret = parse_token(
- ptr,len,valptr,boolNames,
- sizeof(boolNames)/sizeof(boolNames[0]));
+ ret = parse_token(ptr,len,valptr,boolNames,
+ ARRAY_SIZE(boolNames));
if (ret == 1) {
*valptr = *valptr ? !0 : 0;
} else if (ret == 0) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
index 8df969c4874..e8a9252c7df 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -63,6 +63,7 @@ static void set_input(struct pvr2_v4l_cx2584x *ctxt)
vid_input = CX25840_COMPOSITE7;
aud_input = CX25840_AUDIO8;
break;
+ case PVR2_CVAL_INPUT_RADIO: // Treat same as composite
case PVR2_CVAL_INPUT_COMPOSITE:
vid_input = CX25840_COMPOSITE3;
aud_input = CX25840_AUDIO_SERIAL;
@@ -71,7 +72,6 @@ static void set_input(struct pvr2_v4l_cx2584x *ctxt)
vid_input = CX25840_SVIDEO1;
aud_input = CX25840_AUDIO_SERIAL;
break;
- case PVR2_CVAL_INPUT_RADIO:
default:
// Just set it to be composite input for now...
vid_input = CX25840_COMPOSITE3;
@@ -150,8 +150,7 @@ static int decoder_check(struct pvr2_v4l_cx2584x *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
msk = 1 << idx;
if (ctxt->stale_mask & msk) continue;
if (decoder_ops[idx].check(ctxt)) {
@@ -167,8 +166,7 @@ static void decoder_update(struct pvr2_v4l_cx2584x *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
msk = 1 << idx;
if (!(ctxt->stale_mask & msk)) continue;
ctxt->stale_mask &= ~msk;
@@ -199,18 +197,6 @@ static int decoder_detect(struct pvr2_i2c_client *cp)
}
-static int decoder_is_tuned(struct pvr2_v4l_cx2584x *ctxt)
-{
- struct v4l2_tuner vt;
- int ret;
-
- memset(&vt,0,sizeof(vt));
- ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
- if (ret < 0) return -EINVAL;
- return vt.signal ? 1 : 0;
-}
-
-
static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt,
char *buf,unsigned int cnt)
{
@@ -243,21 +229,18 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
if (cp->handler) return 0;
if (!decoder_detect(cp)) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
if (!ctxt) return 0;
- memset(ctxt,0,sizeof(*ctxt));
ctxt->handler.func_data = ctxt;
ctxt->handler.func_table = &hfuncs;
ctxt->ctrl.ctxt = ctxt;
ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
- ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
ctxt->ctrl.force_reset = (void (*)(void*))decoder_reset;
ctxt->client = cp;
ctxt->hdw = hdw;
- ctxt->stale_mask = (1 << (sizeof(decoder_ops)/
- sizeof(decoder_ops[0]))) - 1;
+ ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
hdw->decoder_ctrl = &ctxt->ctrl;
cp->handler = &ctxt->handler;
{
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index f985f00d885..e9da9bb8f8d 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -152,7 +152,7 @@ static unsigned long debugifc_find_mask(const char *buf,unsigned int count)
{
struct debugifc_mask_item *mip;
unsigned int idx;
- for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
mip = mask_items + idx;
if (debugifc_match_keyword(buf,count,mip->name)) {
return mip->msk;
@@ -169,7 +169,7 @@ static int debugifc_print_mask(char *buf,unsigned int sz,
unsigned int idx;
int bcnt = 0;
int ccnt;
- for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
mip = mask_items + idx;
if (!(mip->msk & msk)) continue;
ccnt = scnprintf(buf,sz,"%s%c%s",
diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
index 6cff8e75f42..45cbca0143c 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
@@ -102,9 +102,8 @@ static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw)
}
msg[1].len = pcnt;
msg[1].buf = eeprom+tcnt;
- if ((ret = i2c_transfer(
- &hdw->i2c_adap,
- msg,sizeof(msg)/sizeof(msg[0]))) != 2) {
+ if ((ret = i2c_transfer(&hdw->i2c_adap,
+ msg,ARRAY_SIZE(msg))) != 2) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"eeprom fetch set offs err=%d",ret);
kfree(eeprom);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index c94f97b7939..5786faf9b3b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -26,6 +26,7 @@
#include "pvrusb2-encoder.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
+#include "pvrusb2-fx2-cmd.h"
@@ -34,34 +35,41 @@
#define IVTV_MBOX_DRIVER_DONE 0x00000002
#define IVTV_MBOX_DRIVER_BUSY 0x00000001
+#define MBOX_BASE 0x44
+
static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
+ unsigned int offs,
const u32 *data, unsigned int dlen)
{
- unsigned int idx;
+ unsigned int idx,addr;
+ unsigned int bAddr;
int ret;
- unsigned int offs = 0;
unsigned int chunkCnt;
/*
Format: First byte must be 0x01. Remaining 32 bit words are
- spread out into chunks of 7 bytes each, little-endian ordered,
- offset at zero within each 2 blank bytes following and a
- single byte that is 0x44 plus the offset of the word. Repeat
- request for additional words, with offset adjusted
- accordingly.
+ spread out into chunks of 7 bytes each, with the first 4 bytes
+ being the data word (little endian), and the next 3 bytes
+ being the address where that data word is to be written (big
+ endian). Repeat request for additional words, with offset
+ adjusted accordingly.
*/
while (dlen) {
chunkCnt = 8;
if (chunkCnt > dlen) chunkCnt = dlen;
memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
- hdw->cmd_buffer[0] = 0x01;
+ bAddr = 0;
+ hdw->cmd_buffer[bAddr++] = FX2CMD_MEM_WRITE_DWORD;
for (idx = 0; idx < chunkCnt; idx++) {
- hdw->cmd_buffer[1+(idx*7)+6] = 0x44 + idx + offs;
- PVR2_DECOMPOSE_LE(hdw->cmd_buffer, 1+(idx*7),
- data[idx]);
+ addr = idx + offs;
+ hdw->cmd_buffer[bAddr+6] = (addr & 0xffu);
+ hdw->cmd_buffer[bAddr+5] = ((addr>>8) & 0xffu);
+ hdw->cmd_buffer[bAddr+4] = ((addr>>16) & 0xffu);
+ PVR2_DECOMPOSE_LE(hdw->cmd_buffer, bAddr,data[idx]);
+ bAddr += 7;
}
ret = pvr2_send_request(hdw,
hdw->cmd_buffer,1+(chunkCnt*7),
@@ -76,33 +84,42 @@ static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
}
-static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,int statusFl,
+static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,
+ unsigned int offs,
u32 *data, unsigned int dlen)
{
unsigned int idx;
int ret;
- unsigned int offs = 0;
unsigned int chunkCnt;
/*
Format: First byte must be 0x02 (status check) or 0x28 (read
back block of 32 bit words). Next 6 bytes must be zero,
- followed by a single byte of 0x44+offset for portion to be
- read. Returned data is packed set of 32 bits words that were
- read.
+ followed by a single byte of MBOX_BASE+offset for portion to
+ be read. Returned data is packed set of 32 bits words that
+ were read.
*/
while (dlen) {
chunkCnt = 16;
if (chunkCnt > dlen) chunkCnt = dlen;
- memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
- hdw->cmd_buffer[0] = statusFl ? 0x02 : 0x28;
- hdw->cmd_buffer[7] = 0x44 + offs;
+ if (chunkCnt < 16) chunkCnt = 1;
+ hdw->cmd_buffer[0] =
+ ((chunkCnt == 1) ?
+ FX2CMD_MEM_READ_DWORD : FX2CMD_MEM_READ_64BYTES);
+ hdw->cmd_buffer[1] = 0;
+ hdw->cmd_buffer[2] = 0;
+ hdw->cmd_buffer[3] = 0;
+ hdw->cmd_buffer[4] = 0;
+ hdw->cmd_buffer[5] = ((offs>>16) & 0xffu);
+ hdw->cmd_buffer[6] = ((offs>>8) & 0xffu);
+ hdw->cmd_buffer[7] = (offs & 0xffu);
ret = pvr2_send_request(hdw,
hdw->cmd_buffer,8,
- hdw->cmd_buffer,chunkCnt * 4);
+ hdw->cmd_buffer,
+ (chunkCnt == 1 ? 4 : 16 * 4));
if (ret) return ret;
for (idx = 0; idx < chunkCnt; idx++) {
@@ -129,6 +146,8 @@ static int pvr2_encoder_cmd(void *ctxt,
u32 *argp)
{
unsigned int poll_count;
+ unsigned int try_count = 0;
+ int retry_flag;
int ret = 0;
unsigned int idx;
/* These sizes look to be limited by the FX2 firmware implementation */
@@ -140,14 +159,15 @@ static int pvr2_encoder_cmd(void *ctxt,
/*
The encoder seems to speak entirely using blocks 32 bit words.
- In ivtv driver terms, this is a mailbox which we populate with
- data and watch what the hardware does with it. The first word
- is a set of flags used to control the transaction, the second
- word is the command to execute, the third byte is zero (ivtv
- driver suggests that this is some kind of return value), and
- the fourth byte is a specified timeout (windows driver always
- uses 0x00060000 except for one case when it is zero). All
- successive words are the argument words for the command.
+ In ivtv driver terms, this is a mailbox at MBOX_BASE which we
+ populate with data and watch what the hardware does with it.
+ The first word is a set of flags used to control the
+ transaction, the second word is the command to execute, the
+ third byte is zero (ivtv driver suggests that this is some
+ kind of return value), and the fourth byte is a specified
+ timeout (windows driver always uses 0x00060000 except for one
+ case when it is zero). All successive words are the argument
+ words for the command.
First, write out the entire set of words, with the first word
being zero.
@@ -156,44 +176,42 @@ static int pvr2_encoder_cmd(void *ctxt,
IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which
probably means "go").
- Next, read back 16 words as status. Check the first word,
+ Next, read back the return count words. Check the first word,
which should have IVTV_MBOX_FIRMWARE_DONE set. If however
that bit is not set, then the command isn't done so repeat the
- read.
-
- Next, read back 32 words and compare with the original
- arugments. Hopefully they will match.
+ read until it is set.
Finally, write out just the first word again, but set it to
0x0 this time (which probably means "idle").
*/
- if (arg_cnt_send > (sizeof(wrData)/sizeof(wrData[0]))-4) {
+ if (arg_cnt_send > (ARRAY_SIZE(wrData) - 4)) {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Failed to write cx23416 command"
" - too many input arguments"
- " (was given %u limit %u)",
- arg_cnt_send,
- (unsigned int)(sizeof(wrData)/sizeof(wrData[0])) - 4);
+ " (was given %u limit %lu)",
+ arg_cnt_send, (long unsigned) ARRAY_SIZE(wrData) - 4);
return -EINVAL;
}
- if (arg_cnt_recv > (sizeof(rdData)/sizeof(rdData[0]))-4) {
+ if (arg_cnt_recv > (ARRAY_SIZE(rdData) - 4)) {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Failed to write cx23416 command"
" - too many return arguments"
- " (was given %u limit %u)",
- arg_cnt_recv,
- (unsigned int)(sizeof(rdData)/sizeof(rdData[0])) - 4);
+ " (was given %u limit %lu)",
+ arg_cnt_recv, (long unsigned) ARRAY_SIZE(rdData) - 4);
return -EINVAL;
}
LOCK_TAKE(hdw->ctl_lock); do {
+ retry_flag = 0;
+ try_count++;
+ ret = 0;
wrData[0] = 0;
wrData[1] = cmd;
wrData[2] = 0;
@@ -201,59 +219,74 @@ static int pvr2_encoder_cmd(void *ctxt,
for (idx = 0; idx < arg_cnt_send; idx++) {
wrData[idx+4] = argp[idx];
}
- for (; idx < (sizeof(wrData)/sizeof(wrData[0]))-4; idx++) {
+ for (; idx < ARRAY_SIZE(wrData) - 4; idx++) {
wrData[idx+4] = 0;
}
- ret = pvr2_encoder_write_words(hdw,wrData,idx);
+ ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,idx);
if (ret) break;
wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY;
- ret = pvr2_encoder_write_words(hdw,wrData,1);
+ ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1);
if (ret) break;
poll_count = 0;
while (1) {
- if (poll_count < 10000000) poll_count++;
- ret = pvr2_encoder_read_words(hdw,!0,rdData,1);
- if (ret) break;
+ poll_count++;
+ ret = pvr2_encoder_read_words(hdw,MBOX_BASE,rdData,
+ arg_cnt_recv+4);
+ if (ret) {
+ break;
+ }
if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) {
break;
}
- if (poll_count == 100) {
+ if (rdData[0] && (poll_count < 1000)) continue;
+ if (!rdData[0]) {
+ retry_flag = !0;
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
- "***WARNING*** device's encoder"
- " appears to be stuck"
- " (status=0%08x)",rdData[0]);
+ "Encoder timed out waiting for us"
+ "; arranging to retry");
+ } else {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
- "Encoder command: 0x%02x",cmd);
- for (idx = 4; idx < arg_cnt_send; idx++) {
- pvr2_trace(
- PVR2_TRACE_ERROR_LEGS,
- "Encoder arg%d: 0x%08x",
- idx-3,wrData[idx]);
- }
+ "***WARNING*** device's encoder"
+ " appears to be stuck"
+ " (status=0x%08x)",rdData[0]);
+ }
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Encoder command: 0x%02x",cmd);
+ for (idx = 4; idx < arg_cnt_send; idx++) {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
- "Giving up waiting."
- " It is likely that"
- " this is a bad idea...");
- ret = -EBUSY;
- break;
+ "Encoder arg%d: 0x%08x",
+ idx-3,wrData[idx]);
}
+ ret = -EBUSY;
+ break;
+ }
+ if (retry_flag) {
+ if (try_count < 20) continue;
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Too many retries...");
+ ret = -EBUSY;
+ }
+ if (ret) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Giving up on command."
+ " It is likely that"
+ " this is a bad idea...");
+ break;
}
- if (ret) break;
wrData[0] = 0x7;
- ret = pvr2_encoder_read_words(
- hdw,0,rdData,
- sizeof(rdData)/sizeof(rdData[0]));
- if (ret) break;
for (idx = 0; idx < arg_cnt_recv; idx++) {
argp[idx] = rdData[idx+4];
}
wrData[0] = 0x0;
- ret = pvr2_encoder_write_words(hdw,wrData,1);
+ ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1);
if (ret) break;
} while(0); LOCK_GIVE(hdw->ctl_lock);
@@ -269,13 +302,13 @@ static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
unsigned int idx;
u32 data[12];
- if (args > sizeof(data)/sizeof(data[0])) {
+ if (args > ARRAY_SIZE(data)) {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Failed to write cx23416 command"
" - too many arguments"
- " (was given %u limit %u)",
- args,(unsigned int)(sizeof(data)/sizeof(data[0])));
+ " (was given %u limit %lu)",
+ args, (long unsigned) ARRAY_SIZE(data));
return -EINVAL;
}
@@ -288,6 +321,73 @@ static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
return pvr2_encoder_cmd(hdw,cmd,args,0,data);
}
+
+/* This implements some extra setup for the encoder that seems to be
+ specific to the PVR USB2 hardware. */
+int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
+{
+ int ret = 0;
+ int encMisc3Arg = 0;
+
+#if 0
+ /* This inexplicable bit happens in the Hauppage windows
+ driver (for both 24xxx and 29xxx devices). However I
+ currently see no difference in behavior with or without
+ this stuff. Leave this here as a note of its existence,
+ but don't use it. */
+ LOCK_TAKE(hdw->ctl_lock); do {
+ u32 dat[1];
+ dat[0] = 0x80000640;
+ pvr2_encoder_write_words(hdw,0x01fe,dat,1);
+ pvr2_encoder_write_words(hdw,0x023e,dat,1);
+ } while(0); LOCK_GIVE(hdw->ctl_lock);
+#endif
+
+ /* Mike Isely <isely@pobox.com> 26-Jan-2006 The windows driver
+ sends the following list of ENC_MISC commands (for both
+ 24xxx and 29xxx devices). Meanings are not entirely clear,
+ however without the ENC_MISC(3,1) command then we risk
+ random perpetual video corruption whenever the video input
+ breaks up for a moment (like when switching channels). */
+
+
+#if 0
+ /* This ENC_MISC(5,0) command seems to hurt 29xxx sync
+ performance on channel changes, but is not a problem on
+ 24xxx devices. */
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 5,0,0,0);
+#endif
+
+ /* This ENC_MISC(3,encMisc3Arg) command is critical - without
+ it there will eventually be video corruption. Also, the
+ 29xxx case is strange - the Windows driver is passing 1
+ regardless of device type but if we have 1 for 29xxx device
+ the video turns sluggish. */
+ switch (hdw->hdw_type) {
+ case PVR2_HDW_TYPE_24XXX: encMisc3Arg = 1; break;
+ case PVR2_HDW_TYPE_29XXX: encMisc3Arg = 0; break;
+ default: break;
+ }
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3,
+ encMisc3Arg,0,0);
+
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 8,0,0,0);
+
+#if 0
+ /* This ENC_MISC(4,1) command is poisonous, so it is commented
+ out. But I'm leaving it here anyway to document its
+ existence in the Windows driver. The effect of this
+ command is that apps displaying the stream become sluggish
+ with stuttering video. */
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 4,1,0,0);
+#endif
+
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 0,3,0,0);
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4,15,0,0,0);
+
+ return ret;
+}
+
int pvr2_encoder_configure(struct pvr2_hdw *hdw)
{
int ret;
@@ -302,6 +402,8 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
ret = 0;
+ ret |= pvr2_encoder_prep_config(hdw);
+
if (!ret) ret = pvr2_encoder_vcmd(
hdw,CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
0xf0, 0xf0);
@@ -360,15 +462,22 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000481);
pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
- if (hdw->config == pvr2_config_vbi) {
+ pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1,
+ hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0);
+
+ switch (hdw->config) {
+ case pvr2_config_vbi:
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
0x01,0x14);
- } else if (hdw->config == pvr2_config_mpeg) {
+ break;
+ case pvr2_config_mpeg:
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
0,0x13);
- } else {
+ break;
+ default: /* Unhandled cases for now */
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
0,0x13);
+ break;
}
if (!status) {
hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
@@ -383,15 +492,19 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
/* mask all interrupts */
pvr2_write_register(hdw, 0x0048, 0xffffffff);
- if (hdw->config == pvr2_config_vbi) {
+ switch (hdw->config) {
+ case pvr2_config_vbi:
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
0x01,0x01,0x14);
- } else if (hdw->config == pvr2_config_mpeg) {
+ break;
+ case pvr2_config_mpeg:
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
0x01,0,0x13);
- } else {
+ break;
+ default: /* Unhandled cases for now */
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
0x01,0,0x13);
+ break;
}
/* change some GPIO data */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
new file mode 100644
index 00000000000..ffbc6d09610
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2007 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ * 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
+ *
+ * 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
+ *
+ */
+
+#ifndef _PVRUSB2_FX2_CMD_H_
+#define _PVRUSB2_FX2_CMD_H_
+
+#define FX2CMD_MEM_WRITE_DWORD 0x01
+#define FX2CMD_MEM_READ_DWORD 0x02
+
+#define FX2CMD_MEM_READ_64BYTES 0x28
+
+#define FX2CMD_REG_WRITE 0x04
+#define FX2CMD_REG_READ 0x05
+#define FX2CMD_MEMSEL 0x06
+
+#define FX2CMD_I2C_WRITE 0x08
+#define FX2CMD_I2C_READ 0x09
+
+#define FX2CMD_GET_USB_SPEED 0x0b
+
+#define FX2CMD_STREAMING_ON 0x36
+#define FX2CMD_STREAMING_OFF 0x37
+
+#define FX2CMD_FWPOST1 0x52
+
+#define FX2CMD_POWER_OFF 0xdc
+#define FX2CMD_POWER_ON 0xde
+
+#define FX2CMD_DEEP_RESET 0xdd
+
+#define FX2CMD_GET_EEPROM_ADDR 0xeb
+#define FX2CMD_GET_IR_CODE 0xec
+
+#endif /* _PVRUSB2_FX2_CMD_H_ */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index 34b08fbcc6e..16bd7419960 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -60,6 +60,7 @@ struct pvr2_decoder;
typedef int (*pvr2_ctlf_is_dirty)(struct pvr2_ctrl *);
typedef void (*pvr2_ctlf_clear_dirty)(struct pvr2_ctrl *);
+typedef int (*pvr2_ctlf_check_value)(struct pvr2_ctrl *,int);
typedef int (*pvr2_ctlf_get_value)(struct pvr2_ctrl *,int *);
typedef int (*pvr2_ctlf_set_value)(struct pvr2_ctrl *,int msk,int val);
typedef int (*pvr2_ctlf_val_to_sym)(struct pvr2_ctrl *,int msk,int val,
@@ -83,6 +84,7 @@ struct pvr2_ctl_info {
pvr2_ctlf_get_value get_min_value; /* Get minimum allowed value */
pvr2_ctlf_get_value get_max_value; /* Get maximum allowed value */
pvr2_ctlf_set_value set_value; /* Set its value */
+ pvr2_ctlf_check_value check_value; /* Check that value is valid */
pvr2_ctlf_val_to_sym val_to_sym; /* Custom convert value->symbol */
pvr2_ctlf_sym_to_val sym_to_val; /* Custom convert symbol->value */
pvr2_ctlf_is_dirty is_dirty; /* Return true if dirty */
@@ -135,17 +137,10 @@ struct pvr2_ctrl {
};
-struct pvr2_audio_stat {
- void *ctxt;
- void (*detach)(void *);
- int (*status)(void *);
-};
-
struct pvr2_decoder_ctrl {
void *ctxt;
void (*detach)(void *);
void (*enable)(void *,int);
- int (*tuned)(void *);
void (*force_reset)(void *);
};
@@ -212,7 +207,6 @@ struct pvr2_hdw {
/* Frequency table */
unsigned int freqTable[FREQTABLE_SIZE];
unsigned int freqProgSlot;
- unsigned int freqSlot;
/* Stuff for handling low level control interaction with device */
struct mutex ctl_lock_mutex;
@@ -258,9 +252,17 @@ struct pvr2_hdw {
/* Tuner / frequency control stuff */
unsigned int tuner_type;
int tuner_updated;
- unsigned int freqVal;
+ unsigned int freqValTelevision; /* Current freq for tv mode */
+ unsigned int freqValRadio; /* Current freq for radio mode */
+ unsigned int freqSlotTelevision; /* Current slot for tv mode */
+ unsigned int freqSlotRadio; /* Current slot for radio mode */
+ unsigned int freqSelector; /* 0=radio 1=television */
int freqDirty;
+ /* Current tuner info - this information is polled from the I2C bus */
+ struct v4l2_tuner tuner_signal_info;
+ int tuner_signal_stale;
+
/* Video standard handling */
v4l2_std_id std_mask_eeprom; // Hardware supported selections
v4l2_std_id std_mask_avail; // Which standards we may select from
@@ -281,20 +283,17 @@ struct pvr2_hdw {
int unit_number; /* ID for driver instance */
unsigned long serial_number; /* ID for hardware itself */
- /* Minor number used by v4l logic (yes, this is a hack, as there should
- be no v4l junk here). Probably a better way to do this. */
- int v4l_minor_number;
+ /* Minor numbers used by v4l logic (yes, this is a hack, as there
+ should be no v4l junk here). Probably a better way to do this. */
+ int v4l_minor_number_video;
+ int v4l_minor_number_vbi;
+ int v4l_minor_number_radio;
/* Location of eeprom or a negative number if none */
int eeprom_addr;
enum pvr2_config config;
- /* Information about what audio signal we're hearing */
- int flag_stereo;
- int flag_bilingual;
- struct pvr2_audio_stat *audio_stat;
-
/* Control state needed for cx2341x module */
struct cx2341x_mpeg_params enc_cur_state;
struct cx2341x_mpeg_params enc_ctl_state;
@@ -327,6 +326,9 @@ struct pvr2_hdw {
unsigned int control_cnt;
};
+/* This function gets the current frequency */
+unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *);
+
#endif /* __PVRUSB2_HDW_INTERNAL_H */
/*
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index d2004965187..1ff5138e4bb 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -36,6 +36,10 @@
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-encoder.h"
#include "pvrusb2-debug.h"
+#include "pvrusb2-fx2-cmd.h"
+
+#define TV_MIN_FREQ 55250000L
+#define TV_MAX_FREQ 850000000L
struct usb_device_id pvr2_device_table[] = {
[PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
@@ -71,12 +75,10 @@ static const char *pvr2_client_29xxx[] = {
static struct pvr2_string_table pvr2_client_lists[] = {
[PVR2_HDW_TYPE_29XXX] = {
- pvr2_client_29xxx,
- sizeof(pvr2_client_29xxx)/sizeof(pvr2_client_29xxx[0]),
+ pvr2_client_29xxx, ARRAY_SIZE(pvr2_client_29xxx)
},
[PVR2_HDW_TYPE_24XXX] = {
- pvr2_client_24xxx,
- sizeof(pvr2_client_24xxx)/sizeof(pvr2_client_24xxx[0]),
+ pvr2_client_24xxx, ARRAY_SIZE(pvr2_client_24xxx)
},
};
@@ -160,9 +162,6 @@ static const struct pvr2_mpeg_ids mpeg_ids[] = {
.strid = "video_gop_closure",
.id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
},{
- .strid = "video_pulldown",
- .id = V4L2_CID_MPEG_VIDEO_PULLDOWN,
- },{
.strid = "video_bitrate_mode",
.id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
},{
@@ -212,7 +211,7 @@ static const struct pvr2_mpeg_ids mpeg_ids[] = {
.id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
}
};
-#define MPEGDEF_COUNT (sizeof(mpeg_ids)/sizeof(mpeg_ids[0]))
+#define MPEGDEF_COUNT ARRAY_SIZE(mpeg_ids)
static const char *control_values_srate[] = {
@@ -255,10 +254,10 @@ static const char *control_values_subsystem[] = {
[PVR2_SUBSYS_B_ENC_RUN] = "enc_run",
};
+static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
-static unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw);
static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw);
@@ -272,8 +271,6 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
unsigned int timeout,int probe_fl,
void *write_data,unsigned int write_len,
void *read_data,unsigned int read_len);
-static int pvr2_write_u16(struct pvr2_hdw *hdw, u16 data, int res);
-static int pvr2_write_u8(struct pvr2_hdw *hdw, u8 data, int res);
static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
{
@@ -289,8 +286,21 @@ static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
static int ctrl_channelfreq_set(struct pvr2_ctrl *cptr,int m,int v)
{
struct pvr2_hdw *hdw = cptr->hdw;
- if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) {
- hdw->freqTable[hdw->freqProgSlot-1] = v;
+ unsigned int slotId = hdw->freqProgSlot;
+ if ((slotId > 0) && (slotId <= FREQTABLE_SIZE)) {
+ hdw->freqTable[slotId-1] = v;
+ /* Handle side effects correctly - if we're tuned to this
+ slot, then forgot the slot id relation since the stored
+ frequency has been changed. */
+ if (hdw->freqSelector) {
+ if (hdw->freqSlotRadio == slotId) {
+ hdw->freqSlotRadio = 0;
+ }
+ } else {
+ if (hdw->freqSlotTelevision == slotId) {
+ hdw->freqSlotTelevision = 0;
+ }
+ }
}
return 0;
}
@@ -312,28 +322,32 @@ static int ctrl_channelprog_set(struct pvr2_ctrl *cptr,int m,int v)
static int ctrl_channel_get(struct pvr2_ctrl *cptr,int *vp)
{
- *vp = cptr->hdw->freqSlot;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ *vp = hdw->freqSelector ? hdw->freqSlotRadio : hdw->freqSlotTelevision;
return 0;
}
-static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int v)
+static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int slotId)
{
unsigned freq = 0;
struct pvr2_hdw *hdw = cptr->hdw;
- hdw->freqSlot = v;
- if ((hdw->freqSlot > 0) && (hdw->freqSlot <= FREQTABLE_SIZE)) {
- freq = hdw->freqTable[hdw->freqSlot-1];
- }
- if (freq && (freq != hdw->freqVal)) {
- hdw->freqVal = freq;
- hdw->freqDirty = !0;
+ if ((slotId < 0) || (slotId > FREQTABLE_SIZE)) return 0;
+ if (slotId > 0) {
+ freq = hdw->freqTable[slotId-1];
+ if (!freq) return 0;
+ pvr2_hdw_set_cur_freq(hdw,freq);
+ }
+ if (hdw->freqSelector) {
+ hdw->freqSlotRadio = slotId;
+ } else {
+ hdw->freqSlotTelevision = slotId;
}
return 0;
}
static int ctrl_freq_get(struct pvr2_ctrl *cptr,int *vp)
{
- *vp = cptr->hdw->freqVal;
+ *vp = pvr2_hdw_get_cur_freq(cptr->hdw);
return 0;
}
@@ -349,10 +363,7 @@ static void ctrl_freq_clear_dirty(struct pvr2_ctrl *cptr)
static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v)
{
- struct pvr2_hdw *hdw = cptr->hdw;
- hdw->freqVal = v;
- hdw->freqDirty = !0;
- hdw->freqSlot = 0;
+ pvr2_hdw_set_cur_freq(cptr->hdw,v);
return 0;
}
@@ -378,6 +389,89 @@ static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp)
return 0;
}
+static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->input_val;
+ return 0;
+}
+
+static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
+{
+ struct pvr2_hdw *hdw = cptr->hdw;
+
+ if (hdw->input_val != v) {
+ hdw->input_val = v;
+ hdw->input_dirty = !0;
+ }
+
+ /* Handle side effects - if we switch to a mode that needs the RF
+ tuner, then select the right frequency choice as well and mark
+ it dirty. */
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ hdw->freqSelector = 0;
+ hdw->freqDirty = !0;
+ } else if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
+ hdw->freqSelector = 1;
+ hdw->freqDirty = !0;
+ }
+ return 0;
+}
+
+static int ctrl_isdirty_input(struct pvr2_ctrl *cptr)
+{
+ return cptr->hdw->input_dirty != 0;
+}
+
+static void ctrl_cleardirty_input(struct pvr2_ctrl *cptr)
+{
+ cptr->hdw->input_dirty = 0;
+}
+
+
+static int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp)
+{
+ unsigned long fv;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
+ fv = hdw->tuner_signal_info.rangehigh;
+ if (!fv) {
+ /* Safety fallback */
+ *vp = TV_MAX_FREQ;
+ return 0;
+ }
+ if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+ fv = (fv * 125) / 2;
+ } else {
+ fv = fv * 62500;
+ }
+ *vp = fv;
+ return 0;
+}
+
+static int ctrl_freq_min_get(struct pvr2_ctrl *cptr, int *vp)
+{
+ unsigned long fv;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
+ fv = hdw->tuner_signal_info.rangelow;
+ if (!fv) {
+ /* Safety fallback */
+ *vp = TV_MIN_FREQ;
+ return 0;
+ }
+ if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+ fv = (fv * 125) / 2;
+ } else {
+ fv = fv * 62500;
+ }
+ *vp = fv;
+ return 0;
+}
+
static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
{
return cptr->hdw->enc_stale != 0;
@@ -534,8 +628,32 @@ static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr)
static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp)
{
- *vp = ((pvr2_hdw_get_signal_status_internal(cptr->hdw) &
- PVR2_SIGNAL_OK) ? 1 : 0);
+ struct pvr2_hdw *hdw = cptr->hdw;
+ pvr2_i2c_core_status_poll(hdw);
+ *vp = hdw->tuner_signal_info.signal;
+ return 0;
+}
+
+static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ int val = 0;
+ unsigned int subchan;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ pvr2_i2c_core_status_poll(hdw);
+ subchan = hdw->tuner_signal_info.rxsubchans;
+ if (subchan & V4L2_TUNER_SUB_MONO) {
+ val |= (1 << V4L2_TUNER_MODE_MONO);
+ }
+ if (subchan & V4L2_TUNER_SUB_STEREO) {
+ val |= (1 << V4L2_TUNER_MODE_STEREO);
+ }
+ if (subchan & V4L2_TUNER_SUB_LANG1) {
+ val |= (1 << V4L2_TUNER_MODE_LANG1);
+ }
+ if (subchan & V4L2_TUNER_SUB_LANG2) {
+ val |= (1 << V4L2_TUNER_MODE_LANG2);
+ }
+ *vp = val;
return 0;
}
@@ -604,7 +722,7 @@ static void ctrl_stdenumcur_clear_dirty(struct pvr2_ctrl *cptr)
#define DEFENUM(tab) \
.type = pvr2_ctl_enum, \
- .def.type_enum.count = (sizeof(tab)/sizeof((tab)[0])), \
+ .def.type_enum.count = ARRAY_SIZE(tab), \
.def.type_enum.value_names = tab
#define DEFBOOL \
@@ -641,15 +759,11 @@ VCREATE_FUNCS(balance)
VCREATE_FUNCS(bass)
VCREATE_FUNCS(treble)
VCREATE_FUNCS(mute)
-VCREATE_FUNCS(input)
VCREATE_FUNCS(audiomode)
VCREATE_FUNCS(res_hor)
VCREATE_FUNCS(res_ver)
VCREATE_FUNCS(srate)
-#define MIN_FREQ 55250000L
-#define MAX_FREQ 850000000L
-
/* Table definition of all controls which can be manipulated */
static const struct pvr2_ctl_info control_defs[] = {
{
@@ -684,7 +798,7 @@ static const struct pvr2_ctl_info control_defs[] = {
.v4l_id = V4L2_CID_AUDIO_VOLUME,
.desc = "Volume",
.name = "volume",
- .default_value = 65535,
+ .default_value = 62000,
DEFREF(volume),
DEFINT(0,65535),
},{
@@ -758,12 +872,16 @@ static const struct pvr2_ctl_info control_defs[] = {
.desc = "Tuner Frequency (Hz)",
.name = "frequency",
.internal_id = PVR2_CID_FREQUENCY,
- .default_value = 175250000L,
+ .default_value = 0,
.set_value = ctrl_freq_set,
.get_value = ctrl_freq_get,
.is_dirty = ctrl_freq_is_dirty,
.clear_dirty = ctrl_freq_clear_dirty,
- DEFINT(MIN_FREQ,MAX_FREQ),
+ DEFINT(0,0),
+ /* Hook in check for input value (tv/radio) and adjust
+ max/min values accordingly */
+ .get_max_value = ctrl_freq_max_get,
+ .get_min_value = ctrl_freq_min_get,
},{
.desc = "Channel",
.name = "channel",
@@ -775,7 +893,11 @@ static const struct pvr2_ctl_info control_defs[] = {
.name = "freq_table_value",
.set_value = ctrl_channelfreq_set,
.get_value = ctrl_channelfreq_get,
- DEFINT(MIN_FREQ,MAX_FREQ),
+ DEFINT(0,0),
+ /* Hook in check for input value (tv/radio) and adjust
+ max/min values accordingly */
+ .get_max_value = ctrl_freq_max_get,
+ .get_min_value = ctrl_freq_min_get,
},{
.desc = "Channel Program ID",
.name = "freq_table_channel",
@@ -796,7 +918,20 @@ static const struct pvr2_ctl_info control_defs[] = {
.desc = "Signal Present",
.name = "signal_present",
.get_value = ctrl_signal_get,
- DEFBOOL,
+ DEFINT(0,65535),
+ },{
+ .desc = "Audio Modes Present",
+ .name = "audio_modes_present",
+ .get_value = ctrl_audio_modes_present_get,
+ /* For this type we "borrow" the V4L2_TUNER_MODE enum from
+ v4l. Nothing outside of this module cares about this,
+ but I reuse it in order to also reuse the
+ control_values_audiomode string table. */
+ DEFMASK(((1 << V4L2_TUNER_MODE_MONO)|
+ (1 << V4L2_TUNER_MODE_STEREO)|
+ (1 << V4L2_TUNER_MODE_LANG1)|
+ (1 << V4L2_TUNER_MODE_LANG2)),
+ control_values_audiomode),
},{
.desc = "Video Standards Available Mask",
.name = "video_standard_mask_available",
@@ -846,7 +981,7 @@ static const struct pvr2_ctl_info control_defs[] = {
}
};
-#define CTRLDEF_COUNT (sizeof(control_defs)/sizeof(control_defs[0]))
+#define CTRLDEF_COUNT ARRAY_SIZE(control_defs)
const char *pvr2_config_get_name(enum pvr2_config cfg)
@@ -855,7 +990,8 @@ const char *pvr2_config_get_name(enum pvr2_config cfg)
case pvr2_config_empty: return "empty";
case pvr2_config_mpeg: return "mpeg";
case pvr2_config_vbi: return "vbi";
- case pvr2_config_radio: return "radio";
+ case pvr2_config_pcm: return "pcm";
+ case pvr2_config_rawvideo: return "raw video";
}
return "<unknown>";
}
@@ -872,6 +1008,40 @@ unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw)
return hdw->serial_number;
}
+unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw)
+{
+ return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio;
+}
+
+/* Set the currently tuned frequency and account for all possible
+ driver-core side effects of this action. */
+void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val)
+{
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ if (hdw->freqSelector) {
+ /* Swing over to radio frequency selection */
+ hdw->freqSelector = 0;
+ hdw->freqDirty = !0;
+ }
+ if (hdw->freqValRadio != val) {
+ hdw->freqValRadio = val;
+ hdw->freqSlotRadio = 0;
+ hdw->freqDirty = !0;
+ }
+ } else {
+ if (!(hdw->freqSelector)) {
+ /* Swing over to television frequency selection */
+ hdw->freqSelector = 1;
+ hdw->freqDirty = !0;
+ }
+ if (hdw->freqValTelevision != val) {
+ hdw->freqValTelevision = val;
+ hdw->freqSlotTelevision = 0;
+ hdw->freqDirty = !0;
+ }
+ }
+}
+
int pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw)
{
return hdw->unit_number;
@@ -960,12 +1130,10 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
};
static const struct pvr2_string_table fw_file_defs[] = {
[PVR2_HDW_TYPE_29XXX] = {
- fw_files_29xxx,
- sizeof(fw_files_29xxx)/sizeof(fw_files_29xxx[0]),
+ fw_files_29xxx, ARRAY_SIZE(fw_files_29xxx)
},
[PVR2_HDW_TYPE_24XXX] = {
- fw_files_24xxx,
- sizeof(fw_files_24xxx)/sizeof(fw_files_24xxx[0]),
+ fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx)
},
};
hdw->fw1_state = FW1_STATE_FAILED; // default result
@@ -1041,7 +1209,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
{
const struct firmware *fw_entry = NULL;
void *fw_ptr;
- unsigned int pipe, fw_len, fw_done;
+ unsigned int pipe, fw_len, fw_done, bcnt, icnt;
int actual_length;
int ret = 0;
int fwidx;
@@ -1052,8 +1220,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
trace_firmware("pvr2_upload_firmware2");
ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder",
- sizeof(fw_files)/sizeof(fw_files[0]),
- fw_files);
+ ARRAY_SIZE(fw_files), fw_files);
if (ret < 0) return ret;
fwidx = ret;
ret = 0;
@@ -1079,8 +1246,13 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/
ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/
ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/
- ret |= pvr2_write_u8(hdw, 0x52, 0);
- ret |= pvr2_write_u16(hdw, 0x0600, 0);
+ LOCK_TAKE(hdw->ctl_lock); do {
+ hdw->cmd_buffer[0] = FX2CMD_FWPOST1;
+ ret |= pvr2_send_request(hdw,hdw->cmd_buffer,1,0,0);
+ hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
+ hdw->cmd_buffer[1] = 0;
+ ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,0,0);
+ } while (0); LOCK_GIVE(hdw->ctl_lock);
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
@@ -1093,11 +1265,11 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
fw_len = fw_entry->size;
- if (fw_len % FIRMWARE_CHUNK_SIZE) {
+ if (fw_len % sizeof(u32)) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"size of %s firmware"
- " must be a multiple of 8192B",
- fw_files[fwidx]);
+ " must be a multiple of %zu bytes",
+ fw_files[fwidx],sizeof(u32));
release_firmware(fw_entry);
return -1;
}
@@ -1112,18 +1284,21 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT);
- for (fw_done = 0 ; (fw_done < fw_len) && !ret ;
- fw_done += FIRMWARE_CHUNK_SIZE ) {
- int i;
- memcpy(fw_ptr, fw_entry->data + fw_done, FIRMWARE_CHUNK_SIZE);
- /* Usbsnoop log shows that we must swap bytes... */
- for (i = 0; i < FIRMWARE_CHUNK_SIZE/4 ; i++)
- ((u32 *)fw_ptr)[i] = ___swab32(((u32 *)fw_ptr)[i]);
-
- ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,
- FIRMWARE_CHUNK_SIZE,
+ fw_done = 0;
+ for (fw_done = 0; fw_done < fw_len;) {
+ bcnt = fw_len - fw_done;
+ if (bcnt > FIRMWARE_CHUNK_SIZE) bcnt = FIRMWARE_CHUNK_SIZE;
+ memcpy(fw_ptr, fw_entry->data + fw_done, bcnt);
+ /* Usbsnoop log shows that we must swap bytes... */
+ for (icnt = 0; icnt < bcnt/4 ; icnt++)
+ ((u32 *)fw_ptr)[icnt] =
+ ___swab32(((u32 *)fw_ptr)[icnt]);
+
+ ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,bcnt,
&actual_length, HZ);
- ret |= (actual_length != FIRMWARE_CHUNK_SIZE);
+ ret |= (actual_length != bcnt);
+ if (ret) break;
+ fw_done += bcnt;
}
trace_firmware("upload of %s : %i / %i ",
@@ -1142,7 +1317,11 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/
ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/
- ret |= pvr2_write_u16(hdw, 0x0600, 0);
+ LOCK_TAKE(hdw->ctl_lock); do {
+ hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
+ hdw->cmd_buffer[1] = 0;
+ ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,0,0);
+ } while (0); LOCK_GIVE(hdw->ctl_lock);
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
@@ -1479,7 +1658,7 @@ static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw)
firmware needs be loaded. */
int result;
LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = 0xeb;
+ hdw->cmd_buffer[0] = FX2CMD_GET_EEPROM_ADDR;
result = pvr2_send_request_ex(hdw,HZ*1,!0,
hdw->cmd_buffer,1,
hdw->cmd_buffer,1);
@@ -1611,6 +1790,16 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
cptr->info->set_value(cptr,~0,cptr->info->default_value);
}
+ /* Set up special default values for the television and radio
+ frequencies here. It's not really important what these defaults
+ are, but I set them to something usable in the Chicago area just
+ to make driver testing a little easier. */
+
+ /* US Broadcast channel 7 (175.25 MHz) */
+ hdw->freqValTelevision = 175250000L;
+ /* 104.3 MHz, a usable FM station for my area */
+ hdw->freqValRadio = 104300000L;
+
// Do not use pvr2_reset_ctl_endpoints() here. It is not
// thread-safe against the normal pvr2_send_request() mechanism.
// (We should make it thread safe).
@@ -1750,26 +1939,24 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
struct pvr2_ctl_info *ciptr;
hdw_type = devid - pvr2_device_table;
- if (hdw_type >=
- sizeof(pvr2_device_names)/sizeof(pvr2_device_names[0])) {
+ if (hdw_type >= ARRAY_SIZE(pvr2_device_names)) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"Bogus device type of %u reported",hdw_type);
return NULL;
}
- hdw = kmalloc(sizeof(*hdw),GFP_KERNEL);
+ hdw = kzalloc(sizeof(*hdw),GFP_KERNEL);
pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
hdw,pvr2_device_names[hdw_type]);
if (!hdw) goto fail;
- memset(hdw,0,sizeof(*hdw));
+ hdw->tuner_signal_stale = !0;
cx2341x_fill_defaults(&hdw->enc_ctl_state);
hdw->control_cnt = CTRLDEF_COUNT;
hdw->control_cnt += MPEGDEF_COUNT;
- hdw->controls = kmalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
+ hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
GFP_KERNEL);
if (!hdw->controls) goto fail;
- memset(hdw->controls,0,sizeof(struct pvr2_ctrl) * hdw->control_cnt);
hdw->hdw_type = hdw_type;
for (idx = 0; idx < hdw->control_cnt; idx++) {
cptr = hdw->controls + idx;
@@ -1783,11 +1970,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
cptr->info = control_defs+idx;
}
/* Define and configure additional controls from cx2341x module. */
- hdw->mpeg_ctrl_info = kmalloc(
+ hdw->mpeg_ctrl_info = kzalloc(
sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL);
if (!hdw->mpeg_ctrl_info) goto fail;
- memset(hdw->mpeg_ctrl_info,0,
- sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT);
for (idx = 0; idx < MPEGDEF_COUNT; idx++) {
cptr = hdw->controls + idx + CTRLDEF_COUNT;
ciptr = &(hdw->mpeg_ctrl_info[idx].info);
@@ -1872,7 +2057,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
hdw->eeprom_addr = -1;
hdw->unit_number = -1;
- hdw->v4l_minor_number = -1;
+ hdw->v4l_minor_number_video = -1;
+ hdw->v4l_minor_number_vbi = -1;
+ hdw->v4l_minor_number_radio = -1;
hdw->ctl_write_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
if (!hdw->ctl_write_buffer) goto fail;
hdw->ctl_read_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
@@ -1929,10 +2116,10 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
if (hdw) {
usb_free_urb(hdw->ctl_read_urb);
usb_free_urb(hdw->ctl_write_urb);
- if (hdw->ctl_read_buffer) kfree(hdw->ctl_read_buffer);
- if (hdw->ctl_write_buffer) kfree(hdw->ctl_write_buffer);
- if (hdw->controls) kfree(hdw->controls);
- if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
+ kfree(hdw->ctl_read_buffer);
+ kfree(hdw->ctl_write_buffer);
+ kfree(hdw->controls);
+ kfree(hdw->mpeg_ctrl_info);
kfree(hdw);
}
return NULL;
@@ -1982,9 +2169,6 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
pvr2_stream_destroy(hdw->vid_stream);
hdw->vid_stream = NULL;
}
- if (hdw->audio_stat) {
- hdw->audio_stat->detach(hdw->audio_stat->ctxt);
- }
if (hdw->decoder_ctrl) {
hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
}
@@ -1997,10 +2181,10 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
unit_pointers[hdw->unit_number] = NULL;
}
} while (0); up(&pvr2_unit_sem);
- if (hdw->controls) kfree(hdw->controls);
- if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
- if (hdw->std_defs) kfree(hdw->std_defs);
- if (hdw->std_enum_names) kfree(hdw->std_enum_names);
+ kfree(hdw->controls);
+ kfree(hdw->mpeg_ctrl_info);
+ kfree(hdw->std_defs);
+ kfree(hdw->std_enum_names);
kfree(hdw);
}
@@ -2210,10 +2394,9 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
cptr = hdw->controls + idx;
if (cptr->info->is_dirty == 0) continue;
if (!cptr->info->is_dirty(cptr)) continue;
- if (!commit_flag) {
- commit_flag = !0;
- }
+ commit_flag = !0;
+ if (!(pvrusb2_debug & PVR2_TRACE_CTL)) continue;
bcnt = scnprintf(buf,sizeof(buf),"\"%s\" <-- ",
cptr->info->name);
value = 0;
@@ -2263,6 +2446,13 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
}
+ if (hdw->input_dirty) {
+ /* pk: If input changes to or from radio, then the encoder
+ needs to be restarted (for ENC_MUTE_VIDEO to work) */
+ stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
+ }
+
+
if (hdw->srate_dirty) {
/* Write new sample rate into control structure since
* the master copy is stale. We must track srate
@@ -2343,39 +2533,11 @@ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
}
-/* Return bit mask indicating signal status */
-static unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw)
-{
- unsigned int msk = 0;
- switch (hdw->input_val) {
- case PVR2_CVAL_INPUT_TV:
- case PVR2_CVAL_INPUT_RADIO:
- if (hdw->decoder_ctrl &&
- hdw->decoder_ctrl->tuned(hdw->decoder_ctrl->ctxt)) {
- msk |= PVR2_SIGNAL_OK;
- if (hdw->audio_stat &&
- hdw->audio_stat->status(hdw->audio_stat->ctxt)) {
- if (hdw->flag_stereo) {
- msk |= PVR2_SIGNAL_STEREO;
- }
- if (hdw->flag_bilingual) {
- msk |= PVR2_SIGNAL_SAP;
- }
- }
- }
- break;
- default:
- msk |= PVR2_SIGNAL_OK | PVR2_SIGNAL_STEREO;
- }
- return msk;
-}
-
-
int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
{
int result;
LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = 0x0b;
+ hdw->cmd_buffer[0] = FX2CMD_GET_USB_SPEED;
result = pvr2_send_request(hdw,
hdw->cmd_buffer,1,
hdw->cmd_buffer,1);
@@ -2386,14 +2548,25 @@ int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
}
-/* Return bit mask indicating signal status */
-unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *hdw)
+/* Execute poll of tuner status */
+void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw)
{
- unsigned int msk = 0;
LOCK_TAKE(hdw->big_lock); do {
- msk = pvr2_hdw_get_signal_status_internal(hdw);
+ pvr2_i2c_core_status_poll(hdw);
} while (0); LOCK_GIVE(hdw->big_lock);
- return msk;
+}
+
+
+/* Return information about the tuner */
+int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp)
+{
+ LOCK_TAKE(hdw->big_lock); do {
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
+ memcpy(vtp,&hdw->tuner_signal_info,sizeof(struct v4l2_tuner));
+ } while (0); LOCK_GIVE(hdw->big_lock);
+ return 0;
}
@@ -2442,14 +2615,12 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
pvr2_trace(PVR2_TRACE_FIRMWARE,
"Preparing to suck out CPU firmware");
hdw->fw_size = 0x2000;
- hdw->fw_buffer = kmalloc(hdw->fw_size,GFP_KERNEL);
+ hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL);
if (!hdw->fw_buffer) {
hdw->fw_size = 0;
break;
}
- memset(hdw->fw_buffer,0,hdw->fw_size);
-
/* We have to hold the CPU during firmware upload. */
pvr2_hdw_cpureset_assert(hdw,1);
@@ -2513,16 +2684,28 @@ int pvr2_hdw_cpufw_get(struct pvr2_hdw *hdw,unsigned int offs,
}
-int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw)
+int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw,
+ enum pvr2_v4l_type index)
{
- return hdw->v4l_minor_number;
+ switch (index) {
+ case pvr2_v4l_type_video: return hdw->v4l_minor_number_video;
+ case pvr2_v4l_type_vbi: return hdw->v4l_minor_number_vbi;
+ case pvr2_v4l_type_radio: return hdw->v4l_minor_number_radio;
+ default: return -1;
+ }
}
-/* Store the v4l minor device number */
-void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw,int v)
+/* Store a v4l minor device number */
+void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw,
+ enum pvr2_v4l_type index,int v)
{
- hdw->v4l_minor_number = v;
+ switch (index) {
+ case pvr2_v4l_type_video: hdw->v4l_minor_number_video = v;
+ case pvr2_v4l_type_vbi: hdw->v4l_minor_number_vbi = v;
+ case pvr2_v4l_type_radio: hdw->v4l_minor_number_radio = v;
+ default: break;
+ }
}
@@ -2804,7 +2987,7 @@ int pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data)
LOCK_TAKE(hdw->ctl_lock);
- hdw->cmd_buffer[0] = 0x04; /* write register prefix */
+ hdw->cmd_buffer[0] = FX2CMD_REG_WRITE; /* write register prefix */
PVR2_DECOMPOSE_LE(hdw->cmd_buffer,1,data);
hdw->cmd_buffer[5] = 0;
hdw->cmd_buffer[6] = (reg >> 8) & 0xff;
@@ -2825,7 +3008,7 @@ static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
LOCK_TAKE(hdw->ctl_lock);
- hdw->cmd_buffer[0] = 0x05; /* read register prefix */
+ hdw->cmd_buffer[0] = FX2CMD_REG_READ; /* read register prefix */
hdw->cmd_buffer[1] = 0;
hdw->cmd_buffer[2] = 0;
hdw->cmd_buffer[3] = 0;
@@ -2843,39 +3026,6 @@ static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
}
-static int pvr2_write_u16(struct pvr2_hdw *hdw, u16 data, int res)
-{
- int ret;
-
- LOCK_TAKE(hdw->ctl_lock);
-
- hdw->cmd_buffer[0] = (data >> 8) & 0xff;
- hdw->cmd_buffer[1] = data & 0xff;
-
- ret = pvr2_send_request(hdw, hdw->cmd_buffer, 2, hdw->cmd_buffer, res);
-
- LOCK_GIVE(hdw->ctl_lock);
-
- return ret;
-}
-
-
-static int pvr2_write_u8(struct pvr2_hdw *hdw, u8 data, int res)
-{
- int ret;
-
- LOCK_TAKE(hdw->ctl_lock);
-
- hdw->cmd_buffer[0] = data;
-
- ret = pvr2_send_request(hdw, hdw->cmd_buffer, 1, hdw->cmd_buffer, res);
-
- LOCK_GIVE(hdw->ctl_lock);
-
- return ret;
-}
-
-
static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw)
{
if (!hdw->flag_ok) return;
@@ -2949,7 +3099,7 @@ int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
LOCK_TAKE(hdw->ctl_lock); do {
pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset");
hdw->flag_ok = !0;
- hdw->cmd_buffer[0] = 0xdd;
+ hdw->cmd_buffer[0] = FX2CMD_DEEP_RESET;
status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
} while (0); LOCK_GIVE(hdw->ctl_lock);
return status;
@@ -2961,7 +3111,7 @@ int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw)
int status;
LOCK_TAKE(hdw->ctl_lock); do {
pvr2_trace(PVR2_TRACE_INIT,"Requesting powerup");
- hdw->cmd_buffer[0] = 0xde;
+ hdw->cmd_buffer[0] = FX2CMD_POWER_ON;
status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
} while (0); LOCK_GIVE(hdw->ctl_lock);
return status;
@@ -2994,7 +3144,8 @@ static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
{
int status;
LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = (runFl ? 0x36 : 0x37);
+ hdw->cmd_buffer[0] =
+ (runFl ? FX2CMD_STREAMING_ON : FX2CMD_STREAMING_OFF);
status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
} while (0); LOCK_GIVE(hdw->ctl_lock);
if (!status) {
@@ -3093,7 +3244,7 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
{
int result;
LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = 0xeb;
+ hdw->cmd_buffer[0] = FX2CMD_GET_EEPROM_ADDR;
result = pvr2_send_request(hdw,
hdw->cmd_buffer,1,
hdw->cmd_buffer,1);
@@ -3105,8 +3256,8 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
- u32 chip_id,unsigned long reg_id,
- int setFl,u32 *val_ptr)
+ u32 match_type, u32 match_chip, u64 reg_id,
+ int setFl,u64 *val_ptr)
{
#ifdef CONFIG_VIDEO_ADV_DEBUG
struct list_head *item;
@@ -3115,16 +3266,21 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
int stat = 0;
int okFl = 0;
- req.i2c_id = chip_id;
+ if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+
+ req.match_type = match_type;
+ req.match_chip = match_chip;
req.reg = reg_id;
if (setFl) req.val = *val_ptr;
mutex_lock(&hdw->i2c_list_lock); do {
list_for_each(item,&hdw->i2c_clients) {
cp = list_entry(item,struct pvr2_i2c_client,list);
- if (cp->client->driver->id != chip_id) continue;
+ if (!v4l2_chip_match_i2c_client(cp->client, req.match_type, req.match_chip)) {
+ continue;
+ }
stat = pvr2_i2c_client_cmd(
- cp,(setFl ? VIDIOC_INT_S_REGISTER :
- VIDIOC_INT_G_REGISTER),&req);
+ cp,(setFl ? VIDIOC_DBG_S_REGISTER :
+ VIDIOC_DBG_G_REGISTER),&req);
if (!setFl) *val_ptr = req.val;
okFl = !0;
break;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 29979bb2a76..0c9cca43ff8 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -44,12 +44,6 @@
#define PVR2_CVAL_INPUT_COMPOSITE 2
#define PVR2_CVAL_INPUT_RADIO 3
-/* Values that pvr2_hdw_get_signal_status() returns */
-#define PVR2_SIGNAL_OK 0x0001
-#define PVR2_SIGNAL_STEREO 0x0002
-#define PVR2_SIGNAL_SAP 0x0004
-
-
/* Subsystem definitions - these are various pieces that can be
independently stopped / started. Usually you don't want to mess with
this directly (let the driver handle things itself), but it is useful
@@ -72,10 +66,17 @@
PVR2_SUBSYS_RUN_ALL )
enum pvr2_config {
- pvr2_config_empty,
- pvr2_config_mpeg,
- pvr2_config_vbi,
- pvr2_config_radio,
+ pvr2_config_empty, /* No configuration */
+ pvr2_config_mpeg, /* Encoded / compressed video */
+ pvr2_config_vbi, /* Standard vbi info */
+ pvr2_config_pcm, /* Audio raw pcm stream */
+ pvr2_config_rawvideo, /* Video raw frames */
+};
+
+enum pvr2_v4l_type {
+ pvr2_v4l_type_video,
+ pvr2_v4l_type_vbi,
+ pvr2_v4l_type_radio,
};
const char *pvr2_config_get_name(enum pvr2_config);
@@ -148,8 +149,11 @@ int pvr2_hdw_commit_ctl(struct pvr2_hdw *);
/* Return name for this driver instance */
const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *);
-/* Return PVR2_SIGNAL_XXXX bit mask indicating signal status */
-unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *);
+/* Mark tuner status stale so that it will be re-fetched */
+void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *);
+
+/* Return information about the tuner */
+int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *);
/* Query device and see if it thinks it is on a high-speed USB link */
int pvr2_hdw_is_hsm(struct pvr2_hdw *);
@@ -205,20 +209,22 @@ int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *);
int pvr2_hdw_cpufw_get(struct pvr2_hdw *,unsigned int offs,
char *buf,unsigned int cnt);
-/* Retrieve previously stored v4l minor device number */
-int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *);
+/* Retrieve a previously stored v4l minor device number */
+int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *,enum pvr2_v4l_type index);
-/* Store the v4l minor device number */
-void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,int);
+/* Store a v4l minor device number */
+void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,
+ enum pvr2_v4l_type index,int);
/* Direct read/write access to chip's registers:
- chip_id - unique id of chip (e.g. I2C_DRIVERD_xxxx)
+ match_type - how to interpret match_chip (e.g. driver ID, i2c address)
+ match_chip - chip match value (e.g. I2C_DRIVERD_xxxx)
reg_id - register number to access
setFl - true to set the register, false to read it
val_ptr - storage location for source / result. */
int pvr2_hdw_register_access(struct pvr2_hdw *,
- u32 chip_id,unsigned long reg_id,
- int setFl,u32 *val_ptr);
+ u32 match_type, u32 match_chip,u64 reg_id,
+ int setFl,u64 *val_ptr);
/* The following entry points are all lower level things you normally don't
want to worry about. */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
index 05121666b9b..49773764383 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
@@ -33,15 +33,17 @@
#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
#define OP_STANDARD 0
-#define OP_BCSH 1
-#define OP_VOLUME 2
-#define OP_FREQ 3
-#define OP_AUDIORATE 4
-#define OP_SIZE 5
-#define OP_LOG 6
+#define OP_AUDIOMODE 1
+#define OP_BCSH 2
+#define OP_VOLUME 3
+#define OP_FREQ 4
+#define OP_AUDIORATE 5
+#define OP_SIZE 6
+#define OP_LOG 7
static const struct pvr2_i2c_op * const ops[] = {
[OP_STANDARD] = &pvr2_i2c_op_v4l2_standard,
+ [OP_AUDIOMODE] = &pvr2_i2c_op_v4l2_audiomode,
[OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh,
[OP_VOLUME] = &pvr2_i2c_op_v4l2_volume,
[OP_FREQ] = &pvr2_i2c_op_v4l2_frequency,
@@ -54,11 +56,13 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
int id;
id = cp->client->driver->id;
cp->ctl_mask = ((1 << OP_STANDARD) |
+ (1 << OP_AUDIOMODE) |
(1 << OP_BCSH) |
(1 << OP_VOLUME) |
(1 << OP_FREQ) |
(1 << OP_SIZE) |
(1 << OP_LOG));
+ cp->status_poll = pvr2_v4l2_cmd_status_poll;
if (id == I2C_DRIVERID_MSP3400) {
if (pvr2_i2c_msp3400_setup(hdw,cp)) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
index 05ea17afe90..c650e02ccd0 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
@@ -24,22 +24,26 @@
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
#include <linux/videodev2.h>
-
+#include <media/v4l2-common.h>
static void set_standard(struct pvr2_hdw *hdw)
{
- v4l2_std_id vs;
- vs = hdw->std_mask_cur;
- pvr2_trace(PVR2_TRACE_CHIPS,
- "i2c v4l2 set_standard(0x%llx)",(long long unsigned)vs);
-
- pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_standard");
+
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ pvr2_i2c_core_cmd(hdw,AUDC_SET_RADIO,NULL);
+ } else {
+ v4l2_std_id vs;
+ vs = hdw->std_mask_cur;
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
+ }
+ hdw->tuner_signal_stale = !0;
}
static int check_standard(struct pvr2_hdw *hdw)
{
- return hdw->std_dirty != 0;
+ return (hdw->input_dirty != 0) || (hdw->std_dirty != 0);
}
@@ -136,16 +140,53 @@ const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume = {
};
+static void set_audiomode(struct pvr2_hdw *hdw)
+{
+ struct v4l2_tuner vt;
+ memset(&vt,0,sizeof(vt));
+ vt.audmode = hdw->audiomode_val;
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_TUNER,&vt);
+}
+
+
+static int check_audiomode(struct pvr2_hdw *hdw)
+{
+ return (hdw->input_dirty ||
+ hdw->audiomode_dirty);
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode = {
+ .check = check_audiomode,
+ .update = set_audiomode,
+ .name = "v4l2_audiomode",
+};
+
+
static void set_frequency(struct pvr2_hdw *hdw)
{
unsigned long fv;
struct v4l2_frequency freq;
- fv = hdw->freqVal;
+ fv = pvr2_hdw_get_cur_freq(hdw);
pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_freq(%lu)",fv);
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
memset(&freq,0,sizeof(freq));
- freq.frequency = fv / 62500;
+ if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+ // ((fv * 1000) / 62500)
+ freq.frequency = (fv * 2) / 125;
+ } else {
+ freq.frequency = fv / 62500;
+ }
+ /* tuner-core currently doesn't seem to care about this, but
+ let's set it anyway for completeness. */
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ freq.type = V4L2_TUNER_RADIO;
+ } else {
+ freq.type = V4L2_TUNER_ANALOG_TV;
+ }
freq.tuner = 0;
- freq.type = V4L2_TUNER_ANALOG_TV;
pvr2_i2c_core_cmd(hdw,VIDIOC_S_FREQUENCY,&freq);
}
@@ -221,6 +262,12 @@ void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *cp,int fl)
}
+void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *cp)
+{
+ pvr2_i2c_client_cmd(cp,VIDIOC_G_TUNER,&cp->hdw->tuner_signal_info);
+}
+
+
/*
Stuff for Emacs to see, in order to encourage consistent editing style:
*** Local Variables: ***
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
index ecabddba1ec..c838df6167f 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
@@ -26,13 +26,16 @@
#include "pvrusb2-i2c-core.h"
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_radio;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log;
void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *,int);
+void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *);
#endif /* __PVRUSB2_CMD_V4L2_H */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 62a7cfca837..58fc3c730fe 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -22,6 +22,7 @@
#include "pvrusb2-i2c-core.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
+#include "pvrusb2-fx2-cmd.h"
#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
@@ -66,7 +67,7 @@ static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
/* Set up command buffer for an I2C write */
- hdw->cmd_buffer[0] = 0x08; /* write prefix */
+ hdw->cmd_buffer[0] = FX2CMD_I2C_WRITE; /* write prefix */
hdw->cmd_buffer[1] = i2c_addr; /* i2c addr of chip */
hdw->cmd_buffer[2] = length; /* length of what follows */
if (length) memcpy(hdw->cmd_buffer + 3, data, length);
@@ -128,7 +129,7 @@ static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */
memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
/* Set up command buffer for an I2C write followed by a read */
- hdw->cmd_buffer[0] = 0x09; /* read prefix */
+ hdw->cmd_buffer[0] = FX2CMD_I2C_READ; /* read prefix */
hdw->cmd_buffer[1] = dlen; /* arg length */
hdw->cmd_buffer[2] = rlen; /* answer length. Device will send one
more byte (status). */
@@ -221,7 +222,7 @@ static int i2c_24xxx_ir(struct pvr2_hdw *hdw,
/* Issue a command to the FX2 to read the IR receiver. */
LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = 0xec;
+ hdw->cmd_buffer[0] = FX2CMD_GET_IR_CODE;
stat = pvr2_send_request(hdw,
hdw->cmd_buffer,1,
hdw->cmd_buffer,4);
@@ -590,6 +591,33 @@ static int handler_check(struct pvr2_i2c_client *cp)
#define BUFSIZE 500
+
+void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw)
+{
+ struct list_head *item;
+ struct pvr2_i2c_client *cp;
+ mutex_lock(&hdw->i2c_list_lock); do {
+ struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
+ memset(vtp,0,sizeof(*vtp));
+ list_for_each(item,&hdw->i2c_clients) {
+ cp = list_entry(item,struct pvr2_i2c_client,list);
+ if (!cp->detected_flag) continue;
+ if (!cp->status_poll) continue;
+ cp->status_poll(cp);
+ }
+ hdw->tuner_signal_stale = 0;
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c status poll"
+ " type=%u strength=%u audio=0x%x cap=0x%x"
+ " low=%u hi=%u",
+ vtp->type,
+ vtp->signal,vtp->rxsubchans,vtp->capability,
+ vtp->rangelow,vtp->rangehigh);
+ } while (0); mutex_unlock(&hdw->i2c_list_lock);
+}
+
+
+/* Issue various I2C operations to bring chip-level drivers into sync with
+ state stored in this driver. */
void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
{
unsigned long msk;
@@ -870,12 +898,12 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client)
struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
struct pvr2_i2c_client *cp;
int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);
- cp = kmalloc(sizeof(*cp),GFP_KERNEL);
+ cp = kzalloc(sizeof(*cp),GFP_KERNEL);
trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
client->name,
client->addr,cp);
if (!cp) return -ENOMEM;
- memset(cp,0,sizeof(*cp));
+ cp->hdw = hdw;
INIT_LIST_HEAD(&cp->list);
cp->client = client;
mutex_lock(&hdw->i2c_list_lock); do {
@@ -948,8 +976,7 @@ static void do_i2c_scan(struct pvr2_hdw *hdw)
printk("%s: i2c scan beginning\n",hdw->name);
for (i = 0; i < 128; i++) {
msg[0].addr = i;
- rc = i2c_transfer(&hdw->i2c_adap,msg,
- sizeof(msg)/sizeof(msg[0]));
+ rc = i2c_transfer(&hdw->i2c_adap,msg, ARRAY_SIZE(msg));
if (rc != 1) continue;
printk("%s: i2c scan: found device @ 0x%x\n",hdw->name,i);
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
index 6d7e2524757..bd0807b905b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
@@ -35,10 +35,12 @@ struct pvr2_i2c_client {
struct i2c_client *client;
struct pvr2_i2c_handler *handler;
struct list_head list;
+ struct pvr2_hdw *hdw;
int detected_flag;
int recv_enable;
unsigned long pend_mask;
unsigned long ctl_mask;
+ void (*status_poll)(struct pvr2_i2c_client *);
};
struct pvr2_i2c_handler {
@@ -67,6 +69,7 @@ int pvr2_i2c_core_cmd(struct pvr2_hdw *,unsigned int cmd,void *arg);
int pvr2_i2c_core_check_stale(struct pvr2_hdw *);
void pvr2_i2c_core_sync(struct pvr2_hdw *);
+void pvr2_i2c_core_status_poll(struct pvr2_hdw *);
unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen);
#define PVR2_I2C_DETAIL_DEBUG 0x0001
#define PVR2_I2C_DETAIL_HANDLER 0x0002
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.c b/drivers/media/video/pvrusb2/pvrusb2-io.c
index 57fb3203354..ce3c8982ffe 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-io.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-io.c
@@ -474,9 +474,8 @@ static void buffer_complete(struct urb *urb)
struct pvr2_stream *pvr2_stream_create(void)
{
struct pvr2_stream *sp;
- sp = kmalloc(sizeof(*sp),GFP_KERNEL);
+ sp = kzalloc(sizeof(*sp),GFP_KERNEL);
if (!sp) return sp;
- memset(sp,0,sizeof(*sp));
pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_create: sp=%p",sp);
pvr2_stream_init(sp);
return sp;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
index b71f9a961f8..f782418afa4 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ioread.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
@@ -87,10 +87,9 @@ static void pvr2_ioread_done(struct pvr2_ioread *cp)
struct pvr2_ioread *pvr2_ioread_create(void)
{
struct pvr2_ioread *cp;
- cp = kmalloc(sizeof(*cp),GFP_KERNEL);
+ cp = kzalloc(sizeof(*cp),GFP_KERNEL);
if (!cp) return NULL;
pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp);
- memset(cp,0,sizeof(*cp));
if (pvr2_ioread_init(cp) < 0) {
kfree(cp);
return NULL;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
index c08925557ed..81de26ba41d 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-std.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-std.c
@@ -141,10 +141,8 @@ int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
cnt = 0;
while ((cnt < bufSize) && (bufPtr[cnt] != '-')) cnt++;
if (cnt >= bufSize) return 0; // No more characters
- sp = find_std_name(
- std_groups,
- sizeof(std_groups)/sizeof(std_groups[0]),
- bufPtr,cnt);
+ sp = find_std_name(std_groups, ARRAY_SIZE(std_groups),
+ bufPtr,cnt);
if (!sp) return 0; // Illegal color system name
cnt++;
bufPtr += cnt;
@@ -163,8 +161,7 @@ int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
if (ch == '/') break;
cnt++;
}
- sp = find_std_name(std_items,
- sizeof(std_items)/sizeof(std_items[0]),
+ sp = find_std_name(std_items, ARRAY_SIZE(std_items),
bufPtr,cnt);
if (!sp) return 0; // Illegal modulation system ID
t = sp->id & cmsk;
@@ -189,14 +186,10 @@ unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize,
unsigned int c1,c2;
cfl = 0;
c1 = 0;
- for (idx1 = 0;
- idx1 < sizeof(std_groups)/sizeof(std_groups[0]);
- idx1++) {
+ for (idx1 = 0; idx1 < ARRAY_SIZE(std_groups); idx1++) {
gp = std_groups + idx1;
gfl = 0;
- for (idx2 = 0;
- idx2 < sizeof(std_items)/sizeof(std_items[0]);
- idx2++) {
+ for (idx2 = 0; idx2 < ARRAY_SIZE(std_items); idx2++) {
ip = std_items + idx2;
if (!(gp->id & ip->id & id)) continue;
if (!gfl) {
@@ -279,7 +272,7 @@ static struct v4l2_standard generic_standards[] = {
}
};
-#define generic_standards_cnt (sizeof(generic_standards)/sizeof(generic_standards[0]))
+#define generic_standards_cnt ARRAY_SIZE(generic_standards)
static struct v4l2_standard *match_std(v4l2_std_id id)
{
@@ -348,7 +341,7 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
fmsk |= idmsk;
}
- for (idx2 = 0; idx2 < sizeof(std_mixes)/sizeof(std_mixes[0]); idx2++) {
+ for (idx2 = 0; idx2 < ARRAY_SIZE(std_mixes); idx2++) {
if ((id & std_mixes[idx2]) == std_mixes[idx2]) std_cnt++;
}
@@ -366,16 +359,15 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
std_cnt);
if (!std_cnt) return NULL; // paranoia
- stddefs = kmalloc(sizeof(struct v4l2_standard) * std_cnt,
+ stddefs = kzalloc(sizeof(struct v4l2_standard) * std_cnt,
GFP_KERNEL);
- memset(stddefs,0,sizeof(struct v4l2_standard) * std_cnt);
for (idx = 0; idx < std_cnt; idx++) stddefs[idx].index = idx;
idx = 0;
/* Enumerate potential special cases */
- for (idx2 = 0; ((idx2 < sizeof(std_mixes)/sizeof(std_mixes[0])) &&
- (idx < std_cnt)); idx2++) {
+ for (idx2 = 0; (idx2 < ARRAY_SIZE(std_mixes)) && (idx < std_cnt);
+ idx2++) {
if (!(id & std_mixes[idx2])) continue;
if (pvr2_std_fill(stddefs+idx,std_mixes[idx2])) idx++;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index c294f46db9b..91396fd573e 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -40,8 +40,10 @@ struct pvr2_sysfs {
struct pvr2_sysfs_ctl_item *item_first;
struct pvr2_sysfs_ctl_item *item_last;
struct class_device_attribute attr_v4l_minor_number;
+ struct class_device_attribute attr_v4l_radio_minor_number;
struct class_device_attribute attr_unit_number;
int v4l_minor_number_created_ok;
+ int v4l_radio_minor_number_created_ok;
int unit_number_created_ok;
};
@@ -491,7 +493,7 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
unsigned int cnt,acnt;
int ret;
- if ((ctl_id < 0) || (ctl_id >= (sizeof(funcs)/sizeof(funcs[0])))) {
+ if ((ctl_id < 0) || (ctl_id >= ARRAY_SIZE(funcs))) {
return;
}
@@ -499,9 +501,8 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id);
if (!cptr) return;
- cip = kmalloc(sizeof(*cip),GFP_KERNEL);
+ cip = kzalloc(sizeof(*cip),GFP_KERNEL);
if (!cip) return;
- memset(cip,0,sizeof(*cip));
pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip);
cip->cptr = cptr;
@@ -611,9 +612,8 @@ static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
struct pvr2_sysfs_debugifc *dip;
int ret;
- dip = kmalloc(sizeof(*dip),GFP_KERNEL);
+ dip = kzalloc(sizeof(*dip),GFP_KERNEL);
if (!dip) return;
- memset(dip,0,sizeof(*dip));
dip->attr_debugcmd.attr.owner = THIS_MODULE;
dip->attr_debugcmd.attr.name = "debugcmd";
dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP;
@@ -709,6 +709,10 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp)
class_device_remove_file(sfp->class_dev,
&sfp->attr_v4l_minor_number);
}
+ if (sfp->v4l_radio_minor_number_created_ok) {
+ class_device_remove_file(sfp->class_dev,
+ &sfp->attr_v4l_radio_minor_number);
+ }
if (sfp->unit_number_created_ok) {
class_device_remove_file(sfp->class_dev,
&sfp->attr_unit_number);
@@ -726,7 +730,20 @@ static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf)
sfp = (struct pvr2_sysfs *)class_dev->class_data;
if (!sfp) return -EINVAL;
return scnprintf(buf,PAGE_SIZE,"%d\n",
- pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw));
+ pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
+ pvr2_v4l_type_video));
+}
+
+
+static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev,
+ char *buf)
+{
+ struct pvr2_sysfs *sfp;
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+ return scnprintf(buf,PAGE_SIZE,"%d\n",
+ pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
+ pvr2_v4l_type_radio));
}
@@ -749,9 +766,8 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw);
if (!usb_dev) return;
- class_dev = kmalloc(sizeof(*class_dev),GFP_KERNEL);
+ class_dev = kzalloc(sizeof(*class_dev),GFP_KERNEL);
if (!class_dev) return;
- memset(class_dev,0,sizeof(*class_dev));
pvr2_sysfs_trace("Creating class_dev id=%p",class_dev);
@@ -793,6 +809,20 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
sfp->v4l_minor_number_created_ok = !0;
}
+ sfp->attr_v4l_radio_minor_number.attr.owner = THIS_MODULE;
+ sfp->attr_v4l_radio_minor_number.attr.name = "v4l_radio_minor_number";
+ sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO;
+ sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show;
+ sfp->attr_v4l_radio_minor_number.store = NULL;
+ ret = class_device_create_file(sfp->class_dev,
+ &sfp->attr_v4l_radio_minor_number);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ __FUNCTION__, ret);
+ } else {
+ sfp->v4l_radio_minor_number_created_ok = !0;
+ }
+
sfp->attr_unit_number.attr.owner = THIS_MODULE;
sfp->attr_unit_number.attr.name = "unit_number";
sfp->attr_unit_number.attr.mode = S_IRUGO;
@@ -829,9 +859,8 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp,
struct pvr2_sysfs_class *class_ptr)
{
struct pvr2_sysfs *sfp;
- sfp = kmalloc(sizeof(*sfp),GFP_KERNEL);
+ sfp = kzalloc(sizeof(*sfp),GFP_KERNEL);
if (!sfp) return sfp;
- memset(sfp,0,sizeof(*sfp));
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp);
pvr2_channel_init(&sfp->channel,mp);
sfp->channel.check_func = pvr2_sysfs_internal_check;
@@ -852,9 +881,8 @@ static int pvr2_sysfs_hotplug(struct class_device *cd,char **envp,
struct pvr2_sysfs_class *pvr2_sysfs_class_create(void)
{
struct pvr2_sysfs_class *clp;
- clp = kmalloc(sizeof(*clp),GFP_KERNEL);
+ clp = kzalloc(sizeof(*clp),GFP_KERNEL);
if (!clp) return clp;
- memset(clp,0,sizeof(*clp));
pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp);
clp->class.name = "pvrusb2";
clp->class.class_release = pvr2_sysfs_class_release;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.c b/drivers/media/video/pvrusb2/pvrusb2-tuner.c
index bb17db3f643..05e65ce2e3a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-tuner.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-tuner.c
@@ -93,9 +93,8 @@ int pvr2_i2c_tuner_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
struct pvr2_tuner_handler *ctxt;
if (cp->handler) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
if (!ctxt) return 0;
- memset(ctxt,0,sizeof(*ctxt));
ctxt->i2c_handler.func_data = ctxt;
ctxt->i2c_handler.func_table = &tuner_funcs;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 6cf17080eb4..5313d342666 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -40,7 +40,10 @@ struct pvr2_v4l2_dev {
struct video_device devbase; /* MUST be first! */
struct pvr2_v4l2 *v4lp;
struct pvr2_context_stream *stream;
- enum pvr2_config config;
+ /* Information about this device: */
+ enum pvr2_config config; /* Expected stream format */
+ int v4l_type; /* V4L defined type for this device node */
+ enum pvr2_v4l_type minor_type; /* pvr2-understood minor device type */
};
struct pvr2_v4l2_fh {
@@ -54,6 +57,7 @@ struct pvr2_v4l2_fh {
struct pvr2_v4l2_fh *vprev;
wait_queue_head_t wait_data;
int fw_mode_flag;
+ int prev_input_val;
};
struct pvr2_v4l2 {
@@ -63,13 +67,22 @@ struct pvr2_v4l2 {
struct v4l2_prio_state prio;
- /* streams */
- struct pvr2_v4l2_dev *vdev;
+ /* streams - Note that these must be separately, individually,
+ * allocated pointers. This is because the v4l core is going to
+ * manage their deletion - separately, individually... */
+ struct pvr2_v4l2_dev *dev_video;
+ struct pvr2_v4l2_dev *dev_radio;
};
static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
module_param_array(video_nr, int, NULL, 0444);
-MODULE_PARM_DESC(video_nr, "Offset for device's minor");
+MODULE_PARM_DESC(video_nr, "Offset for device's video dev minor");
+static int radio_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Offset for device's radio dev minor");
+static int vbi_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
+module_param_array(vbi_nr, int, NULL, 0444);
+MODULE_PARM_DESC(vbi_nr, "Offset for device's vbi dev minor");
static struct v4l2_capability pvr_capability ={
.driver = "pvrusb2",
@@ -77,30 +90,11 @@ static struct v4l2_capability pvr_capability ={
.bus_info = "usb",
.version = KERNEL_VERSION(0,8,0),
.capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_TUNER | V4L2_CAP_AUDIO |
+ V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
V4L2_CAP_READWRITE),
.reserved = {0,0,0,0}
};
-static struct v4l2_tuner pvr_v4l2_tuners[]= {
- {
- .index = 0,
- .name = "TV Tuner",
- .type = V4L2_TUNER_ANALOG_TV,
- .capability = (V4L2_TUNER_CAP_NORM |
- V4L2_TUNER_CAP_STEREO |
- V4L2_TUNER_CAP_LANG1 |
- V4L2_TUNER_CAP_LANG2),
- .rangelow = 0,
- .rangehigh = 0,
- .rxsubchans = V4L2_TUNER_SUB_STEREO,
- .audmode = V4L2_TUNER_MODE_STEREO,
- .signal = 0,
- .afc = 0,
- .reserved = {0,0,0,0}
- }
-};
-
static struct v4l2_fmtdesc pvr_fmtdesc [] = {
{
.index = 0,
@@ -154,6 +148,18 @@ static struct v4l2_format pvr_format [] = {
}
};
+
+static const char *get_v4l_name(int v4l_type)
+{
+ switch (v4l_type) {
+ case VFL_TYPE_GRABBER: return "video";
+ case VFL_TYPE_RADIO: return "radio";
+ case VFL_TYPE_VBI: return "vbi";
+ default: return "?";
+ }
+}
+
+
/*
* pvr_ioctl()
*
@@ -315,13 +321,39 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_ENUMAUDIO:
{
+ /* pkt: FIXME: We are returning one "fake" input here
+ which could very well be called "whatever_we_like".
+ This is for apps that want to see an audio input
+ just to feel comfortable, as well as to test if
+ it can do stereo or sth. There is actually no guarantee
+ that the actual audio input cannot change behind the app's
+ back, but most applications should not mind that either.
+
+ Hopefully, mplayer people will work with us on this (this
+ whole mess is to support mplayer pvr://), or Hans will come
+ up with a more standard way to say "we have inputs but we
+ don 't want you to change them independent of video" which
+ will sort this mess.
+ */
+ struct v4l2_audio *vin = arg;
ret = -EINVAL;
+ if (vin->index > 0) break;
+ strncpy(vin->name, "PVRUSB2 Audio",14);
+ vin->capability = V4L2_AUDCAP_STEREO;
+ ret = 0;
+ break;
break;
}
case VIDIOC_G_AUDIO:
{
- ret = -EINVAL;
+ /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */
+ struct v4l2_audio *vin = arg;
+ memset(vin,0,sizeof(*vin));
+ vin->index = 0;
+ strncpy(vin->name, "PVRUSB2 Audio",14);
+ vin->capability = V4L2_AUDCAP_STEREO;
+ ret = 0;
break;
}
@@ -333,34 +365,11 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_G_TUNER:
{
struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
- unsigned int status_mask;
- int val;
- if (vt->index !=0) break;
- status_mask = pvr2_hdw_get_signal_status(hdw);
+ if (vt->index != 0) break; /* Only answer for the 1st tuner */
- memcpy(vt, &pvr_v4l2_tuners[vt->index],
- sizeof(struct v4l2_tuner));
-
- vt->signal = 0;
- if (status_mask & PVR2_SIGNAL_OK) {
- if (status_mask & PVR2_SIGNAL_STEREO) {
- vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
- } else {
- vt->rxsubchans = V4L2_TUNER_SUB_MONO;
- }
- if (status_mask & PVR2_SIGNAL_SAP) {
- vt->rxsubchans |= (V4L2_TUNER_SUB_LANG1 |
- V4L2_TUNER_SUB_LANG2);
- }
- vt->signal = 65535;
- }
-
- val = 0;
- ret = pvr2_ctrl_get_value(
- pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
- &val);
- vt->audmode = val;
+ pvr2_hdw_execute_tuner_poll(hdw);
+ ret = pvr2_hdw_get_tuner_status(hdw,vt);
break;
}
@@ -374,14 +383,40 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
ret = pvr2_ctrl_set_value(
pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
vt->audmode);
+ break;
}
case VIDIOC_S_FREQUENCY:
{
const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
+ unsigned long fv;
+ struct v4l2_tuner vt;
+ int cur_input;
+ struct pvr2_ctrl *ctrlp;
+ ret = pvr2_hdw_get_tuner_status(hdw,&vt);
+ if (ret != 0) break;
+ ctrlp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+ ret = pvr2_ctrl_get_value(ctrlp,&cur_input);
+ if (ret != 0) break;
+ if (vf->type == V4L2_TUNER_RADIO) {
+ if (cur_input != PVR2_CVAL_INPUT_RADIO) {
+ pvr2_ctrl_set_value(ctrlp,
+ PVR2_CVAL_INPUT_RADIO);
+ }
+ } else {
+ if (cur_input == PVR2_CVAL_INPUT_RADIO) {
+ pvr2_ctrl_set_value(ctrlp,
+ PVR2_CVAL_INPUT_TV);
+ }
+ }
+ fv = vf->frequency;
+ if (vt.capability & V4L2_TUNER_CAP_LOW) {
+ fv = (fv * 125) / 2;
+ } else {
+ fv = fv * 62500;
+ }
ret = pvr2_ctrl_set_value(
- pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
- vf->frequency * 62500);
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv);
break;
}
@@ -389,10 +424,27 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
{
struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
int val = 0;
+ int cur_input;
+ struct v4l2_tuner vt;
+ ret = pvr2_hdw_get_tuner_status(hdw,&vt);
+ if (ret != 0) break;
ret = pvr2_ctrl_get_value(
pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
&val);
- val /= 62500;
+ if (ret != 0) break;
+ pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
+ &cur_input);
+ if (cur_input == PVR2_CVAL_INPUT_RADIO) {
+ vf->type = V4L2_TUNER_RADIO;
+ } else {
+ vf->type = V4L2_TUNER_ANALOG_TV;
+ }
+ if (vt.capability & V4L2_TUNER_CAP_LOW) {
+ val = (val * 2) / 125;
+ } else {
+ val /= 62500;
+ }
vf->frequency = val;
break;
}
@@ -449,7 +501,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
ret = 0;
switch(vf->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- int lmin,lmax;
+ int lmin,lmax,ldef;
struct pvr2_ctrl *hcp,*vcp;
int h = vf->fmt.pix.height;
int w = vf->fmt.pix.width;
@@ -458,14 +510,20 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
lmin = pvr2_ctrl_get_min(hcp);
lmax = pvr2_ctrl_get_max(hcp);
- if (w < lmin) {
+ ldef = pvr2_ctrl_get_def(hcp);
+ if (w == -1) {
+ w = ldef;
+ } else if (w < lmin) {
w = lmin;
} else if (w > lmax) {
w = lmax;
}
lmin = pvr2_ctrl_get_min(vcp);
lmax = pvr2_ctrl_get_max(vcp);
- if (h < lmin) {
+ ldef = pvr2_ctrl_get_def(vcp);
+ if (h == -1) {
+ h = ldef;
+ } else if (h < lmin) {
h = lmin;
} else if (h > lmax) {
h = lmax;
@@ -494,6 +552,13 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_STREAMON:
{
+ if (!fh->dev_info->stream) {
+ /* No stream defined for this node. This means
+ that we're not currently allowed to stream from
+ this node. */
+ ret = -EPERM;
+ break;
+ }
ret = pvr2_hdw_set_stream_type(hdw,dev_info->config);
if (ret < 0) return ret;
ret = pvr2_hdw_set_streaming(hdw,!0);
@@ -502,6 +567,13 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_STREAMOFF:
{
+ if (!fh->dev_info->stream) {
+ /* No stream defined for this node. This means
+ that we're not currently allowed to stream from
+ this node. */
+ ret = -EPERM;
+ break;
+ }
ret = pvr2_hdw_set_streaming(hdw,0);
break;
}
@@ -599,6 +671,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_ext_control *ctrl;
unsigned int idx;
int val;
+ ret = 0;
for (idx = 0; idx < ctls->count; idx++) {
ctrl = ctls->controls + idx;
ret = pvr2_ctrl_get_value(
@@ -621,6 +694,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
(struct v4l2_ext_controls *)arg;
struct v4l2_ext_control *ctrl;
unsigned int idx;
+ ret = 0;
for (idx = 0; idx < ctls->count; idx++) {
ctrl = ctls->controls + idx;
ret = pvr2_ctrl_set_value(
@@ -643,6 +717,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
unsigned int idx;
/* For the moment just validate that the requested control
actually exists. */
+ ret = 0;
for (idx = 0; idx < ctls->count; idx++) {
ctrl = ctls->controls + idx;
pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);
@@ -662,16 +737,16 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
break;
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_INT_G_REGISTER:
- case VIDIOC_INT_S_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
{
- u32 val;
+ u64 val;
struct v4l2_register *req = (struct v4l2_register *)arg;
- if (cmd == VIDIOC_INT_S_REGISTER) val = req->val;
+ if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val;
ret = pvr2_hdw_register_access(
- hdw,req->i2c_id,req->reg,
- cmd == VIDIOC_INT_S_REGISTER,&val);
- if (cmd == VIDIOC_INT_G_REGISTER) req->val = val;
+ hdw,req->match_type,req->match_chip,req->reg,
+ cmd == VIDIOC_DBG_S_REGISTER,&val);
+ if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val;
break;
}
#endif
@@ -707,8 +782,12 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
{
- printk(KERN_INFO "pvrusb2: unregistering device video%d [%s]\n",
- dip->devbase.minor,pvr2_config_get_name(dip->config));
+ int minor_id = dip->devbase.minor;
+ struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw;
+ enum pvr2_config cfg = dip->config;
+ int v4l_type = dip->v4l_type;
+
+ pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1);
/* Paranoia */
dip->v4lp = NULL;
@@ -717,13 +796,24 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
/* Actual deallocation happens later when all internal references
are gone. */
video_unregister_device(&dip->devbase);
+
+ printk(KERN_INFO "pvrusb2: unregistered device %s%u [%s]\n",
+ get_v4l_name(v4l_type),minor_id & 0x1f,
+ pvr2_config_get_name(cfg));
+
}
static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
{
- pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,-1);
- pvr2_v4l2_dev_destroy(vp->vdev);
+ if (vp->dev_video) {
+ pvr2_v4l2_dev_destroy(vp->dev_video);
+ vp->dev_video = 0;
+ }
+ if (vp->dev_radio) {
+ pvr2_v4l2_dev_destroy(vp->dev_radio);
+ vp->dev_radio = 0;
+ }
pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
pvr2_channel_done(&vp->channel);
@@ -766,23 +856,37 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file)
struct pvr2_v4l2_fh *fhp = file->private_data;
struct pvr2_v4l2 *vp = fhp->vhead;
struct pvr2_context *mp = fhp->vhead->channel.mc_head;
+ struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw;
pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");
if (fhp->rhp) {
struct pvr2_stream *sp;
- struct pvr2_hdw *hdw;
- hdw = fhp->channel.mc_head->hdw;
pvr2_hdw_set_streaming(hdw,0);
sp = pvr2_ioread_get_stream(fhp->rhp);
if (sp) pvr2_stream_set_callback(sp,NULL,NULL);
pvr2_ioread_destroy(fhp->rhp);
fhp->rhp = NULL;
}
+
v4l2_prio_close(&vp->prio, &fhp->prio);
file->private_data = NULL;
pvr2_context_enter(mp); do {
+ /* Restore the previous input selection, if it makes sense
+ to do so. */
+ if (fhp->dev_info->v4l_type == VFL_TYPE_RADIO) {
+ struct pvr2_ctrl *cp;
+ int pval;
+ cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+ pvr2_ctrl_get_value(cp,&pval);
+ /* Only restore if we're still selecting the radio */
+ if (pval == PVR2_CVAL_INPUT_RADIO) {
+ pvr2_ctrl_set_value(cp,fhp->prev_input_val);
+ pvr2_hdw_commit_ctl(hdw);
+ }
+ }
+
if (fhp->vnext) {
fhp->vnext->vprev = fhp->vprev;
} else {
@@ -828,11 +932,10 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
return -EIO;
}
- fhp = kmalloc(sizeof(*fhp),GFP_KERNEL);
+ fhp = kzalloc(sizeof(*fhp),GFP_KERNEL);
if (!fhp) {
return -ENOMEM;
}
- memset(fhp,0,sizeof(*fhp));
init_waitqueue_head(&fhp->wait_data);
fhp->dev_info = dip;
@@ -840,6 +943,7 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
pvr2_context_enter(vp->channel.mc_head); do {
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
+
fhp->vnext = NULL;
fhp->vprev = vp->vlast;
if (vp->vlast) {
@@ -849,6 +953,18 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
}
vp->vlast = fhp;
fhp->vhead = vp;
+
+ /* Opening the /dev/radioX device implies a mode switch.
+ So execute that here. Note that you can get the
+ IDENTICAL effect merely by opening the normal video
+ device and setting the input appropriately. */
+ if (dip->v4l_type == VFL_TYPE_RADIO) {
+ struct pvr2_ctrl *cp;
+ cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+ pvr2_ctrl_get_value(cp,&fhp->prev_input_val);
+ pvr2_ctrl_set_value(cp,PVR2_CVAL_INPUT_RADIO);
+ pvr2_hdw_commit_ctl(hdw);
+ }
} while (0); pvr2_context_exit(vp->channel.mc_head);
fhp->file = file;
@@ -873,6 +989,12 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
struct pvr2_hdw *hdw;
if (fh->rhp) return 0;
+ if (!fh->dev_info->stream) {
+ /* No stream defined for this node. This means that we're
+ not currently allowed to stream from this node. */
+ return -EPERM;
+ }
+
/* First read() attempt. Try to claim the stream and start
it... */
if ((ret = pvr2_channel_claim_stream(&fh->channel,
@@ -1012,25 +1134,37 @@ static struct video_device vdev_template = {
static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
struct pvr2_v4l2 *vp,
- enum pvr2_config cfg)
+ int v4l_type)
{
int mindevnum;
int unit_number;
- int v4l_type;
+ int *nr_ptr = 0;
dip->v4lp = vp;
- dip->config = cfg;
- switch (cfg) {
- case pvr2_config_mpeg:
- v4l_type = VFL_TYPE_GRABBER;
+ dip->v4l_type = v4l_type;
+ switch (v4l_type) {
+ case VFL_TYPE_GRABBER:
dip->stream = &vp->channel.mc_head->video_stream;
+ dip->config = pvr2_config_mpeg;
+ dip->minor_type = pvr2_v4l_type_video;
+ nr_ptr = video_nr;
+ if (!dip->stream) {
+ err("Failed to set up pvrusb2 v4l video dev"
+ " due to missing stream instance");
+ return;
+ }
break;
- case pvr2_config_vbi:
- v4l_type = VFL_TYPE_VBI;
+ case VFL_TYPE_VBI:
+ dip->config = pvr2_config_vbi;
+ dip->minor_type = pvr2_v4l_type_vbi;
+ nr_ptr = vbi_nr;
break;
- case pvr2_config_radio:
- v4l_type = VFL_TYPE_RADIO;
+ case VFL_TYPE_RADIO:
+ dip->stream = &vp->channel.mc_head->video_stream;
+ dip->config = pvr2_config_mpeg;
+ dip->minor_type = pvr2_v4l_type_radio;
+ nr_ptr = radio_nr;
break;
default:
/* Bail out (this should be impossible) */
@@ -1039,30 +1173,27 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
return;
}
- if (!dip->stream) {
- err("Failed to set up pvrusb2 v4l dev"
- " due to missing stream instance");
- return;
- }
-
memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template));
dip->devbase.release = pvr2_video_device_release;
mindevnum = -1;
unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
- if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
- mindevnum = video_nr[unit_number];
+ if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) {
+ mindevnum = nr_ptr[unit_number];
}
- if ((video_register_device(&dip->devbase, v4l_type, mindevnum) < 0) &&
- (video_register_device(&dip->devbase, v4l_type, -1) < 0)) {
- err("Failed to register pvrusb2 v4l video device");
- } else {
- printk(KERN_INFO "pvrusb2: registered device video%d [%s]\n",
- dip->devbase.minor,pvr2_config_get_name(dip->config));
+ if ((video_register_device(&dip->devbase,
+ dip->v4l_type, mindevnum) < 0) &&
+ (video_register_device(&dip->devbase,
+ dip->v4l_type, -1) < 0)) {
+ err("Failed to register pvrusb2 v4l device");
}
+ printk(KERN_INFO "pvrusb2: registered device %s%u [%s]\n",
+ get_v4l_name(dip->v4l_type),dip->devbase.minor & 0x1f,
+ pvr2_config_get_name(dip->config));
+
pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
- dip->devbase.minor);
+ dip->minor_type,dip->devbase.minor);
}
@@ -1070,22 +1201,24 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
{
struct pvr2_v4l2 *vp;
- vp = kmalloc(sizeof(*vp),GFP_KERNEL);
+ vp = kzalloc(sizeof(*vp),GFP_KERNEL);
if (!vp) return vp;
- memset(vp,0,sizeof(*vp));
- vp->vdev = kmalloc(sizeof(*vp->vdev),GFP_KERNEL);
- if (!vp->vdev) {
+ vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
+ vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
+ if (!(vp->dev_video && vp->dev_radio)) {
+ kfree(vp->dev_video);
+ kfree(vp->dev_radio);
kfree(vp);
return NULL;
}
- memset(vp->vdev,0,sizeof(*vp->vdev));
pvr2_channel_init(&vp->channel,mnp);
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
vp->channel.check_func = pvr2_v4l2_internal_check;
/* register streams */
- pvr2_v4l2_dev_init(vp->vdev,vp,pvr2_config_mpeg);
+ pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER);
+ pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
return vp;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
index 2a826464911..61efa6f0220 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
@@ -66,7 +66,9 @@ static void set_input(struct pvr2_v4l_decoder *ctxt)
route.input = SAA7115_SVIDEO2;
break;
case PVR2_CVAL_INPUT_RADIO:
- // ????? No idea yet what to do here
+ // In radio mode, we mute the video, but point at one
+ // spot just to stay consistent
+ route.input = SAA7115_COMPOSITE5;
default:
return;
}
@@ -137,8 +139,7 @@ static int decoder_check(struct pvr2_v4l_decoder *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
msk = 1 << idx;
if (ctxt->stale_mask & msk) continue;
if (decoder_ops[idx].check(ctxt)) {
@@ -154,8 +155,7 @@ static void decoder_update(struct pvr2_v4l_decoder *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
msk = 1 << idx;
if (!(ctxt->stale_mask & msk)) continue;
ctxt->stale_mask &= ~msk;
@@ -183,18 +183,6 @@ static void decoder_enable(struct pvr2_v4l_decoder *ctxt,int fl)
}
-static int decoder_is_tuned(struct pvr2_v4l_decoder *ctxt)
-{
- struct v4l2_tuner vt;
- int ret;
-
- memset(&vt,0,sizeof(vt));
- ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
- if (ret < 0) return -EINVAL;
- return vt.signal ? 1 : 0;
-}
-
-
static unsigned int decoder_describe(struct pvr2_v4l_decoder *ctxt,char *buf,unsigned int cnt)
{
return scnprintf(buf,cnt,"handler: pvrusb2-video-v4l");
@@ -218,20 +206,17 @@ int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw,
if (cp->handler) return 0;
if (!decoder_detect(cp)) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
if (!ctxt) return 0;
- memset(ctxt,0,sizeof(*ctxt));
ctxt->handler.func_data = ctxt;
ctxt->handler.func_table = &hfuncs;
ctxt->ctrl.ctxt = ctxt;
ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
- ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
ctxt->client = cp;
ctxt->hdw = hdw;
- ctxt->stale_mask = (1 << (sizeof(decoder_ops)/
- sizeof(decoder_ops[0]))) - 1;
+ ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
hdw->decoder_ctrl = &ctxt->ctrl;
cp->handler = &ctxt->handler;
pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up",
diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
index 7794c34c355..66b4d36ef76 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
@@ -50,15 +50,21 @@ static void set_input(struct pvr2_v4l_wm8775 *ctxt)
{
struct v4l2_routing route;
struct pvr2_hdw *hdw = ctxt->hdw;
- int msk = 0;
memset(&route,0,sizeof(route));
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c wm8775 set_input(val=%d msk=0x%x)",
- hdw->input_val,msk);
+ switch(hdw->input_val) {
+ case PVR2_CVAL_INPUT_RADIO:
+ route.input = 1;
+ break;
+ default:
+ /* All other cases just use the second input */
+ route.input = 2;
+ break;
+ }
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c wm8775 set_input(val=%d route=0x%x)",
+ hdw->input_val,route.input);
- // Always point to input #1 no matter what
- route.input = 2;
pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
}
@@ -99,8 +105,7 @@ static int wm8775_check(struct pvr2_v4l_wm8775 *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(wm8775_ops); idx++) {
msk = 1 << idx;
if (ctxt->stale_mask & msk) continue;
if (wm8775_ops[idx].check(ctxt)) {
@@ -116,8 +121,7 @@ static void wm8775_update(struct pvr2_v4l_wm8775 *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(wm8775_ops); idx++) {
msk = 1 << idx;
if (!(ctxt->stale_mask & msk)) continue;
ctxt->stale_mask &= ~msk;
@@ -140,16 +144,14 @@ int pvr2_i2c_wm8775_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
if (cp->handler) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
if (!ctxt) return 0;
- memset(ctxt,0,sizeof(*ctxt));
ctxt->handler.func_data = ctxt;
ctxt->handler.func_table = &hfuncs;
ctxt->client = cp;
ctxt->hdw = hdw;
- ctxt->stale_mask = (1 << (sizeof(wm8775_ops)/
- sizeof(wm8775_ops[0]))) - 1;
+ ctxt->stale_mask = (1 << ARRAY_SIZE(wm8775_ops)) - 1;
cp->handler = &ctxt->handler;
pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x wm8775 V4L2 handler set up",
cp->client->addr);
diff --git a/drivers/media/video/pwc/Makefile b/drivers/media/video/pwc/Makefile
index 9db2260d10c..f5c8ec261e8 100644
--- a/drivers/media/video/pwc/Makefile
+++ b/drivers/media/video/pwc/Makefile
@@ -2,11 +2,3 @@ pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-v4l.o pwc-uncompress.o
pwc-objs += pwc-dec1.o pwc-dec23.o pwc-kiara.o pwc-timon.o
obj-$(CONFIG_USB_PWC) += pwc.o
-
-ifeq ($(CONFIG_USB_PWC_DEBUG),y)
-EXTRA_CFLAGS += -DCONFIG_PWC_DEBUG=1
-else
-EXTRA_CFLAGS += -DCONFIG_PWC_DEBUG=0
-endif
-
-
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 9825fd34810..27ed76986ca 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -128,7 +128,7 @@ static int default_size = PSZ_QCIF;
static int default_fps = 10;
static int default_fbufs = 3; /* Default number of frame buffers */
int pwc_mbufs = 2; /* Default number of mmap() buffers */
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
int pwc_trace = PWC_DEBUG_LEVEL;
#endif
static int power_save = 0;
@@ -1051,7 +1051,7 @@ static void pwc_remove_sysfs_files(struct video_device *vdev)
video_device_remove_file(vdev, &class_device_attr_button);
}
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
{
switch(sensor_type) {
@@ -1835,7 +1835,7 @@ module_param(size, charp, 0444);
module_param(fps, int, 0444);
module_param(fbufs, int, 0444);
module_param(mbufs, int, 0444);
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
module_param_named(trace, pwc_trace, int, 0644);
#endif
module_param(power_save, int, 0444);
@@ -1908,7 +1908,7 @@ static int __init usb_pwc_init(void)
default_fbufs = fbufs;
PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs);
}
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
if (pwc_trace >= 0) {
PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
}
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index b7eb3ce3b96..d5e6bc85064 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -350,7 +350,7 @@ int pwc_video_do_ioctl(struct inode *inode, struct file *file,
if (pdev == NULL)
return -EFAULT;
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace)
v4l_printk_ioctl(cmd);
#endif
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index 7e9c4237d1e..e778a2b8c28 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -39,11 +39,6 @@
#include "pwc-uncompress.h"
#include <media/pwc-ioctl.h>
-/* Turn some debugging options on/off */
-#ifndef CONFIG_PWC_DEBUG
-#define CONFIG_PWC_DEBUG 1
-#endif
-
/* Version block */
#define PWC_MAJOR 10
#define PWC_MINOR 0
@@ -76,7 +71,7 @@
#define PWC_DEBUG_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args)
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
#define PWC_DEBUG_LEVEL (PWC_DEBUG_LEVEL_MODULE)
@@ -270,7 +265,7 @@ extern "C" {
#endif
/* Global variables */
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
extern int pwc_trace;
#endif
extern int pwc_mbufs;
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
index 76f5f5d49da..e20aa3612a7 100644
--- a/drivers/media/video/saa5246a.c
+++ b/drivers/media/video/saa5246a.c
@@ -111,7 +111,7 @@ static int saa5246a_attach(struct i2c_adapter *adap, int addr, int kind)
for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++)
{
memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0]));
- t->is_searching[pgbuf] = FALSE;
+ t->is_searching[pgbuf] = false;
}
vd->priv=t;
@@ -198,7 +198,7 @@ static int i2c_senddata(struct saa5246a_device *t, ...)
/* Get count number of bytes from I²C-device at address adr, store them in buf.
* Start & stop handshaking is done by this routine, ack will be sent after the
- * last byte to inhibit further sending of data. If uaccess is TRUE, data is
+ * last byte to inhibit further sending of data. If uaccess is 'true', data is
* written to user-space with put_user. Returns -1 if I²C-device didn't send
* acknowledge, 0 otherwise
*/
@@ -338,7 +338,7 @@ static int saa5246a_request_page(struct saa5246a_device *t,
return -EIO;
}
- t->is_searching[req->pgbuf] = TRUE;
+ t->is_searching[req->pgbuf] = true;
return 0;
}
@@ -452,7 +452,7 @@ static inline int saa5246a_get_status(struct saa5246a_device *t,
}
}
if (!info->hamming && !info->notfound)
- t->is_searching[dau_no] = FALSE;
+ t->is_searching[dau_no] = false;
return 0;
}
@@ -564,7 +564,7 @@ static inline int saa5246a_stop_dau(struct saa5246a_device *t,
{
return -EIO;
}
- t->is_searching[dau_no] = FALSE;
+ t->is_searching[dau_no] = false;
return 0;
}
diff --git a/drivers/media/video/saa5246a.h b/drivers/media/video/saa5246a.h
index 7b91112304e..64394c036c6 100644
--- a/drivers/media/video/saa5246a.h
+++ b/drivers/media/video/saa5246a.h
@@ -41,23 +41,18 @@
#define POS_HEADER_START 7
#define POS_HEADER_END 31
-/* Returns TRUE if the part of the videotext page described with req contains
+/* Returns 'true' if the part of the videotext page described with req contains
(at least parts of) the time field */
#define REQ_CONTAINS_TIME(p_req) \
((p_req)->start <= POS_TIME_END && \
(p_req)->end >= POS_TIME_START)
-/* Returns TRUE if the part of the videotext page described with req contains
+/* Returns 'true' if the part of the videotext page described with req contains
(at least parts of) the page header */
#define REQ_CONTAINS_HEADER(p_req) \
((p_req)->start <= POS_HEADER_END && \
(p_req)->end >= POS_HEADER_START)
-#ifndef FALSE
-#define FALSE 0
-#define TRUE 1
-#endif
-
/*****************************************************************************/
/* Mode register numbers of the SAA5246A */
/*****************************************************************************/
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index 3e84737878a..f2a2f34cd62 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -124,11 +124,6 @@ struct saa5249_device
/* General defines and debugging support */
-#ifndef FALSE
-#define FALSE 0
-#define TRUE 1
-#endif
-
#define RESCHED do { cond_resched(); } while(0)
static struct video_device saa_template; /* Declared near bottom */
@@ -183,9 +178,9 @@ static int saa5249_attach(struct i2c_adapter *adap, int addr, int kind)
memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
t->vdau[pgbuf].expire = 0;
- t->vdau[pgbuf].clrfound = TRUE;
- t->vdau[pgbuf].stopped = TRUE;
- t->is_searching[pgbuf] = FALSE;
+ t->vdau[pgbuf].clrfound = true;
+ t->vdau[pgbuf].stopped = true;
+ t->is_searching[pgbuf] = false;
}
vd->priv=t;
@@ -298,7 +293,7 @@ static int i2c_senddata(struct saa5249_device *t, ...)
/* Get count number of bytes from I²C-device at address adr, store them in buf. Start & stop
* handshaking is done by this routine, ack will be sent after the last byte to inhibit further
- * sending of data. If uaccess is TRUE, data is written to user-space with put_user.
+ * sending of data. If uaccess is 'true', data is written to user-space with put_user.
* Returns -1 if I²C-device didn't send acknowledge, 0 otherwise
*/
@@ -317,7 +312,7 @@ static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
static int do_saa5249_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
- static int virtual_mode = FALSE;
+ static int virtual_mode = false;
struct video_device *vd = video_devdata(file);
struct saa5249_device *t=vd->priv;
@@ -340,7 +335,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
return -EINVAL;
memset(t->vdau[req->pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
- t->vdau[req->pgbuf].clrfound = TRUE;
+ t->vdau[req->pgbuf].clrfound = true;
return 0;
}
@@ -350,7 +345,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
return -EINVAL;
- t->vdau[req->pgbuf].clrfound = TRUE;
+ t->vdau[req->pgbuf].clrfound = true;
return 0;
}
@@ -376,9 +371,9 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
t->vdau[req->pgbuf].sregs[4] = (req->pagemask & HR_UNIT ? 0x10 : 0) | (req->hour & 0xf);
t->vdau[req->pgbuf].sregs[5] = (req->pagemask & MIN_TEN ? 0x10 : 0) | (req->minute / 0x10);
t->vdau[req->pgbuf].sregs[6] = (req->pagemask & MIN_UNIT ? 0x10 : 0) | (req->minute & 0xf);
- t->vdau[req->pgbuf].stopped = FALSE;
- t->vdau[req->pgbuf].clrfound = TRUE;
- t->is_searching[req->pgbuf] = TRUE;
+ t->vdau[req->pgbuf].stopped = false;
+ t->vdau[req->pgbuf].clrfound = true;
+ t->is_searching[req->pgbuf] = true;
return 0;
}
@@ -430,7 +425,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 23 * 40))
return -EIO;
}
- t->vdau[req->pgbuf].clrfound = FALSE;
+ t->vdau[req->pgbuf].clrfound = false;
memcpy(t->vdau[req->pgbuf].laststat, infobits, sizeof(infobits));
}
else
@@ -474,7 +469,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
if (!info.hamming && !info.notfound)
{
- t->is_searching[req->pgbuf] = FALSE;
+ t->is_searching[req->pgbuf] = false;
}
return 0;
}
@@ -530,8 +525,8 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
return -EINVAL;
- t->vdau[req->pgbuf].stopped = TRUE;
- t->is_searching[req->pgbuf] = FALSE;
+ t->vdau[req->pgbuf].stopped = true;
+ t->is_searching[req->pgbuf] = false;
return 0;
}
@@ -660,11 +655,11 @@ static int saa5249_open(struct inode *inode, struct file *file)
memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
t->vdau[pgbuf].expire = 0;
- t->vdau[pgbuf].clrfound = TRUE;
- t->vdau[pgbuf].stopped = TRUE;
- t->is_searching[pgbuf] = FALSE;
+ t->vdau[pgbuf].clrfound = true;
+ t->vdau[pgbuf].stopped = true;
+ t->is_searching[pgbuf] = false;
}
- t->virtual_mode=FALSE;
+ t->virtual_mode = false;
return 0;
fail:
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index c2374ed7ba9..7735b675892 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -71,6 +71,7 @@ I2C_CLIENT_INSMOD;
struct saa711x_state {
v4l2_std_id std;
int input;
+ int output;
int enable;
int radio;
int bright;
@@ -1301,7 +1302,7 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
struct v4l2_routing *route = arg;
route->input = state->input;
- route->output = 0;
+ route->output = state->output;
break;
}
@@ -1309,7 +1310,7 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
{
struct v4l2_routing *route = arg;
- v4l_dbg(1, debug, client, "decoder set input %d\n", route->input);
+ v4l_dbg(1, debug, client, "decoder set input %d output %d\n", route->input, route->output);
/* saa7113 does not have these inputs */
if (state->ident == V4L2_IDENT_SAA7113 &&
(route->input == SAA7115_COMPOSITE4 ||
@@ -1318,10 +1319,12 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
}
if (route->input > SAA7115_SVIDEO3)
return -EINVAL;
- if (state->input == route->input)
+ if (route->output > SAA7115_IPORT_ON)
+ return -EINVAL;
+ if (state->input == route->input && state->output == route->output)
break;
- v4l_dbg(1, debug, client, "now setting %s input\n",
- (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite");
+ v4l_dbg(1, debug, client, "now setting %s input %s output\n",
+ (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite", (route->output == SAA7115_IPORT_ON) ? "iport on" : "iport off");
state->input = route->input;
/* select mode */
@@ -1333,6 +1336,14 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
saa711x_write(client, R_09_LUMA_CNTL,
(saa711x_read(client, R_09_LUMA_CNTL) & 0x7f) |
(state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
+
+ state->output = route->output;
+ if (state->ident == V4L2_IDENT_SAA7114 ||
+ state->ident == V4L2_IDENT_SAA7115) {
+ saa711x_write(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK,
+ (saa711x_read(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
+ (state->output & 0x01));
+ }
break;
}
@@ -1377,6 +1388,9 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
{
struct v4l2_sliced_vbi_data *data = arg;
+ /* Note: the internal field ID is inverted for NTSC,
+ so data->field 0 maps to the saa7115 even field,
+ whereas for PAL it maps to the saa7115 odd field. */
switch (data->id) {
case V4L2_SLICED_WSS_625:
if (saa711x_read(client, 0x6b) & 0xc0)
@@ -1387,17 +1401,17 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
case V4L2_SLICED_CAPTION_525:
if (data->field == 0) {
/* CC */
- if (saa711x_read(client, 0x66) & 0xc0)
+ if (saa711x_read(client, 0x66) & 0x30)
return -EIO;
- data->data[0] = saa711x_read(client, 0x67);
- data->data[1] = saa711x_read(client, 0x68);
+ data->data[0] = saa711x_read(client, 0x69);
+ data->data[1] = saa711x_read(client, 0x6a);
return 0;
}
/* XDS */
- if (saa711x_read(client, 0x66) & 0x30)
+ if (saa711x_read(client, 0x66) & 0xc0)
return -EIO;
- data->data[0] = saa711x_read(client, 0x69);
- data->data[1] = saa711x_read(client, 0x6a);
+ data->data[0] = saa711x_read(client, 0x67);
+ data->data[1] = saa711x_read(client, 0x68);
return 0;
default:
return -EINVAL;
@@ -1406,25 +1420,19 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_INT_G_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
{
struct v4l2_register *reg = arg;
- if (reg->i2c_id != I2C_DRIVERID_SAA711X)
- return -EINVAL;
- reg->val = saa711x_read(client, reg->reg & 0xff);
- break;
- }
-
- case VIDIOC_INT_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
-
- if (reg->i2c_id != I2C_DRIVERID_SAA711X)
+ if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ reg->val = saa711x_read(client, reg->reg & 0xff);
+ else
+ saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
break;
}
#endif
@@ -1492,6 +1500,7 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
return -ENOMEM;
}
state->input = -1;
+ state->output = SAA7115_IPORT_ON;
state->enable = 1;
state->radio = 0;
state->bright = 128;
@@ -1550,7 +1559,7 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
static int saa711x_probe(struct i2c_adapter *adapter)
{
- if (adapter->class & I2C_CLASS_TV_ANALOG)
+ if (adapter->class & I2C_CLASS_TV_ANALOG || adapter->class & I2C_CLASS_TV_DIGITAL)
return i2c_probe(adapter, &addr_data, &saa711x_attach);
return 0;
}
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index ad401bdefea..654863db159 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -614,25 +614,19 @@ static int saa7127_command(struct i2c_client *client,
break;
#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_INT_G_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
{
struct v4l2_register *reg = arg;
- if (reg->i2c_id != I2C_DRIVERID_SAA7127)
- return -EINVAL;
- reg->val = saa7127_read(client, reg->reg & 0xff);
- break;
- }
-
- case VIDIOC_INT_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
-
- if (reg->i2c_id != I2C_DRIVERID_SAA7127)
+ if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- saa7127_write(client, reg->reg & 0xff, reg->val & 0xff);
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ reg->val = saa7127_read(client, reg->reg & 0xff);
+ else
+ saa7127_write(client, reg->reg & 0xff, reg->val & 0xff);
break;
}
#endif
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
index 89a1565b425..c85c8a8ec36 100644
--- a/drivers/media/video/saa7134/Makefile
+++ b/drivers/media/video/saa7134/Makefile
@@ -14,7 +14,3 @@ obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
EXTRA_CFLAGS += -Idrivers/media/video
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
-
-extra-cflags-$(CONFIG_VIDEO_BUF_DVB) += -DHAVE_VIDEO_BUF_DVB=1
-
-EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index ae984bbe36b..89f32107f46 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -2469,6 +2469,11 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE2,
.gpio = 0x0200000,
},{
+ .name = name_comp2,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x0200000,
+ },{
.name = name_svideo,
.vmux = 8,
.amux = LINE2,
@@ -3183,6 +3188,107 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE1,
}},
},
+ [SAA7134_BOARD_ENCORE_ENLTV] = {
+ /* Steven Walter <stevenrwalter@gmail.com>
+ Juan Pablo Sormani <sorman@gmail.com> */
+ .name = "Encore ENLTV",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_TNF_5335MF,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = 3,
+ .tv = 1,
+ },{
+ .name = name_tv_mono,
+ .vmux = 7,
+ .amux = 4,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = 2,
+ },{
+ .name = name_svideo,
+ .vmux = 0,
+ .amux = 2,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+/* .gpio = 0x00300001,*/
+ .gpio = 0x20000,
+
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = 0,
+ },
+ },
+ [SAA7134_BOARD_ENCORE_ENLTV_FM] = {
+ /* Juan Pablo Sormani <sorman@gmail.com> */
+ .name = "Encore ENLTV-FM",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_ATSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = 3,
+ .tv = 1,
+ },{
+ .name = name_tv_mono,
+ .vmux = 7,
+ .amux = 4,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = 2,
+ },{
+ .name = name_svideo,
+ .vmux = 0,
+ .amux = 2,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ .gpio = 0x20000,
+
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = 0,
+ },
+ },
+ [SAA7134_BOARD_CINERGY_HT_PCI] = {
+ .name = "Terratec Cinergy HT PCI",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 6,
+ .amux = LINE1,
+ }},
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -3822,6 +3928,36 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x1172,
.driver_data = SAA7134_BOARD_CINERGY_HT_PCMCIA,
},{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2342,
+ .driver_data = SAA7134_BOARD_ENCORE_ENLTV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1131,
+ .subdevice = 0x2341,
+ .driver_data = SAA7134_BOARD_ENCORE_ENLTV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x3016,
+ .subdevice = 0x2344,
+ .driver_data = SAA7134_BOARD_ENCORE_ENLTV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1131,
+ .subdevice = 0x230f,
+ .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x153b,
+ .subdevice = 0x1175,
+ .driver_data = SAA7134_BOARD_CINERGY_HT_PCI,
+ },{
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -3926,9 +4062,12 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_KWORLD_TERMINATOR:
case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
case SAA7134_BOARD_FLYDVBT_LR301:
+ case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
case SAA7134_BOARD_FLYDVBTDUO:
case SAA7134_BOARD_PROTEUS_2309:
case SAA7134_BOARD_AVERMEDIA_A16AR:
+ case SAA7134_BOARD_ENCORE_ENLTV:
+ case SAA7134_BOARD_ENCORE_ENLTV_FM:
dev->has_remote = SAA7134_REMOTE_GPIO;
break;
case SAA7134_BOARD_FLYDVBS_LR300:
@@ -4150,6 +4289,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_CINERGY_HT_PCMCIA:
+ case SAA7134_BOARD_CINERGY_HT_PCI:
/* make the tda10046 find its eeprom */
{
u8 data[] = { 0x3c, 0x33, 0x60};
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index c33f6a69a24..e3059fd3395 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -1426,6 +1426,18 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
+ case SAA7134_BOARD_CINERGY_HT_PCI:
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &cinergy_ht_config,
+ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
+ dev->dvb.frontend->ops.tuner_ops.init = cinergy_ht_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = cinergy_ht_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = md8800_dvbt_pll_set;
+
+ }
+ break;
default:
printk("%s: Huh? unknown DVB card?\n",dev->name);
break;
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 6f9fe86fed9..cce8da6a4f9 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -120,9 +120,9 @@ static inline int i2c_is_error(enum i2c_status status)
case ARB_LOST:
case SEQ_ERR:
case ST_ERR:
- return TRUE;
+ return true;
default:
- return FALSE;
+ return false;
}
}
@@ -131,9 +131,9 @@ static inline int i2c_is_idle(enum i2c_status status)
switch (status) {
case IDLE:
case DONE_STOP:
- return TRUE;
+ return true;
default:
- return FALSE;
+ return false;
}
}
@@ -141,9 +141,9 @@ static inline int i2c_is_busy(enum i2c_status status)
{
switch (status) {
case BUSY:
- return TRUE;
+ return true;
default:
- return FALSE;
+ return false;
}
}
@@ -159,8 +159,8 @@ static int i2c_is_busy_wait(struct saa7134_dev *dev)
saa_wait(I2C_WAIT_DELAY);
}
if (I2C_WAIT_RETRY == count)
- return FALSE;
- return TRUE;
+ return false;
+ return true;
}
static int i2c_reset(struct saa7134_dev *dev)
@@ -171,7 +171,7 @@ static int i2c_reset(struct saa7134_dev *dev)
d2printk(KERN_DEBUG "%s: i2c reset\n",dev->name);
status = i2c_get_status(dev);
if (!i2c_is_error(status))
- return TRUE;
+ return true;
i2c_set_status(dev,status);
for (count = 0; count < I2C_WAIT_RETRY; count++) {
@@ -181,13 +181,13 @@ static int i2c_reset(struct saa7134_dev *dev)
udelay(I2C_WAIT_DELAY);
}
if (I2C_WAIT_RETRY == count)
- return FALSE;
+ return false;
if (!i2c_is_idle(status))
- return FALSE;
+ return false;
i2c_set_attr(dev,NOP);
- return TRUE;
+ return true;
}
static inline int i2c_send_byte(struct saa7134_dev *dev,
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index e4252683a59..46c583f1e78 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -40,16 +40,24 @@ static int pinnacle_remote = 0;
module_param(pinnacle_remote, int, 0644); /* Choose Pinnacle PCTV remote */
MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)");
+static int ir_rc5_remote_gap = 885;
+module_param(ir_rc5_remote_gap, int, 0644);
+static int ir_rc5_key_timeout = 115;
+module_param(ir_rc5_key_timeout, int, 0644);
+
#define dprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
#define i2cdprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
+/** rc5 functions */
+static int saa7134_rc5_irq(struct saa7134_dev *dev);
+
/* -------------------- GPIO generic keycode builder -------------------- */
static int build_key(struct saa7134_dev *dev)
{
- struct saa7134_ir *ir = dev->remote;
+ struct card_ir *ir = dev->remote;
u32 gpio, data;
/* rising SAA7134_GPIO_GPRESCAN reads the status */
@@ -134,16 +142,19 @@ static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
void saa7134_input_irq(struct saa7134_dev *dev)
{
- struct saa7134_ir *ir = dev->remote;
+ struct card_ir *ir = dev->remote;
- if (!ir->polling)
+ if (!ir->polling && !ir->rc5_gpio) {
build_key(dev);
+ } else if (ir->rc5_gpio) {
+ saa7134_rc5_irq(dev);
+ }
}
static void saa7134_input_timer(unsigned long data)
{
struct saa7134_dev *dev = (struct saa7134_dev*)data;
- struct saa7134_ir *ir = dev->remote;
+ struct card_ir *ir = dev->remote;
unsigned long timeout;
build_key(dev);
@@ -151,7 +162,7 @@ static void saa7134_input_timer(unsigned long data)
mod_timer(&ir->timer, timeout);
}
-static void saa7134_ir_start(struct saa7134_dev *dev, struct saa7134_ir *ir)
+static void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
{
if (ir->polling) {
init_timer(&ir->timer);
@@ -159,6 +170,19 @@ static void saa7134_ir_start(struct saa7134_dev *dev, struct saa7134_ir *ir)
ir->timer.data = (unsigned long)dev;
ir->timer.expires = jiffies + HZ;
add_timer(&ir->timer);
+ } else if (ir->rc5_gpio) {
+ /* set timer_end for code completion */
+ init_timer(&ir->timer_end);
+ ir->timer_end.function = ir_rc5_timer_end;
+ ir->timer_end.data = (unsigned long)ir;
+ init_timer(&ir->timer_keyup);
+ ir->timer_keyup.function = ir_rc5_timer_keyup;
+ ir->timer_keyup.data = (unsigned long)ir;
+ ir->shift_by = 2;
+ ir->start = 0x2;
+ ir->addr = 0x17;
+ ir->rc5_key_timeout = ir_rc5_key_timeout;
+ ir->rc5_remote_gap = ir_rc5_remote_gap;
}
}
@@ -170,13 +194,14 @@ static void saa7134_ir_stop(struct saa7134_dev *dev)
int saa7134_input_init1(struct saa7134_dev *dev)
{
- struct saa7134_ir *ir;
+ struct card_ir *ir;
struct input_dev *input_dev;
IR_KEYTAB_TYPE *ir_codes = NULL;
u32 mask_keycode = 0;
u32 mask_keydown = 0;
u32 mask_keyup = 0;
int polling = 0;
+ int rc5_gpio = 0;
int ir_type = IR_TYPE_OTHER;
int err;
@@ -295,6 +320,18 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keycode = 0x0001F00;
mask_keydown = 0x0040000;
break;
+ case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+ ir_codes = ir_codes_asus_pc39;
+ mask_keydown = 0x0040000;
+ rc5_gpio = 1;
+ break;
+ case SAA7134_BOARD_ENCORE_ENLTV:
+ case SAA7134_BOARD_ENCORE_ENLTV_FM:
+ ir_codes = ir_codes_encore_enltv;
+ mask_keycode = 0x00007f;
+ mask_keyup = 0x040000;
+ polling = 50; // ms
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
@@ -316,6 +353,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
ir->mask_keydown = mask_keydown;
ir->mask_keyup = mask_keyup;
ir->polling = polling;
+ ir->rc5_gpio = rc5_gpio;
/* init input device */
snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
@@ -402,6 +440,49 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
}
}
+
+static int saa7134_rc5_irq(struct saa7134_dev *dev)
+{
+ struct card_ir *ir = dev->remote;
+ struct timeval tv;
+ u32 gap;
+ unsigned long current_jiffies, timeout;
+
+ /* get time of bit */
+ current_jiffies = jiffies;
+ do_gettimeofday(&tv);
+
+ /* avoid overflow with gap >1s */
+ if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+ gap = 200000;
+ } else {
+ gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+ tv.tv_usec - ir->base_time.tv_usec;
+ }
+
+ /* active code => add bit */
+ if (ir->active) {
+ /* only if in the code (otherwise spurious IRQ or timer
+ late) */
+ if (ir->last_bit < 28) {
+ ir->last_bit = (gap - ir_rc5_remote_gap / 2) /
+ ir_rc5_remote_gap;
+ ir->code |= 1 << ir->last_bit;
+ }
+ /* starting new code */
+ } else {
+ ir->active = 1;
+ ir->code = 0;
+ ir->base_time = tv;
+ ir->last_bit = 0;
+
+ timeout = current_jiffies + (500 + 30 * HZ) / 1000;
+ mod_timer(&ir->timer_end, timeout);
+ }
+
+ return 1;
+}
+
/* ----------------------------------------------------------------------
* Local variables:
* c-basic-offset: 8
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 88cd1297df1..b3e3957c89b 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -41,14 +41,10 @@
#include <sound/driver.h>
#include <sound/core.h>
#include <sound/pcm.h>
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
#include <media/video-buf-dvb.h>
-
-#ifndef TRUE
-# define TRUE (1==1)
-#endif
-#ifndef FALSE
-# define FALSE (1==0)
#endif
+
#define UNSET (-1U)
/* ----------------------------------------------------------- */
@@ -232,6 +228,9 @@ struct saa7134_format {
#define SAA7134_BOARD_VIDEOMATE_DVBT_200A 103
#define SAA7134_BOARD_HAUPPAUGE_HVR1110 104
#define SAA7134_BOARD_CINERGY_HT_PCMCIA 105
+#define SAA7134_BOARD_ENCORE_ENLTV 106
+#define SAA7134_BOARD_ENCORE_ENLTV_FM 107
+#define SAA7134_BOARD_CINERGY_HT_PCI 108
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
@@ -411,20 +410,6 @@ struct saa7134_dmasound {
struct snd_pcm_substream *substream;
};
-/* IR input */
-struct saa7134_ir {
- struct input_dev *dev;
- struct ir_input_state ir;
- char name[32];
- char phys[32];
- u32 mask_keycode;
- u32 mask_keydown;
- u32 mask_keyup;
- int polling;
- u32 last_gpio;
- struct timer_list timer;
-};
-
/* ts/mpeg status */
struct saa7134_ts {
/* TS capture */
@@ -463,7 +448,7 @@ struct saa7134_dev {
/* infrared remote */
int has_remote;
- struct saa7134_ir *remote;
+ struct card_ir *remote;
/* pci i/o */
char name[32];
@@ -543,9 +528,11 @@ struct saa7134_dev {
struct work_struct empress_workqueue;
int empress_started;
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
/* SAA7134_MPEG_DVB only */
struct videobuf_dvb dvb;
int (*original_demod_sleep)(struct dvb_frontend* fe);
+#endif
};
/* ----------------------------------------------------------- */
@@ -698,6 +685,7 @@ void saa7134_input_fini(struct saa7134_dev *dev);
void saa7134_input_irq(struct saa7134_dev *dev);
void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir);
+
/*
* Local variables:
* c-basic-offset: 8
diff --git a/drivers/media/video/sn9c102/Kconfig b/drivers/media/video/sn9c102/Kconfig
index cf552e6b8ec..1a7ccb666ab 100644
--- a/drivers/media/video/sn9c102/Kconfig
+++ b/drivers/media/video/sn9c102/Kconfig
@@ -1,9 +1,9 @@
config USB_SN9C102
- tristate "USB SN9C10x PC Camera Controller support"
+ tristate "USB SN9C1xx PC Camera Controller support"
depends on USB && VIDEO_V4L1
---help---
Say Y here if you want support for cameras based on SONiX SN9C101,
- SN9C102 or SN9C103 PC Camera Controllers.
+ SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers.
See <file:Documentation/video4linux/sn9c102.txt> for more info.
diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/video/sn9c102/Makefile
index 536ad3098da..30e3dfe537f 100644
--- a/drivers/media/video/sn9c102/Makefile
+++ b/drivers/media/video/sn9c102/Makefile
@@ -1,5 +1,5 @@
sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \
- sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \
+ sn9c102_ov7630.o sn9c102_ov7660.o sn9c102_pas106b.o \
sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \
sn9c102_tas5130d1b.o
diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h
index 2c6ff396daf..5428f34e7c5 100644
--- a/drivers/media/video/sn9c102/sn9c102.h
+++ b/drivers/media/video/sn9c102/sn9c102.h
@@ -1,5 +1,5 @@
/***************************************************************************
- * V4L2 driver for SN9C10x PC Camera Controllers *
+ * V4L2 driver for SN9C1xx PC Camera Controllers *
* *
* Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
@@ -37,33 +37,10 @@
#include <linux/string.h>
#include <linux/stddef.h>
+#include "sn9c102_config.h"
#include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
-/*****************************************************************************/
-
-#define SN9C102_DEBUG
-#define SN9C102_DEBUG_LEVEL 2
-#define SN9C102_MAX_DEVICES 64
-#define SN9C102_PRESERVE_IMGSCALE 0
-#define SN9C102_FORCE_MUNMAP 0
-#define SN9C102_MAX_FRAMES 32
-#define SN9C102_URBS 2
-#define SN9C102_ISO_PACKETS 7
-#define SN9C102_ALTERNATE_SETTING 8
-#define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
-#define SN9C102_CTRL_TIMEOUT 300
-#define SN9C102_FRAME_TIMEOUT 2
-
-/*****************************************************************************/
-
-enum sn9c102_bridge {
- BRIDGE_SN9C101 = 0x01,
- BRIDGE_SN9C102 = 0x02,
- BRIDGE_SN9C103 = 0x04,
-};
-
-SN9C102_ID_TABLE
-SN9C102_SENSOR_TABLE
enum sn9c102_frame_state {
F_UNUSED,
@@ -99,13 +76,11 @@ enum sn9c102_stream_state {
STREAM_ON,
};
-typedef char sn9c103_sof_header_t[18];
-typedef char sn9c102_sof_header_t[12];
-typedef char sn9c102_eof_header_t[4];
+typedef char sn9c102_sof_header_t[62];
struct sn9c102_sysfs_attr {
u8 reg, i2c_reg;
- sn9c103_sof_header_t frame_header;
+ sn9c102_sof_header_t frame_header;
};
struct sn9c102_module_param {
@@ -137,8 +112,8 @@ struct sn9c102_device {
struct v4l2_jpegcompression compression;
struct sn9c102_sysfs_attr sysfs;
- sn9c103_sof_header_t sof_header;
- u16 reg[63];
+ sn9c102_sof_header_t sof_header;
+ u16 reg[384];
struct sn9c102_module_param module_param;
@@ -155,10 +130,7 @@ struct sn9c102_device {
struct sn9c102_device*
sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)
{
- if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
- return cam;
-
- return NULL;
+ return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
}
@@ -169,6 +141,19 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
}
+
+enum sn9c102_bridge
+sn9c102_get_bridge(struct sn9c102_device* cam)
+{
+ return cam->bridge;
+}
+
+
+struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam)
+{
+ return &cam->sensor;
+}
+
/*****************************************************************************/
#undef DBG
diff --git a/drivers/media/video/sn9c102/sn9c102_config.h b/drivers/media/video/sn9c102/sn9c102_config.h
new file mode 100644
index 00000000000..0f4e0378b07
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_config.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * Global parameters for the V4L2 driver for SN9C1xx PC Camera Controllers *
+ * *
+ * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the Free Software *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
+ ***************************************************************************/
+
+#ifndef _SN9C102_CONFIG_H_
+#define _SN9C102_CONFIG_H_
+
+#include <linux/types.h>
+#include <linux/jiffies.h>
+
+#define SN9C102_DEBUG
+#define SN9C102_DEBUG_LEVEL 2
+#define SN9C102_MAX_DEVICES 64
+#define SN9C102_PRESERVE_IMGSCALE 0
+#define SN9C102_FORCE_MUNMAP 0
+#define SN9C102_MAX_FRAMES 32
+#define SN9C102_URBS 2
+#define SN9C102_ISO_PACKETS 7
+#define SN9C102_ALTERNATE_SETTING 8
+#define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
+#define SN9C102_CTRL_TIMEOUT 300
+#define SN9C102_FRAME_TIMEOUT 0
+
+/*****************************************************************************/
+
+static const u8 SN9C102_Y_QTABLE0[64] = {
+ 8, 5, 5, 8, 12, 20, 25, 30,
+ 6, 6, 7, 9, 13, 29, 30, 27,
+ 7, 6, 8, 12, 20, 28, 34, 28,
+ 7, 8, 11, 14, 25, 43, 40, 31,
+ 9, 11, 18, 28, 34, 54, 51, 38,
+ 12, 17, 27, 32, 40, 52, 56, 46,
+ 24, 32, 39, 43, 51, 60, 60, 50,
+ 36, 46, 47, 49, 56, 50, 51, 49
+};
+
+static const u8 SN9C102_UV_QTABLE0[64] = {
+ 8, 9, 12, 23, 49, 49, 49, 49,
+ 9, 10, 13, 33, 49, 49, 49, 49,
+ 12, 13, 28, 49, 49, 49, 49, 49,
+ 23, 33, 49, 49, 49, 49, 49, 49,
+ 49, 49, 49, 49, 49, 49, 49, 49,
+ 49, 49, 49, 49, 49, 49, 49, 49,
+ 49, 49, 49, 49, 49, 49, 49, 49,
+ 49, 49, 49, 49, 49, 49, 49, 49
+};
+
+static const u8 SN9C102_Y_QTABLE1[64] = {
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99
+};
+
+static const u8 SN9C102_UV_QTABLE1[64] = {
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+};
+
+#endif /* _SN9C102_CONFIG_H_ */
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index 04d4c8f28b8..d0e2b40a772 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -1,7 +1,7 @@
/***************************************************************************
- * V4L2 driver for SN9C10x PC Camera Controllers *
+ * V4L2 driver for SN9C1xx PC Camera Controllers *
* *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* 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 *
@@ -43,12 +43,12 @@
/*****************************************************************************/
-#define SN9C102_MODULE_NAME "V4L2 driver for SN9C10x PC Camera Controllers"
+#define SN9C102_MODULE_NAME "V4L2 driver for SN9C1xx PC Camera Controllers"
#define SN9C102_MODULE_AUTHOR "(C) 2004-2006 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE "GPL"
-#define SN9C102_MODULE_VERSION "1:1.27"
-#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 27)
+#define SN9C102_MODULE_VERSION "1:1.34"
+#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 34)
/*****************************************************************************/
@@ -91,7 +91,8 @@ static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
SN9C102_FRAME_TIMEOUT};
module_param_array(frame_timeout, uint, NULL, 0644);
MODULE_PARM_DESC(frame_timeout,
- "\n<n[,...]> Timeout for a video frame in seconds."
+ "\n<0|n[,...]> Timeout for a video frame in seconds before"
+ "\nreturning an I/O error; 0 for infinity."
"\nThis parameter is specific for each detected camera."
"\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
"\n");
@@ -113,32 +114,13 @@ MODULE_PARM_DESC(debug,
/*****************************************************************************/
-static sn9c102_sof_header_t sn9c102_sof_header[] = {
- {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00},
- {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01},
-};
-
-static sn9c103_sof_header_t sn9c103_sof_header[] = {
- {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x20},
-};
-
-static sn9c102_eof_header_t sn9c102_eof_header[] = {
- {0x00, 0x00, 0x00, 0x00},
- {0x40, 0x00, 0x00, 0x00},
- {0x80, 0x00, 0x00, 0x00},
- {0xc0, 0x00, 0x00, 0x00},
-};
-
-/*****************************************************************************/
-
static u32
sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
enum sn9c102_io_method io)
{
struct v4l2_pix_format* p = &(cam->sensor.pix_format);
struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
- const size_t imagesize = cam->module_param.force_munmap ||
- io == IO_READ ?
+ size_t imagesize = cam->module_param.force_munmap || io == IO_READ ?
(p->width * p->height * p->priv) / 8 :
(r->width * r->height * p->priv) / 8;
void* buff = NULL;
@@ -147,9 +129,13 @@ sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
if (count > SN9C102_MAX_FRAMES)
count = SN9C102_MAX_FRAMES;
+ if (cam->bridge == BRIDGE_SN9C105 || cam->bridge == BRIDGE_SN9C120)
+ imagesize += 589 + 2; /* length of JPEG header + EOI marker */
+
cam->nbuffers = count;
while (cam->nbuffers > 0) {
- if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+ if ((buff = vmalloc_32_user(cam->nbuffers *
+ PAGE_ALIGN(imagesize))))
break;
cam->nbuffers--;
}
@@ -322,9 +308,21 @@ static int
sn9c102_i2c_detect_read_error(struct sn9c102_device* cam,
struct sn9c102_sensor* sensor)
{
- int r;
+ int r , err = 0;
+
r = sn9c102_read_reg(cam, 0x08);
- return (r < 0 || (r >= 0 && !(r & 0x08))) ? -EIO : 0;
+ if (r < 0)
+ err += r;
+
+ if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
+ if (!(r & 0x08))
+ err += -1;
+ } else {
+ if (r & 0x08)
+ err += -1;
+ }
+
+ return err ? -EIO : 0;
}
@@ -415,7 +413,7 @@ sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
data[4] = data3;
data[5] = data4;
data[6] = data5;
- data[7] = 0x14;
+ data[7] = 0x17;
res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
if (res < 0)
@@ -467,31 +465,35 @@ int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
/*****************************************************************************/
-static void*
-sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
+static size_t sn9c102_sof_length(struct sn9c102_device* cam)
{
- size_t soflen = 0, i;
- u8 j, n = 0;
-
switch (cam->bridge) {
case BRIDGE_SN9C101:
case BRIDGE_SN9C102:
- soflen = sizeof(sn9c102_sof_header_t);
- n = sizeof(sn9c102_sof_header) / soflen;
- break;
+ return 12;
case BRIDGE_SN9C103:
- soflen = sizeof(sn9c103_sof_header_t);
- n = sizeof(sn9c103_sof_header) / soflen;
+ return 18;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ return 62;
}
+ return 0;
+}
+
+
+static void*
+sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
+{
+ char sof_header[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
+ size_t soflen = 0, i;
+
+ soflen = sn9c102_sof_length(cam);
+
for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
- for (j = 0; j < n; j++)
- /* The invariable part of the header is 6 bytes long */
- if ((cam->bridge != BRIDGE_SN9C103 &&
- !memcmp(mem + i, sn9c102_sof_header[j], 6)) ||
- (cam->bridge == BRIDGE_SN9C103 &&
- !memcmp(mem + i, sn9c103_sof_header[j], 6))) {
- memcpy(cam->sof_header, mem + i, soflen);
+ if (!memcmp(mem + i, sof_header, sizeof(sof_header))) {
+ memcpy(cam->sof_header, mem + i,
+ sizeof(sn9c102_sof_header_t));
/* Skip the header */
return mem + i + soflen;
}
@@ -503,21 +505,123 @@ sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
static void*
sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
{
- size_t eoflen = sizeof(sn9c102_eof_header_t), i;
- unsigned j, n = sizeof(sn9c102_eof_header) / eoflen;
+ char eof_header[4][4] = {
+ {0x00, 0x00, 0x00, 0x00},
+ {0x40, 0x00, 0x00, 0x00},
+ {0x80, 0x00, 0x00, 0x00},
+ {0xc0, 0x00, 0x00, 0x00},
+ };
+ size_t i, j;
- if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+ if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X ||
+ cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
return NULL; /* EOF header does not exist in compressed data */
- for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++)
- for (j = 0; j < n; j++)
- if (!memcmp(mem + i, sn9c102_eof_header[j], eoflen))
+ for (i = 0; (len >= 4) && (i <= len - 4); i++)
+ for (j = 0; j < ARRAY_SIZE(eof_header); j++)
+ if (!memcmp(mem + i, eof_header[j], 4))
return mem + i;
return NULL;
}
+static void
+sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f)
+{
+ static u8 jpeg_header[589] = {
+ 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05,
+ 0x06, 0x05, 0x04, 0x06, 0x06, 0x05, 0x06, 0x07, 0x07, 0x06,
+ 0x08, 0x0a, 0x10, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e,
+ 0x0f, 0x0c, 0x10, 0x17, 0x14, 0x18, 0x18, 0x17, 0x14, 0x16,
+ 0x16, 0x1a, 0x1d, 0x25, 0x1f, 0x1a, 0x1b, 0x23, 0x1c, 0x16,
+ 0x16, 0x20, 0x2c, 0x20, 0x23, 0x26, 0x27, 0x29, 0x2a, 0x29,
+ 0x19, 0x1f, 0x2d, 0x30, 0x2d, 0x28, 0x30, 0x25, 0x28, 0x29,
+ 0x28, 0x01, 0x07, 0x07, 0x07, 0x0a, 0x08, 0x0a, 0x13, 0x0a,
+ 0x0a, 0x13, 0x28, 0x1a, 0x16, 0x1a, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0xff, 0xc4, 0x01, 0xa2,
+ 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01,
+ 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00,
+ 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
+ 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04,
+ 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
+ 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23,
+ 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62,
+ 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
+ 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+ 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
+ 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
+ 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
+ 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+ 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
+ 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2,
+ 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3,
+ 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3,
+ 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
+ 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02,
+ 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04,
+ 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
+ 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1,
+ 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1,
+ 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19,
+ 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+ 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
+ 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
+ 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
+ 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
+ 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3,
+ 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
+ 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xc0, 0x00, 0x11,
+ 0x08, 0x01, 0xe0, 0x02, 0x80, 0x03, 0x01, 0x21, 0x00, 0x02,
+ 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03,
+ 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
+ };
+ u8 *pos = f->bufmem;
+
+ memcpy(pos, jpeg_header, sizeof(jpeg_header));
+ *(pos + 6) = 0x00;
+ *(pos + 7 + 64) = 0x01;
+ if (cam->compression.quality == 0) {
+ memcpy(pos + 7, SN9C102_Y_QTABLE0, 64);
+ memcpy(pos + 8 + 64, SN9C102_UV_QTABLE0, 64);
+ } else if (cam->compression.quality == 1) {
+ memcpy(pos + 7, SN9C102_Y_QTABLE1, 64);
+ memcpy(pos + 8 + 64, SN9C102_UV_QTABLE1, 64);
+ }
+ *(pos + 564) = cam->sensor.pix_format.width & 0xFF;
+ *(pos + 563) = (cam->sensor.pix_format.width >> 8) & 0xFF;
+ *(pos + 562) = cam->sensor.pix_format.height & 0xFF;
+ *(pos + 561) = (cam->sensor.pix_format.height >> 8) & 0xFF;
+ *(pos + 567) = 0x21;
+
+ f->buf.bytesused += sizeof(jpeg_header);
+}
+
+
+static void
+sn9c102_write_eoimarker(struct sn9c102_device* cam, struct sn9c102_frame_t* f)
+{
+ static const u8 eoi_marker[2] = {0xff, 0xd9};
+
+ memcpy(f->bufmem + f->buf.bytesused, eoi_marker, sizeof(eoi_marker));
+ f->buf.bytesused += sizeof(eoi_marker);
+}
+
+
static void sn9c102_urb_complete(struct urb *urb)
{
struct sn9c102_device* cam = urb->context;
@@ -535,7 +639,7 @@ static void sn9c102_urb_complete(struct urb *urb)
cam->stream = STREAM_OFF;
if ((*f))
(*f)->state = F_QUEUED;
- DBG(3, "Stream interrupted");
+ DBG(3, "Stream interrupted by application");
wake_up(&cam->wait_stream);
}
@@ -557,10 +661,9 @@ static void sn9c102_urb_complete(struct urb *urb)
imagesize = (cam->sensor.pix_format.width *
cam->sensor.pix_format.height *
cam->sensor.pix_format.priv) / 8;
-
- soflen = (cam->bridge) == BRIDGE_SN9C103 ?
- sizeof(sn9c103_sof_header_t) :
- sizeof(sn9c102_sof_header_t);
+ if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
+ imagesize += 589; /* length of jpeg header */
+ soflen = sn9c102_sof_length(cam);
for (i = 0; i < urb->number_of_packets; i++) {
unsigned int img, len, status;
@@ -610,12 +713,21 @@ end_of_frame:
(*f)->buf.bytesused += img;
if ((*f)->buf.bytesused == imagesize ||
- (cam->sensor.pix_format.pixelformat ==
- V4L2_PIX_FMT_SN9C10X && eof)) {
+ ((cam->sensor.pix_format.pixelformat ==
+ V4L2_PIX_FMT_SN9C10X ||
+ cam->sensor.pix_format.pixelformat ==
+ V4L2_PIX_FMT_JPEG) && eof)) {
u32 b;
+
+ if (cam->sensor.pix_format.pixelformat
+ == V4L2_PIX_FMT_JPEG)
+ sn9c102_write_eoimarker(cam,
+ (*f));
+
b = (*f)->buf.bytesused;
(*f)->state = F_DONE;
(*f)->buf.sequence= ++cam->frame_count;
+
spin_lock(&cam->queue_lock);
list_move_tail(&(*f)->frame,
&cam->outqueue);
@@ -627,8 +739,10 @@ end_of_frame:
else
(*f) = NULL;
spin_unlock(&cam->queue_lock);
+
memcpy(cam->sysfs.frame_header,
cam->sof_header, soflen);
+
DBG(3, "Video frame captured: %lu "
"bytes", (unsigned long)(b));
@@ -661,6 +775,9 @@ start_of_frame:
(*f)->buf.bytesused = 0;
len -= (sof - pos);
pos = sof;
+ if (cam->sensor.pix_format.pixelformat ==
+ V4L2_PIX_FMT_JPEG)
+ sn9c102_write_jpegheader(cam, (*f));
DBG(3, "SOF detected: new video frame");
if (len)
goto redo;
@@ -671,7 +788,9 @@ start_of_frame:
goto end_of_frame; /* (1) */
else {
if (cam->sensor.pix_format.pixelformat ==
- V4L2_PIX_FMT_SN9C10X) {
+ V4L2_PIX_FMT_SN9C10X ||
+ cam->sensor.pix_format.pixelformat ==
+ V4L2_PIX_FMT_JPEG) {
eof = sof - soflen;
goto end_of_frame;
} else {
@@ -701,13 +820,11 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
{
struct usb_device *udev = cam->usbdev;
struct urb* urb;
- const unsigned int sn9c102_wMaxPacketSize[] = {0, 128, 256, 384, 512,
- 680, 800, 900, 1023};
- const unsigned int sn9c103_wMaxPacketSize[] = {0, 128, 256, 384, 512,
- 680, 800, 900, 1003};
- const unsigned int psz = (cam->bridge == BRIDGE_SN9C103) ?
- sn9c103_wMaxPacketSize[SN9C102_ALTERNATE_SETTING] :
- sn9c102_wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
+ struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
+ usb_ifnum_to_if(udev, 0),
+ SN9C102_ALTERNATE_SETTING);
+ const unsigned int psz = le16_to_cpu(altsetting->
+ endpoint[0].desc.wMaxPacketSize);
s8 i, j;
int err = 0;
@@ -775,7 +892,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
return 0;
free_urbs:
- for (i = 0; i < SN9C102_URBS; i++)
+ for (i = 0; (i < SN9C102_URBS) && cam->urb[i]; i++)
usb_free_urb(cam->urb[i]);
free_buffers:
@@ -834,29 +951,29 @@ static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
/*****************************************************************************/
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count)
+static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count)
{
- char str[5];
+ char str[7];
char* endp;
unsigned long val;
- if (len < 4) {
+ if (len < 6) {
strncpy(str, buff, len);
str[len+1] = '\0';
} else {
strncpy(str, buff, 4);
- str[4] = '\0';
+ str[6] = '\0';
}
val = simple_strtoul(str, &endp, 0);
*count = 0;
- if (val <= 0xff)
+ if (val <= 0xffff)
*count = (ssize_t)(endp - str);
if ((*count) && (len == *count+1) && (buff[*count] == '\n'))
*count += 1;
- return (u8)val;
+ return (u16)val;
}
/*
@@ -873,7 +990,8 @@ static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
@@ -891,27 +1009,28 @@ static ssize_t
sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
{
struct sn9c102_device* cam;
- u8 index;
+ u16 index;
ssize_t count;
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
}
- index = sn9c102_strtou8(buf, len, &count);
- if (index > 0x1f || !count) {
+ index = sn9c102_strtou16(buf, len, &count);
+ if (index >= ARRAY_SIZE(cam->reg) || !count) {
mutex_unlock(&sn9c102_sysfs_lock);
return -EINVAL;
}
cam->sysfs.reg = index;
- DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg);
+ DBG(2, "Moved SN9C1XX register index to 0x%02X", cam->sysfs.reg);
DBG(3, "Written bytes: %zd", count);
mutex_unlock(&sn9c102_sysfs_lock);
@@ -929,7 +1048,8 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
@@ -954,20 +1074,21 @@ static ssize_t
sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
{
struct sn9c102_device* cam;
- u8 value;
+ u16 value;
ssize_t count;
int err;
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
}
- value = sn9c102_strtou8(buf, len, &count);
+ value = sn9c102_strtou16(buf, len, &count);
if (!count) {
mutex_unlock(&sn9c102_sysfs_lock);
return -EINVAL;
@@ -979,7 +1100,7 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
return -EIO;
}
- DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X",
+ DBG(2, "Written SN9C1XX reg. 0x%02X, val. 0x%02X",
cam->sysfs.reg, value);
DBG(3, "Written bytes: %zd", count);
@@ -997,7 +1118,8 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
@@ -1017,19 +1139,20 @@ static ssize_t
sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
{
struct sn9c102_device* cam;
- u8 index;
+ u16 index;
ssize_t count;
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
}
- index = sn9c102_strtou8(buf, len, &count);
+ index = sn9c102_strtou16(buf, len, &count);
if (!count) {
mutex_unlock(&sn9c102_sysfs_lock);
return -EINVAL;
@@ -1055,7 +1178,8 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
@@ -1085,14 +1209,15 @@ static ssize_t
sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
{
struct sn9c102_device* cam;
- u8 value;
+ u16 value;
ssize_t count;
int err;
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
@@ -1103,7 +1228,7 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
return -ENOSYS;
}
- value = sn9c102_strtou8(buf, len, &count);
+ value = sn9c102_strtou16(buf, len, &count);
if (!count) {
mutex_unlock(&sn9c102_sysfs_lock);
return -EINVAL;
@@ -1131,13 +1256,14 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
struct sn9c102_device* cam;
enum sn9c102_bridge bridge;
ssize_t res = 0;
- u8 value;
+ u16 value;
ssize_t count;
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
@@ -1147,7 +1273,7 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
mutex_unlock(&sn9c102_sysfs_lock);
- value = sn9c102_strtou8(buf, len, &count);
+ value = sn9c102_strtou16(buf, len, &count);
if (!count)
return -EINVAL;
@@ -1160,9 +1286,11 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
res = sn9c102_store_val(cd, buf, len);
break;
case BRIDGE_SN9C103:
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
if (value > 0x7f)
return -EINVAL;
- if ((res = sn9c102_store_reg(cd, "0x04", 4)) >= 0)
+ if ((res = sn9c102_store_reg(cd, "0x07", 4)) >= 0)
res = sn9c102_store_val(cd, buf, len);
break;
}
@@ -1175,10 +1303,10 @@ static ssize_t
sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len)
{
ssize_t res = 0;
- u8 value;
+ u16 value;
ssize_t count;
- value = sn9c102_strtou8(buf, len, &count);
+ value = sn9c102_strtou16(buf, len, &count);
if (!count || value > 0x7f)
return -EINVAL;
@@ -1193,10 +1321,10 @@ static ssize_t
sn9c102_store_red(struct class_device* cd, const char* buf, size_t len)
{
ssize_t res = 0;
- u8 value;
+ u16 value;
ssize_t count;
- value = sn9c102_strtou8(buf, len, &count);
+ value = sn9c102_strtou16(buf, len, &count);
if (!count || value > 0x7f)
return -EINVAL;
@@ -1212,7 +1340,8 @@ static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf)
struct sn9c102_device* cam;
ssize_t count;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam)
return -ENODEV;
@@ -1243,30 +1372,36 @@ static CLASS_DEVICE_ATTR(frame_header, S_IRUGO,
static int sn9c102_create_sysfs(struct sn9c102_device* cam)
{
struct video_device *v4ldev = cam->v4ldev;
- int rc;
+ int err = 0;
- rc = video_device_create_file(v4ldev, &class_device_attr_reg);
- if (rc) goto err;
- rc = video_device_create_file(v4ldev, &class_device_attr_val);
- if (rc) goto err_reg;
- rc = video_device_create_file(v4ldev, &class_device_attr_frame_header);
- if (rc) goto err_val;
+ if ((err = video_device_create_file(v4ldev, &class_device_attr_reg)))
+ goto err_out;
+ if ((err = video_device_create_file(v4ldev, &class_device_attr_val)))
+ goto err_reg;
+ if ((err = video_device_create_file(v4ldev,
+ &class_device_attr_frame_header)))
+ goto err_val;
if (cam->sensor.sysfs_ops) {
- rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
- if (rc) goto err_frhead;
- rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val);
- if (rc) goto err_i2c_reg;
+ if ((err = video_device_create_file(v4ldev,
+ &class_device_attr_i2c_reg)))
+ goto err_frame_header;
+ if ((err = video_device_create_file(v4ldev,
+ &class_device_attr_i2c_val)))
+ goto err_i2c_reg;
}
if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
- rc = video_device_create_file(v4ldev, &class_device_attr_green);
- if (rc) goto err_i2c_val;
- } else if (cam->bridge == BRIDGE_SN9C103) {
- rc = video_device_create_file(v4ldev, &class_device_attr_blue);
- if (rc) goto err_i2c_val;
- rc = video_device_create_file(v4ldev, &class_device_attr_red);
- if (rc) goto err_blue;
+ if ((err = video_device_create_file(v4ldev,
+ &class_device_attr_green)))
+ goto err_i2c_val;
+ } else {
+ if ((err = video_device_create_file(v4ldev,
+ &class_device_attr_blue)))
+ goto err_i2c_val;
+ if ((err = video_device_create_file(v4ldev,
+ &class_device_attr_red)))
+ goto err_blue;
}
return 0;
@@ -1279,14 +1414,14 @@ err_i2c_val:
err_i2c_reg:
if (cam->sensor.sysfs_ops)
video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
-err_frhead:
+err_frame_header:
video_device_remove_file(v4ldev, &class_device_attr_frame_header);
err_val:
video_device_remove_file(v4ldev, &class_device_attr_val);
err_reg:
video_device_remove_file(v4ldev, &class_device_attr_reg);
-err:
- return rc;
+err_out:
+ return err;
}
#endif /* CONFIG_VIDEO_ADV_DEBUG */
@@ -1297,10 +1432,36 @@ sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix)
{
int err = 0;
- if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
- err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, 0x18);
- else
- err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, 0x18);
+ if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X ||
+ pix->pixelformat == V4L2_PIX_FMT_JPEG) {
+ switch (cam->bridge) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
+ err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80,
+ 0x18);
+ break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f,
+ 0x18);
+ break;
+ }
+ } else {
+ switch (cam->bridge) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
+ err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f,
+ 0x18);
+ break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80,
+ 0x18);
+ break;
+ }
+ }
return err ? -EIO : 0;
}
@@ -1310,12 +1471,46 @@ static int
sn9c102_set_compression(struct sn9c102_device* cam,
struct v4l2_jpegcompression* compression)
{
- int err = 0;
+ int i, err = 0;
+ switch (cam->bridge) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
if (compression->quality == 0)
- err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17);
+ err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01,
+ 0x17);
else if (compression->quality == 1)
- err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17);
+ err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe,
+ 0x17);
+ break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ if (compression->quality == 0) {
+ for (i = 0; i <= 63; i++) {
+ err += sn9c102_write_reg(cam,
+ SN9C102_Y_QTABLE0[i],
+ 0x100 + i);
+ err += sn9c102_write_reg(cam,
+ SN9C102_UV_QTABLE0[i],
+ 0x140 + i);
+ }
+ err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf,
+ 0x18);
+ } else if (compression->quality == 1) {
+ for (i = 0; i <= 63; i++) {
+ err += sn9c102_write_reg(cam,
+ SN9C102_Y_QTABLE1[i],
+ 0x100 + i);
+ err += sn9c102_write_reg(cam,
+ SN9C102_UV_QTABLE1[i],
+ 0x140 + i);
+ }
+ err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x40,
+ 0x18);
+ }
+ break;
+ }
return err ? -EIO : 0;
}
@@ -1399,7 +1594,16 @@ static int sn9c102_init(struct sn9c102_device* cam)
}
if (!(cam->state & DEV_INITIALIZED))
- cam->compression.quality = cam->reg[0x17] & 0x01 ? 0 : 1;
+ if (cam->bridge == BRIDGE_SN9C101 ||
+ cam->bridge == BRIDGE_SN9C102 ||
+ cam->bridge == BRIDGE_SN9C103) {
+ cam->compression.quality = cam->reg[0x17] & 0x01 ?
+ 0 : 1;
+ } else {
+ cam->compression.quality = cam->reg[0x18] & 0x40 ?
+ 0 : 1;
+ err += sn9c102_set_compression(cam, &cam->compression);
+ }
else
err += sn9c102_set_compression(cam, &cam->compression);
err += sn9c102_set_pix_format(cam, &s->pix_format);
@@ -1408,7 +1612,8 @@ static int sn9c102_init(struct sn9c102_device* cam)
if (err)
return err;
- if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+ if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X ||
+ s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
DBG(3, "Compressed video format is active, quality %d",
cam->compression.quality);
else
@@ -1490,6 +1695,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
if (cam->users) {
DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+ DBG(3, "Simultaneous opens are not supported");
if ((filp->f_flags & O_NONBLOCK) ||
(filp->f_flags & O_NDELAY)) {
err = -EWOULDBLOCK;
@@ -1628,6 +1834,17 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
mutex_unlock(&cam->fileop_mutex);
return -EAGAIN;
}
+ if (!cam->module_param.frame_timeout) {
+ err = wait_event_interruptible
+ ( cam->wait_frame,
+ (!list_empty(&cam->outqueue)) ||
+ (cam->state & DEV_DISCONNECTED) ||
+ (cam->state & DEV_MISCONFIGURED) );
+ if (err) {
+ mutex_unlock(&cam->fileop_mutex);
+ return err;
+ }
+ } else {
timeout = wait_event_interruptible_timeout
( cam->wait_frame,
(!list_empty(&cam->outqueue)) ||
@@ -1638,12 +1855,18 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
if (timeout < 0) {
mutex_unlock(&cam->fileop_mutex);
return timeout;
+ } else if (timeout == 0 &&
+ !(cam->state & DEV_DISCONNECTED)) {
+ DBG(1, "Video frame timeout elapsed");
+ mutex_unlock(&cam->fileop_mutex);
+ return -EIO;
+ }
}
if (cam->state & DEV_DISCONNECTED) {
mutex_unlock(&cam->fileop_mutex);
return -ENODEV;
}
- if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
+ if (cam->state & DEV_MISCONFIGURED) {
mutex_unlock(&cam->fileop_mutex);
return -EIO;
}
@@ -1940,6 +2163,9 @@ exit:
if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
return -EFAULT;
+ PDBGG("VIDIOC_G_CTRL: id %lu, value %lu",
+ (unsigned long)ctrl.id, (unsigned long)ctrl.value);
+
return err;
}
@@ -2127,6 +2353,45 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
static int
+sn9c102_vidioc_enum_framesizes(struct sn9c102_device* cam, void __user * arg)
+{
+ struct v4l2_frmsizeenum frmsize;
+
+ if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
+ return -EFAULT;
+
+ if (frmsize.index != 0)
+ return -EINVAL;
+
+ switch (cam->bridge) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
+ if (frmsize.pixel_format != V4L2_PIX_FMT_SN9C10X &&
+ frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8)
+ return -EINVAL;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ if (frmsize.pixel_format != V4L2_PIX_FMT_JPEG &&
+ frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8)
+ return -EINVAL;
+ }
+
+ frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16;
+ frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16;
+ frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width;
+ frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height;
+ memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
+
+ if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+static int
sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
{
struct v4l2_fmtdesc fmtd;
@@ -2134,12 +2399,26 @@ sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
return -EFAULT;
+ if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
if (fmtd.index == 0) {
strcpy(fmtd.description, "bayer rgb");
fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
} else if (fmtd.index == 1) {
+ switch (cam->bridge) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
strcpy(fmtd.description, "compressed");
fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
+ break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ strcpy(fmtd.description, "JPEG");
+ fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
+ break;
+ }
fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
} else
return -EINVAL;
@@ -2166,7 +2445,8 @@ sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
+ pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X ||
+ pfmt->pixelformat==V4L2_PIX_FMT_JPEG)
? 0 : (pfmt->width * pfmt->priv) / 8;
pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
pfmt->field = V4L2_FIELD_NONE;
@@ -2237,12 +2517,25 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
pix->width = rect.width / scale;
pix->height = rect.height / scale;
+ switch (cam->bridge) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
pix->pixelformat = pfmt->pixelformat;
+ break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ if (pix->pixelformat != V4L2_PIX_FMT_JPEG &&
+ pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
+ pix->pixelformat = pfmt->pixelformat;
+ break;
+ }
pix->priv = pfmt->priv; /* bpp */
pix->colorspace = pfmt->colorspace;
- pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+ pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X ||
+ pix->pixelformat == V4L2_PIX_FMT_JPEG)
? 0 : (pix->width * pix->priv) / 8;
pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
pix->field = V4L2_FIELD_NONE;
@@ -2315,8 +2608,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
static int
sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg)
{
- if (copy_to_user(arg, &cam->compression,
- sizeof(cam->compression)))
+ if (copy_to_user(arg, &cam->compression, sizeof(cam->compression)))
return -EFAULT;
return 0;
@@ -2471,6 +2763,7 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
struct sn9c102_frame_t *f;
unsigned long lock_flags;
long timeout;
+ int err = 0;
if (copy_from_user(&b, arg, sizeof(b)))
return -EFAULT;
@@ -2483,6 +2776,15 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
return -EINVAL;
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
+ if (!cam->module_param.frame_timeout) {
+ err = wait_event_interruptible
+ ( cam->wait_frame,
+ (!list_empty(&cam->outqueue)) ||
+ (cam->state & DEV_DISCONNECTED) ||
+ (cam->state & DEV_MISCONFIGURED) );
+ if (err)
+ return err;
+ } else {
timeout = wait_event_interruptible_timeout
( cam->wait_frame,
(!list_empty(&cam->outqueue)) ||
@@ -2492,9 +2794,15 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
1000 * msecs_to_jiffies(1) );
if (timeout < 0)
return timeout;
+ else if (timeout == 0 &&
+ !(cam->state & DEV_DISCONNECTED)) {
+ DBG(1, "Video frame timeout elapsed");
+ return -EIO;
+ }
+ }
if (cam->state & DEV_DISCONNECTED)
return -ENODEV;
- if (!timeout || (cam->state & DEV_MISCONFIGURED))
+ if (cam->state & DEV_MISCONFIGURED)
return -EIO;
}
@@ -2612,6 +2920,70 @@ sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg)
}
+static int
+sn9c102_vidioc_enumaudio(struct sn9c102_device* cam, void __user * arg)
+{
+ struct v4l2_audio audio;
+
+ if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
+ return -EINVAL;
+
+ if (copy_from_user(&audio, arg, sizeof(audio)))
+ return -EFAULT;
+
+ if (audio.index != 0)
+ return -EINVAL;
+
+ strcpy(audio.name, "Microphone");
+ audio.capability = 0;
+ audio.mode = 0;
+
+ if (copy_to_user(arg, &audio, sizeof(audio)))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+static int
+sn9c102_vidioc_g_audio(struct sn9c102_device* cam, void __user * arg)
+{
+ struct v4l2_audio audio;
+
+ if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
+ return -EINVAL;
+
+ if (copy_from_user(&audio, arg, sizeof(audio)))
+ return -EFAULT;
+
+ memset(&audio, 0, sizeof(audio));
+ strcpy(audio.name, "Microphone");
+
+ if (copy_to_user(arg, &audio, sizeof(audio)))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+static int
+sn9c102_vidioc_s_audio(struct sn9c102_device* cam, void __user * arg)
+{
+ struct v4l2_audio audio;
+
+ if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
+ return -EINVAL;
+
+ if (copy_from_user(&audio, arg, sizeof(audio)))
+ return -EFAULT;
+
+ if (audio.index != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+
static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
unsigned int cmd, void __user * arg)
{
@@ -2649,6 +3021,9 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_S_CROP:
return sn9c102_vidioc_s_crop(cam, arg);
+ case VIDIOC_ENUM_FRAMESIZES:
+ return sn9c102_vidioc_enum_framesizes(cam, arg);
+
case VIDIOC_ENUM_FMT:
return sn9c102_vidioc_enum_fmt(cam, arg);
@@ -2689,11 +3064,21 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_S_PARM:
return sn9c102_vidioc_s_parm(cam, arg);
+ case VIDIOC_ENUMAUDIO:
+ return sn9c102_vidioc_enumaudio(cam, arg);
+
+ case VIDIOC_G_AUDIO:
+ return sn9c102_vidioc_g_audio(cam, arg);
+
+ case VIDIOC_S_AUDIO:
+ return sn9c102_vidioc_s_audio(cam, arg);
+
case VIDIOC_G_STD:
case VIDIOC_S_STD:
case VIDIOC_QUERYSTD:
case VIDIOC_ENUMSTD:
case VIDIOC_QUERYMENU:
+ case VIDIOC_ENUM_FRAMEINTERVALS:
return -EINVAL;
default:
@@ -2741,6 +3126,7 @@ static const struct file_operations sn9c102_fops = {
.open = sn9c102_open,
.release = sn9c102_release,
.ioctl = sn9c102_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.read = sn9c102_read,
.poll = sn9c102_poll,
.mmap = sn9c102_mmap,
@@ -2765,7 +3151,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
cam->usbdev = udev;
if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
- DBG(1, "kmalloc() failed");
+ DBG(1, "kzalloc() failed");
err = -ENOMEM;
goto fail;
}
@@ -2779,24 +3165,31 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
mutex_init(&cam->dev_mutex);
r = sn9c102_read_reg(cam, 0x00);
- if (r < 0 || r != 0x10) {
- DBG(1, "Sorry, this is not a SN9C10x based camera "
- "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+ if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) {
+ DBG(1, "Sorry, this is not a SN9C1xx based camera "
+ "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
err = -ENODEV;
goto fail;
}
- cam->bridge = (id->idProduct & 0xffc0) == 0x6080 ?
- BRIDGE_SN9C103 : BRIDGE_SN9C102;
+ cam->bridge = id->driver_info;
switch (cam->bridge) {
case BRIDGE_SN9C101:
case BRIDGE_SN9C102:
DBG(2, "SN9C10[12] PC Camera Controller detected "
- "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+ "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
break;
case BRIDGE_SN9C103:
DBG(2, "SN9C103 PC Camera Controller detected "
- "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+ "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+ break;
+ case BRIDGE_SN9C105:
+ DBG(2, "SN9C105 PC Camera Controller detected "
+ "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+ break;
+ case BRIDGE_SN9C120:
+ DBG(2, "SN9C120 PC Camera Controller detected "
+ "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
break;
}
@@ -2816,12 +3209,18 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
goto fail;
}
+ if (!(cam->bridge & cam->sensor.supported_bridge)) {
+ DBG(1, "Bridge not supported");
+ err = -ENODEV;
+ goto fail;
+ }
+
if (sn9c102_init(cam)) {
DBG(1, "Initialization failed. I will retry on open().");
cam->state |= DEV_MISCONFIGURED;
}
- strcpy(cam->v4ldev->name, "SN9C10x PC Camera");
+ strcpy(cam->v4ldev->name, "SN9C1xx PC Camera");
cam->v4ldev->owner = THIS_MODULE;
cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
cam->v4ldev->hardware = 0;
@@ -2838,7 +3237,10 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
DBG(1, "V4L2 device registration failed");
if (err == -ENFILE && video_nr[dev_nr] == -1)
DBG(1, "Free /dev/videoX node not found");
- goto fail2;
+ video_nr[dev_nr] = -1;
+ dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
+ mutex_unlock(&cam->dev_mutex);
+ goto fail;
}
DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
@@ -2850,9 +3252,14 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
#ifdef CONFIG_VIDEO_ADV_DEBUG
err = sn9c102_create_sysfs(cam);
- if (err)
- goto fail3;
- DBG(2, "Optional device control through 'sysfs' interface ready");
+ if (!err)
+ DBG(2, "Optional device control through 'sysfs' "
+ "interface ready");
+ else
+ DBG(2, "Failed to create optional 'sysfs' interface for "
+ "device controlling. Error #%d", err);
+#else
+ DBG(2, "Optional device control through 'sysfs' interface disabled");
#endif
usb_set_intfdata(intf, cam);
@@ -2861,14 +3268,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
return 0;
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-fail3:
- video_unregister_device(cam->v4ldev);
-#endif
-fail2:
- video_nr[dev_nr] = -1;
- dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
- mutex_unlock(&cam->dev_mutex);
fail:
if (cam) {
kfree(cam->control_buffer);
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
new file mode 100644
index 00000000000..3a682eca6c6
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -0,0 +1,142 @@
+/***************************************************************************
+ * Table of device identifiers of the SN9C1xx PC Camera Controllers *
+ * *
+ * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the Free Software *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
+ ***************************************************************************/
+
+#ifndef _SN9C102_DEVTABLE_H_
+#define _SN9C102_DEVTABLE_H_
+
+#include <linux/usb.h>
+
+struct sn9c102_device;
+
+/*
+ Each SN9C1xx camera has proper PID/VID identifiers.
+ SN9C103, SN9C105, SN9C120 support multiple interfaces, but we only have to
+ handle the video class interface.
+*/
+#define SN9C102_USB_DEVICE(vend, prod, bridge) \
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+ USB_DEVICE_ID_MATCH_INT_CLASS, \
+ .idVendor = (vend), \
+ .idProduct = (prod), \
+ .bInterfaceClass = 0xff, \
+ .driver_info = (bridge)
+
+static const struct usb_device_id sn9c102_id_table[] = {
+ /* SN9C101 and SN9C102 */
+ { SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6028, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x603f, BRIDGE_SN9C102), },
+ /* SN9C103 */
+ { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), },
+ /* SN9C105 */
+ { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), },
+ /* SN9C120 */
+ { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), },
+ { }
+};
+
+/*
+ Probing functions: on success, you must attach the sensor to the camera
+ by calling sn9c102_attach_sensor().
+ To enable the I2C communication, you might need to perform a really basic
+ initialization of the SN9C1XX chip.
+ Functions must return 0 on success, the appropriate error otherwise.
+*/
+extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
+extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
+extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
+extern int sn9c102_probe_ov7660(struct sn9c102_device* cam);
+extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
+extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
+extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
+extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
+
+/*
+ Add the above entries to this table. Be sure to add the entry in the right
+ place, since, on failure, the next probing routine is called according to
+ the order of the list below, from top to bottom.
+*/
+static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {
+ &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */
+ &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */
+ &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */
+ &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */
+ &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */
+ &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */
+ &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */
+ &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */
+ NULL,
+};
+
+#endif /* _SN9C102_DEVTABLE_H_ */
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131d.c b/drivers/media/video/sn9c102/sn9c102_hv7131d.c
index c4117bf64b6..7ae368f60d8 100644
--- a/drivers/media/video/sn9c102/sn9c102_hv7131d.c
+++ b/drivers/media/video/sn9c102/sn9c102_hv7131d.c
@@ -1,8 +1,8 @@
/***************************************************************************
- * Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for HV7131D image sensor connected to the SN9C1xx PC Camera *
* Controllers *
* *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* 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 *
@@ -124,7 +124,7 @@ static int hv7131d_set_ctrl(struct sn9c102_device* cam,
static int hv7131d_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
- struct sn9c102_sensor* s = &hv7131d;
+ struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
@@ -153,6 +153,7 @@ static int hv7131d_set_pix_format(struct sn9c102_device* cam,
static struct sn9c102_sensor hv7131d = {
.name = "HV7131D",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_2WIRES,
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0343.c b/drivers/media/video/sn9c102/sn9c102_mi0343.c
index 4169ea4a2e2..a33d1bc10f9 100644
--- a/drivers/media/video/sn9c102/sn9c102_mi0343.c
+++ b/drivers/media/video/sn9c102/sn9c102_mi0343.c
@@ -1,8 +1,8 @@
/***************************************************************************
- * Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for MI-0343 image sensor connected to the SN9C1xx PC Camera *
* Controllers *
* *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* 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 *
@@ -201,7 +201,7 @@ static int mi0343_set_ctrl(struct sn9c102_device* cam,
static int mi0343_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
- struct sn9c102_sensor* s = &mi0343;
+ struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
@@ -237,6 +237,7 @@ static int mi0343_set_pix_format(struct sn9c102_device* cam,
static struct sn9c102_sensor mi0343 = {
.name = "MI-0343",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_2WIRES,
.i2c_slave_id = 0x5d,
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7630.c b/drivers/media/video/sn9c102/sn9c102_ov7630.c
index 3da04202178..7df09ff38e6 100644
--- a/drivers/media/video/sn9c102/sn9c102_ov7630.c
+++ b/drivers/media/video/sn9c102/sn9c102_ov7630.c
@@ -1,8 +1,8 @@
/***************************************************************************
- * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for OV7630 image sensor connected to the SN9C1xx PC Camera *
* Controllers *
* *
- * Copyright (C) 2005-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* 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 *
@@ -29,13 +29,17 @@ static int ov7630_init(struct sn9c102_device* cam)
{
int err = 0;
+ switch (sn9c102_get_bridge(cam)) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
err += sn9c102_write_reg(cam, 0x00, 0x14);
err += sn9c102_write_reg(cam, 0x60, 0x17);
err += sn9c102_write_reg(cam, 0x0f, 0x18);
err += sn9c102_write_reg(cam, 0x50, 0x19);
- err += sn9c102_i2c_write(cam, 0x12, 0x80);
- err += sn9c102_i2c_write(cam, 0x11, 0x01);
+ err += sn9c102_i2c_write(cam, 0x12, 0x8d);
+ err += sn9c102_i2c_write(cam, 0x12, 0x0d);
+ err += sn9c102_i2c_write(cam, 0x11, 0x00);
err += sn9c102_i2c_write(cam, 0x15, 0x34);
err += sn9c102_i2c_write(cam, 0x16, 0x03);
err += sn9c102_i2c_write(cam, 0x17, 0x1c);
@@ -43,14 +47,72 @@ static int ov7630_init(struct sn9c102_device* cam)
err += sn9c102_i2c_write(cam, 0x19, 0x06);
err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
err += sn9c102_i2c_write(cam, 0x1b, 0x04);
- err += sn9c102_i2c_write(cam, 0x20, 0xf6);
+ err += sn9c102_i2c_write(cam, 0x20, 0x44);
+ err += sn9c102_i2c_write(cam, 0x23, 0xee);
+ err += sn9c102_i2c_write(cam, 0x26, 0xa0);
+ err += sn9c102_i2c_write(cam, 0x27, 0x9a);
+ err += sn9c102_i2c_write(cam, 0x28, 0x20);
+ err += sn9c102_i2c_write(cam, 0x29, 0x30);
+ err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
+ err += sn9c102_i2c_write(cam, 0x30, 0x24);
+ err += sn9c102_i2c_write(cam, 0x32, 0x86);
+ err += sn9c102_i2c_write(cam, 0x60, 0xa9);
+ err += sn9c102_i2c_write(cam, 0x61, 0x42);
+ err += sn9c102_i2c_write(cam, 0x65, 0x00);
+ err += sn9c102_i2c_write(cam, 0x69, 0x38);
+ err += sn9c102_i2c_write(cam, 0x6f, 0x88);
+ err += sn9c102_i2c_write(cam, 0x70, 0x0b);
+ err += sn9c102_i2c_write(cam, 0x71, 0x00);
+ err += sn9c102_i2c_write(cam, 0x74, 0x21);
+ err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
+ break;
+ case BRIDGE_SN9C103:
+ err += sn9c102_write_reg(cam, 0x00, 0x02);
+ err += sn9c102_write_reg(cam, 0x00, 0x03);
+ err += sn9c102_write_reg(cam, 0x1a, 0x04);
+ err += sn9c102_write_reg(cam, 0x20, 0x05);
+ err += sn9c102_write_reg(cam, 0x20, 0x06);
+ err += sn9c102_write_reg(cam, 0x20, 0x07);
+ err += sn9c102_write_reg(cam, 0x03, 0x10);
+ err += sn9c102_write_reg(cam, 0x0a, 0x14);
+ err += sn9c102_write_reg(cam, 0x60, 0x17);
+ err += sn9c102_write_reg(cam, 0x0f, 0x18);
+ err += sn9c102_write_reg(cam, 0x50, 0x19);
+ err += sn9c102_write_reg(cam, 0x1d, 0x1a);
+ err += sn9c102_write_reg(cam, 0x10, 0x1b);
+ err += sn9c102_write_reg(cam, 0x02, 0x1c);
+ err += sn9c102_write_reg(cam, 0x03, 0x1d);
+ err += sn9c102_write_reg(cam, 0x0f, 0x1e);
+ err += sn9c102_write_reg(cam, 0x0c, 0x1f);
+ err += sn9c102_write_reg(cam, 0x00, 0x20);
+ err += sn9c102_write_reg(cam, 0x10, 0x21);
+ err += sn9c102_write_reg(cam, 0x20, 0x22);
+ err += sn9c102_write_reg(cam, 0x30, 0x23);
+ err += sn9c102_write_reg(cam, 0x40, 0x24);
+ err += sn9c102_write_reg(cam, 0x50, 0x25);
+ err += sn9c102_write_reg(cam, 0x60, 0x26);
+ err += sn9c102_write_reg(cam, 0x70, 0x27);
+ err += sn9c102_write_reg(cam, 0x80, 0x28);
+ err += sn9c102_write_reg(cam, 0x90, 0x29);
+ err += sn9c102_write_reg(cam, 0xa0, 0x2a);
+ err += sn9c102_write_reg(cam, 0xb0, 0x2b);
+ err += sn9c102_write_reg(cam, 0xc0, 0x2c);
+ err += sn9c102_write_reg(cam, 0xd0, 0x2d);
+ err += sn9c102_write_reg(cam, 0xe0, 0x2e);
+ err += sn9c102_write_reg(cam, 0xf0, 0x2f);
+ err += sn9c102_write_reg(cam, 0xff, 0x30);
+
+ err += sn9c102_i2c_write(cam, 0x12, 0x8d);
+ err += sn9c102_i2c_write(cam, 0x12, 0x0d);
+ err += sn9c102_i2c_write(cam, 0x15, 0x34);
+ err += sn9c102_i2c_write(cam, 0x11, 0x01);
+ err += sn9c102_i2c_write(cam, 0x1b, 0x04);
+ err += sn9c102_i2c_write(cam, 0x20, 0x44);
err += sn9c102_i2c_write(cam, 0x23, 0xee);
err += sn9c102_i2c_write(cam, 0x26, 0xa0);
err += sn9c102_i2c_write(cam, 0x27, 0x9a);
- err += sn9c102_i2c_write(cam, 0x28, 0xa0);
+ err += sn9c102_i2c_write(cam, 0x28, 0x20);
err += sn9c102_i2c_write(cam, 0x29, 0x30);
- err += sn9c102_i2c_write(cam, 0x2a, 0xa0);
- err += sn9c102_i2c_write(cam, 0x2b, 0x1f);
err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
err += sn9c102_i2c_write(cam, 0x30, 0x24);
err += sn9c102_i2c_write(cam, 0x32, 0x86);
@@ -63,45 +125,97 @@ static int ov7630_init(struct sn9c102_device* cam)
err += sn9c102_i2c_write(cam, 0x71, 0x00);
err += sn9c102_i2c_write(cam, 0x74, 0x21);
err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
+ break;
+ default:
+ break;
+ }
return err;
}
-static int ov7630_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
+static int ov7630_get_ctrl(struct sn9c102_device* cam,
+ struct v4l2_control* ctrl)
{
int err = 0;
switch (ctrl->id) {
case V4L2_CID_EXPOSURE:
- err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2);
- err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03);
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
+ return -EIO;
break;
case V4L2_CID_RED_BALANCE:
- err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
+ ctrl->value = sn9c102_pread_reg(cam, 0x07);
break;
case V4L2_CID_BLUE_BALANCE:
- err += sn9c102_i2c_write(cam, 0x01, ctrl->value);
+ ctrl->value = sn9c102_pread_reg(cam, 0x06);
+ break;
+ case SN9C102_V4L2_CID_GREEN_BALANCE:
+ ctrl->value = sn9c102_pread_reg(cam, 0x05);
break;
case V4L2_CID_GAIN:
- err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
+ return -EIO;
+ ctrl->value &= 0x3f;
+ break;
+ case V4L2_CID_DO_WHITE_BALANCE:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
+ return -EIO;
+ ctrl->value &= 0x3f;
+ break;
+ case V4L2_CID_WHITENESS:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0)
+ return -EIO;
+ ctrl->value &= 0x3f;
+ break;
+ case V4L2_CID_AUTOGAIN:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0)
+ return -EIO;
+ ctrl->value &= 0x01;
+ break;
+ case V4L2_CID_VFLIP:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x75)) < 0)
+ return -EIO;
+ ctrl->value = (ctrl->value & 0x80) ? 1 : 0;
+ break;
+ case SN9C102_V4L2_CID_GAMMA:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x14)) < 0)
+ return -EIO;
+ ctrl->value = (ctrl->value & 0x02) ? 1 : 0;
+ break;
+ case SN9C102_V4L2_CID_BAND_FILTER:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x2d)) < 0)
+ return -EIO;
+ ctrl->value = (ctrl->value & 0x02) ? 1 : 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err ? -EIO : 0;
+}
+
+
+static int ov7630_set_ctrl(struct sn9c102_device* cam,
+ const struct v4l2_control* ctrl)
+{
+ int err = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
break;
- case V4L2_CID_CONTRAST:
- err += ctrl->value ? sn9c102_i2c_write(cam, 0x05,
- (ctrl->value-1) | 0x20)
- : sn9c102_i2c_write(cam, 0x05, 0x00);
+ case V4L2_CID_RED_BALANCE:
+ err += sn9c102_write_reg(cam, ctrl->value, 0x07);
break;
- case V4L2_CID_BRIGHTNESS:
- err += sn9c102_i2c_write(cam, 0x06, ctrl->value);
+ case V4L2_CID_BLUE_BALANCE:
+ err += sn9c102_write_reg(cam, ctrl->value, 0x06);
break;
- case V4L2_CID_SATURATION:
- err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4);
+ case SN9C102_V4L2_CID_GREEN_BALANCE:
+ err += sn9c102_write_reg(cam, ctrl->value, 0x05);
break;
- case V4L2_CID_HUE:
- err += ctrl->value ? sn9c102_i2c_write(cam, 0x04,
- (ctrl->value-1) | 0x20)
- : sn9c102_i2c_write(cam, 0x04, 0x00);
+ case V4L2_CID_GAIN:
+ err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
break;
case V4L2_CID_DO_WHITE_BALANCE:
err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
@@ -109,23 +223,15 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
case V4L2_CID_WHITENESS:
err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
break;
- case V4L2_CID_AUTO_WHITE_BALANCE:
- err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78);
- break;
case V4L2_CID_AUTOGAIN:
- err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
+ err += sn9c102_i2c_write(cam, 0x13, ctrl->value |
+ (ctrl->value << 1));
break;
case V4L2_CID_VFLIP:
err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7));
break;
- case V4L2_CID_BLACK_LEVEL:
- err += sn9c102_i2c_write(cam, 0x25, ctrl->value);
- break;
- case SN9C102_V4L2_CID_BRIGHT_LEVEL:
- err += sn9c102_i2c_write(cam, 0x24, ctrl->value);
- break;
case SN9C102_V4L2_CID_GAMMA:
- err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80);
+ err += sn9c102_i2c_write(cam, 0x14, ctrl->value << 2);
break;
case SN9C102_V4L2_CID_BAND_FILTER:
err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2);
@@ -141,10 +247,12 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
static int ov7630_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
- struct sn9c102_sensor* s = &ov7630;
+ struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
int err = 0;
- u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+ u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
+ v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+ err += sn9c102_write_reg(cam, h_start, 0x12);
err += sn9c102_write_reg(cam, v_start, 0x13);
return err;
@@ -168,7 +276,8 @@ static int ov7630_set_pix_format(struct sn9c102_device* cam,
static struct sn9c102_sensor ov7630 = {
.name = "OV7630",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .sysfs_ops = SN9C102_I2C_WRITE,
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
+ .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_2WIRES,
.i2c_slave_id = 0x21,
@@ -185,73 +294,23 @@ static struct sn9c102_sensor ov7630 = {
.flags = 0,
},
{
- .id = V4L2_CID_HUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "hue",
- .minimum = 0x00,
- .maximum = 0x1f+1,
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "saturation",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x08,
- .flags = 0,
- },
- {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "contrast",
- .minimum = 0x00,
- .maximum = 0x1f+1,
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- {
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "exposure",
- .minimum = 0x000,
- .maximum = 0x3ff,
- .step = 0x001,
- .default_value = 0x83<<2,
- .flags = 0,
- },
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = 0x3a,
- .flags = 0,
- },
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
.minimum = 0x00,
.maximum = 0xff,
.step = 0x01,
- .default_value = 0x77,
+ .default_value = 0x60,
.flags = 0,
},
{
- .id = V4L2_CID_BRIGHTNESS,
+ .id = V4L2_CID_WHITENESS,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "brightness",
+ .name = "white balance background: red",
.minimum = 0x00,
- .maximum = 0xff,
+ .maximum = 0x3f,
.step = 0x01,
- .default_value = 0xa0,
+ .default_value = 0x20,
.flags = 0,
},
{
@@ -265,31 +324,31 @@ static struct sn9c102_sensor ov7630 = {
.flags = 0,
},
{
- .id = V4L2_CID_WHITENESS,
+ .id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "white balance background: red",
+ .name = "red balance",
.minimum = 0x00,
- .maximum = 0x3f,
+ .maximum = 0x7f,
.step = 0x01,
.default_value = 0x20,
.flags = 0,
},
{
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto white balance",
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "blue balance",
.minimum = 0x00,
- .maximum = 0x01,
+ .maximum = 0x7f,
.step = 0x01,
- .default_value = 0x01,
+ .default_value = 0x20,
.flags = 0,
},
{
.id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain & exposure mode",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto adjust",
.minimum = 0x00,
- .maximum = 0x03,
+ .maximum = 0x01,
.step = 0x01,
.default_value = 0x00,
.flags = 0,
@@ -305,23 +364,13 @@ static struct sn9c102_sensor ov7630 = {
.flags = 0,
},
{
- .id = V4L2_CID_BLACK_LEVEL,
+ .id = SN9C102_V4L2_CID_GREEN_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "black pixel ratio",
- .minimum = 0x01,
- .maximum = 0x9a,
- .step = 0x01,
- .default_value = 0x8a,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_BRIGHT_LEVEL,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "bright pixel ratio",
- .minimum = 0x01,
- .maximum = 0x9a,
+ .name = "green balance",
+ .minimum = 0x00,
+ .maximum = 0x7f,
.step = 0x01,
- .default_value = 0x10,
+ .default_value = 0x20,
.flags = 0,
},
{
@@ -345,6 +394,7 @@ static struct sn9c102_sensor ov7630 = {
.flags = 0,
},
},
+ .get_ctrl = &ov7630_get_ctrl,
.set_ctrl = &ov7630_set_ctrl,
.cropcap = {
.bounds = {
@@ -364,7 +414,7 @@ static struct sn9c102_sensor ov7630 = {
.pix_format = {
.width = 640,
.height = 480,
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
+ .pixelformat = V4L2_PIX_FMT_SN9C10X,
.priv = 8,
},
.set_pix_format = &ov7630_set_pix_format
@@ -373,28 +423,36 @@ static struct sn9c102_sensor ov7630 = {
int sn9c102_probe_ov7630(struct sn9c102_device* cam)
{
- const struct usb_device_id ov7630_id_table[] = {
- { USB_DEVICE(0x0c45, 0x602c), },
- { USB_DEVICE(0x0c45, 0x602d), },
- { USB_DEVICE(0x0c45, 0x608f), },
- { USB_DEVICE(0x0c45, 0x60b0), },
- { }
- };
- int err = 0;
-
- if (!sn9c102_match_id(cam, ov7630_id_table))
- return -ENODEV;
+ int pid, ver, err = 0;
+ switch (sn9c102_get_bridge(cam)) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
err += sn9c102_write_reg(cam, 0x01, 0x01);
err += sn9c102_write_reg(cam, 0x00, 0x01);
err += sn9c102_write_reg(cam, 0x28, 0x17);
- if (err)
- return -EIO;
+ break;
+ case BRIDGE_SN9C103: /* do _not_ change anything! */
+ err += sn9c102_write_reg(cam, 0x09, 0x01);
+ err += sn9c102_write_reg(cam, 0x42, 0x01);
+ err += sn9c102_write_reg(cam, 0x28, 0x17);
+ err += sn9c102_write_reg(cam, 0x44, 0x02);
+ pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a);
+ if (err || pid < 0) { /* try a different initialization */
+ err = sn9c102_write_reg(cam, 0x01, 0x01);
+ err += sn9c102_write_reg(cam, 0x00, 0x01);
+ }
+ break;
+ default:
+ break;
+ }
- err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0);
- if (err)
+ pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a);
+ ver = sn9c102_i2c_try_read(cam, &ov7630, 0x0b);
+ if (err || pid < 0 || ver < 0)
+ return -EIO;
+ if (pid != 0x76 || ver != 0x31)
return -ENODEV;
-
sn9c102_attach_sensor(cam, &ov7630);
return 0;
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7660.c b/drivers/media/video/sn9c102/sn9c102_ov7660.c
new file mode 100644
index 00000000000..d670c24d443
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_ov7660.c
@@ -0,0 +1,592 @@
+/***************************************************************************
+ * Plug-in for OV7660 image sensor connected to the SN9C1xx PC Camera *
+ * Controllers *
+ * *
+ * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the Free Software *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
+ ***************************************************************************/
+
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor ov7660;
+
+
+static int ov7660_init(struct sn9c102_device* cam)
+{
+ int err = 0;
+
+ err += sn9c102_write_reg(cam, 0x40, 0x02);
+ err += sn9c102_write_reg(cam, 0x00, 0x03);
+ err += sn9c102_write_reg(cam, 0x1a, 0x04);
+ err += sn9c102_write_reg(cam, 0x03, 0x10);
+ err += sn9c102_write_reg(cam, 0x08, 0x14);
+ err += sn9c102_write_reg(cam, 0x20, 0x17);
+ err += sn9c102_write_reg(cam, 0x8b, 0x18);
+ err += sn9c102_write_reg(cam, 0x00, 0x19);
+ err += sn9c102_write_reg(cam, 0x1d, 0x1a);
+ err += sn9c102_write_reg(cam, 0x10, 0x1b);
+ err += sn9c102_write_reg(cam, 0x02, 0x1c);
+ err += sn9c102_write_reg(cam, 0x03, 0x1d);
+ err += sn9c102_write_reg(cam, 0x0f, 0x1e);
+ err += sn9c102_write_reg(cam, 0x0c, 0x1f);
+ err += sn9c102_write_reg(cam, 0x00, 0x20);
+ err += sn9c102_write_reg(cam, 0x29, 0x21);
+ err += sn9c102_write_reg(cam, 0x40, 0x22);
+ err += sn9c102_write_reg(cam, 0x54, 0x23);
+ err += sn9c102_write_reg(cam, 0x66, 0x24);
+ err += sn9c102_write_reg(cam, 0x76, 0x25);
+ err += sn9c102_write_reg(cam, 0x85, 0x26);
+ err += sn9c102_write_reg(cam, 0x94, 0x27);
+ err += sn9c102_write_reg(cam, 0xa1, 0x28);
+ err += sn9c102_write_reg(cam, 0xae, 0x29);
+ err += sn9c102_write_reg(cam, 0xbb, 0x2a);
+ err += sn9c102_write_reg(cam, 0xc7, 0x2b);
+ err += sn9c102_write_reg(cam, 0xd3, 0x2c);
+ err += sn9c102_write_reg(cam, 0xde, 0x2d);
+ err += sn9c102_write_reg(cam, 0xea, 0x2e);
+ err += sn9c102_write_reg(cam, 0xf4, 0x2f);
+ err += sn9c102_write_reg(cam, 0xff, 0x30);
+ err += sn9c102_write_reg(cam, 0x00, 0x3F);
+ err += sn9c102_write_reg(cam, 0xC7, 0x40);
+ err += sn9c102_write_reg(cam, 0x01, 0x41);
+ err += sn9c102_write_reg(cam, 0x44, 0x42);
+ err += sn9c102_write_reg(cam, 0x00, 0x43);
+ err += sn9c102_write_reg(cam, 0x44, 0x44);
+ err += sn9c102_write_reg(cam, 0x00, 0x45);
+ err += sn9c102_write_reg(cam, 0x44, 0x46);
+ err += sn9c102_write_reg(cam, 0x00, 0x47);
+ err += sn9c102_write_reg(cam, 0xC7, 0x48);
+ err += sn9c102_write_reg(cam, 0x01, 0x49);
+ err += sn9c102_write_reg(cam, 0xC7, 0x4A);
+ err += sn9c102_write_reg(cam, 0x01, 0x4B);
+ err += sn9c102_write_reg(cam, 0xC7, 0x4C);
+ err += sn9c102_write_reg(cam, 0x01, 0x4D);
+ err += sn9c102_write_reg(cam, 0x44, 0x4E);
+ err += sn9c102_write_reg(cam, 0x00, 0x4F);
+ err += sn9c102_write_reg(cam, 0x44, 0x50);
+ err += sn9c102_write_reg(cam, 0x00, 0x51);
+ err += sn9c102_write_reg(cam, 0x44, 0x52);
+ err += sn9c102_write_reg(cam, 0x00, 0x53);
+ err += sn9c102_write_reg(cam, 0xC7, 0x54);
+ err += sn9c102_write_reg(cam, 0x01, 0x55);
+ err += sn9c102_write_reg(cam, 0xC7, 0x56);
+ err += sn9c102_write_reg(cam, 0x01, 0x57);
+ err += sn9c102_write_reg(cam, 0xC7, 0x58);
+ err += sn9c102_write_reg(cam, 0x01, 0x59);
+ err += sn9c102_write_reg(cam, 0x44, 0x5A);
+ err += sn9c102_write_reg(cam, 0x00, 0x5B);
+ err += sn9c102_write_reg(cam, 0x44, 0x5C);
+ err += sn9c102_write_reg(cam, 0x00, 0x5D);
+ err += sn9c102_write_reg(cam, 0x44, 0x5E);
+ err += sn9c102_write_reg(cam, 0x00, 0x5F);
+ err += sn9c102_write_reg(cam, 0xC7, 0x60);
+ err += sn9c102_write_reg(cam, 0x01, 0x61);
+ err += sn9c102_write_reg(cam, 0xC7, 0x62);
+ err += sn9c102_write_reg(cam, 0x01, 0x63);
+ err += sn9c102_write_reg(cam, 0xC7, 0x64);
+ err += sn9c102_write_reg(cam, 0x01, 0x65);
+ err += sn9c102_write_reg(cam, 0x44, 0x66);
+ err += sn9c102_write_reg(cam, 0x00, 0x67);
+ err += sn9c102_write_reg(cam, 0x44, 0x68);
+ err += sn9c102_write_reg(cam, 0x00, 0x69);
+ err += sn9c102_write_reg(cam, 0x44, 0x6A);
+ err += sn9c102_write_reg(cam, 0x00, 0x6B);
+ err += sn9c102_write_reg(cam, 0xC7, 0x6C);
+ err += sn9c102_write_reg(cam, 0x01, 0x6D);
+ err += sn9c102_write_reg(cam, 0xC7, 0x6E);
+ err += sn9c102_write_reg(cam, 0x01, 0x6F);
+ err += sn9c102_write_reg(cam, 0xC7, 0x70);
+ err += sn9c102_write_reg(cam, 0x01, 0x71);
+ err += sn9c102_write_reg(cam, 0x44, 0x72);
+ err += sn9c102_write_reg(cam, 0x00, 0x73);
+ err += sn9c102_write_reg(cam, 0x44, 0x74);
+ err += sn9c102_write_reg(cam, 0x00, 0x75);
+ err += sn9c102_write_reg(cam, 0x44, 0x76);
+ err += sn9c102_write_reg(cam, 0x00, 0x77);
+ err += sn9c102_write_reg(cam, 0xC7, 0x78);
+ err += sn9c102_write_reg(cam, 0x01, 0x79);
+ err += sn9c102_write_reg(cam, 0xC7, 0x7A);
+ err += sn9c102_write_reg(cam, 0x01, 0x7B);
+ err += sn9c102_write_reg(cam, 0xC7, 0x7C);
+ err += sn9c102_write_reg(cam, 0x01, 0x7D);
+ err += sn9c102_write_reg(cam, 0x44, 0x7E);
+ err += sn9c102_write_reg(cam, 0x00, 0x7F);
+ err += sn9c102_write_reg(cam, 0x14, 0x84);
+ err += sn9c102_write_reg(cam, 0x00, 0x85);
+ err += sn9c102_write_reg(cam, 0x27, 0x86);
+ err += sn9c102_write_reg(cam, 0x00, 0x87);
+ err += sn9c102_write_reg(cam, 0x07, 0x88);
+ err += sn9c102_write_reg(cam, 0x00, 0x89);
+ err += sn9c102_write_reg(cam, 0xEC, 0x8A);
+ err += sn9c102_write_reg(cam, 0x0f, 0x8B);
+ err += sn9c102_write_reg(cam, 0xD8, 0x8C);
+ err += sn9c102_write_reg(cam, 0x0f, 0x8D);
+ err += sn9c102_write_reg(cam, 0x3D, 0x8E);
+ err += sn9c102_write_reg(cam, 0x00, 0x8F);
+ err += sn9c102_write_reg(cam, 0x3D, 0x90);
+ err += sn9c102_write_reg(cam, 0x00, 0x91);
+ err += sn9c102_write_reg(cam, 0xCD, 0x92);
+ err += sn9c102_write_reg(cam, 0x0f, 0x93);
+ err += sn9c102_write_reg(cam, 0xf7, 0x94);
+ err += sn9c102_write_reg(cam, 0x0f, 0x95);
+ err += sn9c102_write_reg(cam, 0x0C, 0x96);
+ err += sn9c102_write_reg(cam, 0x00, 0x97);
+ err += sn9c102_write_reg(cam, 0x00, 0x98);
+ err += sn9c102_write_reg(cam, 0x66, 0x99);
+ err += sn9c102_write_reg(cam, 0x05, 0x9A);
+ err += sn9c102_write_reg(cam, 0x00, 0x9B);
+ err += sn9c102_write_reg(cam, 0x04, 0x9C);
+ err += sn9c102_write_reg(cam, 0x00, 0x9D);
+ err += sn9c102_write_reg(cam, 0x08, 0x9E);
+ err += sn9c102_write_reg(cam, 0x00, 0x9F);
+ err += sn9c102_write_reg(cam, 0x2D, 0xC0);
+ err += sn9c102_write_reg(cam, 0x2D, 0xC1);
+ err += sn9c102_write_reg(cam, 0x3A, 0xC2);
+ err += sn9c102_write_reg(cam, 0x05, 0xC3);
+ err += sn9c102_write_reg(cam, 0x04, 0xC4);
+ err += sn9c102_write_reg(cam, 0x3F, 0xC5);
+ err += sn9c102_write_reg(cam, 0x00, 0xC6);
+ err += sn9c102_write_reg(cam, 0x00, 0xC7);
+ err += sn9c102_write_reg(cam, 0x50, 0xC8);
+ err += sn9c102_write_reg(cam, 0x3C, 0xC9);
+ err += sn9c102_write_reg(cam, 0x28, 0xCA);
+ err += sn9c102_write_reg(cam, 0xD8, 0xCB);
+ err += sn9c102_write_reg(cam, 0x14, 0xCC);
+ err += sn9c102_write_reg(cam, 0xEC, 0xCD);
+ err += sn9c102_write_reg(cam, 0x32, 0xCE);
+ err += sn9c102_write_reg(cam, 0xDD, 0xCF);
+ err += sn9c102_write_reg(cam, 0x32, 0xD0);
+ err += sn9c102_write_reg(cam, 0xDD, 0xD1);
+ err += sn9c102_write_reg(cam, 0x6A, 0xD2);
+ err += sn9c102_write_reg(cam, 0x50, 0xD3);
+ err += sn9c102_write_reg(cam, 0x00, 0xD4);
+ err += sn9c102_write_reg(cam, 0x00, 0xD5);
+ err += sn9c102_write_reg(cam, 0x00, 0xD6);
+
+ err += sn9c102_i2c_write(cam, 0x12, 0x80);
+ err += sn9c102_i2c_write(cam, 0x11, 0x09);
+ err += sn9c102_i2c_write(cam, 0x00, 0x0A);
+ err += sn9c102_i2c_write(cam, 0x01, 0x78);
+ err += sn9c102_i2c_write(cam, 0x02, 0x90);
+ err += sn9c102_i2c_write(cam, 0x03, 0x00);
+ err += sn9c102_i2c_write(cam, 0x04, 0x00);
+ err += sn9c102_i2c_write(cam, 0x05, 0x08);
+ err += sn9c102_i2c_write(cam, 0x06, 0x0B);
+ err += sn9c102_i2c_write(cam, 0x07, 0x00);
+ err += sn9c102_i2c_write(cam, 0x08, 0x1C);
+ err += sn9c102_i2c_write(cam, 0x09, 0x01);
+ err += sn9c102_i2c_write(cam, 0x0A, 0x76);
+ err += sn9c102_i2c_write(cam, 0x0B, 0x60);
+ err += sn9c102_i2c_write(cam, 0x0C, 0x00);
+ err += sn9c102_i2c_write(cam, 0x0D, 0x08);
+ err += sn9c102_i2c_write(cam, 0x0E, 0x04);
+ err += sn9c102_i2c_write(cam, 0x0F, 0x6F);
+ err += sn9c102_i2c_write(cam, 0x10, 0x20);
+ err += sn9c102_i2c_write(cam, 0x11, 0x03);
+ err += sn9c102_i2c_write(cam, 0x12, 0x05);
+ err += sn9c102_i2c_write(cam, 0x13, 0xF8);
+ err += sn9c102_i2c_write(cam, 0x14, 0x2C);
+ err += sn9c102_i2c_write(cam, 0x15, 0x00);
+ err += sn9c102_i2c_write(cam, 0x16, 0x02);
+ err += sn9c102_i2c_write(cam, 0x17, 0x10);
+ err += sn9c102_i2c_write(cam, 0x18, 0x60);
+ err += sn9c102_i2c_write(cam, 0x19, 0x02);
+ err += sn9c102_i2c_write(cam, 0x1A, 0x7B);
+ err += sn9c102_i2c_write(cam, 0x1B, 0x02);
+ err += sn9c102_i2c_write(cam, 0x1C, 0x7F);
+ err += sn9c102_i2c_write(cam, 0x1D, 0xA2);
+ err += sn9c102_i2c_write(cam, 0x1E, 0x01);
+ err += sn9c102_i2c_write(cam, 0x1F, 0x0E);
+ err += sn9c102_i2c_write(cam, 0x20, 0x05);
+ err += sn9c102_i2c_write(cam, 0x21, 0x05);
+ err += sn9c102_i2c_write(cam, 0x22, 0x05);
+ err += sn9c102_i2c_write(cam, 0x23, 0x05);
+ err += sn9c102_i2c_write(cam, 0x24, 0x68);
+ err += sn9c102_i2c_write(cam, 0x25, 0x58);
+ err += sn9c102_i2c_write(cam, 0x26, 0xD4);
+ err += sn9c102_i2c_write(cam, 0x27, 0x80);
+ err += sn9c102_i2c_write(cam, 0x28, 0x80);
+ err += sn9c102_i2c_write(cam, 0x29, 0x30);
+ err += sn9c102_i2c_write(cam, 0x2A, 0x00);
+ err += sn9c102_i2c_write(cam, 0x2B, 0x00);
+ err += sn9c102_i2c_write(cam, 0x2C, 0x80);
+ err += sn9c102_i2c_write(cam, 0x2D, 0x00);
+ err += sn9c102_i2c_write(cam, 0x2E, 0x00);
+ err += sn9c102_i2c_write(cam, 0x2F, 0x0E);
+ err += sn9c102_i2c_write(cam, 0x30, 0x08);
+ err += sn9c102_i2c_write(cam, 0x31, 0x30);
+ err += sn9c102_i2c_write(cam, 0x32, 0xB4);
+ err += sn9c102_i2c_write(cam, 0x33, 0x00);
+ err += sn9c102_i2c_write(cam, 0x34, 0x07);
+ err += sn9c102_i2c_write(cam, 0x35, 0x84);
+ err += sn9c102_i2c_write(cam, 0x36, 0x00);
+ err += sn9c102_i2c_write(cam, 0x37, 0x0C);
+ err += sn9c102_i2c_write(cam, 0x38, 0x02);
+ err += sn9c102_i2c_write(cam, 0x39, 0x43);
+ err += sn9c102_i2c_write(cam, 0x3A, 0x00);
+ err += sn9c102_i2c_write(cam, 0x3B, 0x02);
+ err += sn9c102_i2c_write(cam, 0x3C, 0x6C);
+ err += sn9c102_i2c_write(cam, 0x3D, 0x99);
+ err += sn9c102_i2c_write(cam, 0x3E, 0x0E);
+ err += sn9c102_i2c_write(cam, 0x3F, 0x41);
+ err += sn9c102_i2c_write(cam, 0x40, 0xC1);
+ err += sn9c102_i2c_write(cam, 0x41, 0x22);
+ err += sn9c102_i2c_write(cam, 0x42, 0x08);
+ err += sn9c102_i2c_write(cam, 0x43, 0xF0);
+ err += sn9c102_i2c_write(cam, 0x44, 0x10);
+ err += sn9c102_i2c_write(cam, 0x45, 0x78);
+ err += sn9c102_i2c_write(cam, 0x46, 0xA8);
+ err += sn9c102_i2c_write(cam, 0x47, 0x60);
+ err += sn9c102_i2c_write(cam, 0x48, 0x80);
+ err += sn9c102_i2c_write(cam, 0x49, 0x00);
+ err += sn9c102_i2c_write(cam, 0x4A, 0x00);
+ err += sn9c102_i2c_write(cam, 0x4B, 0x00);
+ err += sn9c102_i2c_write(cam, 0x4C, 0x00);
+ err += sn9c102_i2c_write(cam, 0x4D, 0x00);
+ err += sn9c102_i2c_write(cam, 0x4E, 0x00);
+ err += sn9c102_i2c_write(cam, 0x4F, 0x46);
+ err += sn9c102_i2c_write(cam, 0x50, 0x36);
+ err += sn9c102_i2c_write(cam, 0x51, 0x0F);
+ err += sn9c102_i2c_write(cam, 0x52, 0x17);
+ err += sn9c102_i2c_write(cam, 0x53, 0x7F);
+ err += sn9c102_i2c_write(cam, 0x54, 0x96);
+ err += sn9c102_i2c_write(cam, 0x55, 0x40);
+ err += sn9c102_i2c_write(cam, 0x56, 0x40);
+ err += sn9c102_i2c_write(cam, 0x57, 0x40);
+ err += sn9c102_i2c_write(cam, 0x58, 0x0F);
+ err += sn9c102_i2c_write(cam, 0x59, 0xBA);
+ err += sn9c102_i2c_write(cam, 0x5A, 0x9A);
+ err += sn9c102_i2c_write(cam, 0x5B, 0x22);
+ err += sn9c102_i2c_write(cam, 0x5C, 0xB9);
+ err += sn9c102_i2c_write(cam, 0x5D, 0x9B);
+ err += sn9c102_i2c_write(cam, 0x5E, 0x10);
+ err += sn9c102_i2c_write(cam, 0x5F, 0xF0);
+ err += sn9c102_i2c_write(cam, 0x60, 0x05);
+ err += sn9c102_i2c_write(cam, 0x61, 0x60);
+ err += sn9c102_i2c_write(cam, 0x62, 0x00);
+ err += sn9c102_i2c_write(cam, 0x63, 0x00);
+ err += sn9c102_i2c_write(cam, 0x64, 0x50);
+ err += sn9c102_i2c_write(cam, 0x65, 0x30);
+ err += sn9c102_i2c_write(cam, 0x66, 0x00);
+ err += sn9c102_i2c_write(cam, 0x67, 0x80);
+ err += sn9c102_i2c_write(cam, 0x68, 0x7A);
+ err += sn9c102_i2c_write(cam, 0x69, 0x90);
+ err += sn9c102_i2c_write(cam, 0x6A, 0x80);
+ err += sn9c102_i2c_write(cam, 0x6B, 0x0A);
+ err += sn9c102_i2c_write(cam, 0x6C, 0x30);
+ err += sn9c102_i2c_write(cam, 0x6D, 0x48);
+ err += sn9c102_i2c_write(cam, 0x6E, 0x80);
+ err += sn9c102_i2c_write(cam, 0x6F, 0x74);
+ err += sn9c102_i2c_write(cam, 0x70, 0x64);
+ err += sn9c102_i2c_write(cam, 0x71, 0x60);
+ err += sn9c102_i2c_write(cam, 0x72, 0x5C);
+ err += sn9c102_i2c_write(cam, 0x73, 0x58);
+ err += sn9c102_i2c_write(cam, 0x74, 0x54);
+ err += sn9c102_i2c_write(cam, 0x75, 0x4C);
+ err += sn9c102_i2c_write(cam, 0x76, 0x40);
+ err += sn9c102_i2c_write(cam, 0x77, 0x38);
+ err += sn9c102_i2c_write(cam, 0x78, 0x34);
+ err += sn9c102_i2c_write(cam, 0x79, 0x30);
+ err += sn9c102_i2c_write(cam, 0x7A, 0x2F);
+ err += sn9c102_i2c_write(cam, 0x7B, 0x2B);
+ err += sn9c102_i2c_write(cam, 0x7C, 0x03);
+ err += sn9c102_i2c_write(cam, 0x7D, 0x07);
+ err += sn9c102_i2c_write(cam, 0x7E, 0x17);
+ err += sn9c102_i2c_write(cam, 0x7F, 0x34);
+ err += sn9c102_i2c_write(cam, 0x80, 0x41);
+ err += sn9c102_i2c_write(cam, 0x81, 0x4D);
+ err += sn9c102_i2c_write(cam, 0x82, 0x58);
+ err += sn9c102_i2c_write(cam, 0x83, 0x63);
+ err += sn9c102_i2c_write(cam, 0x84, 0x6E);
+ err += sn9c102_i2c_write(cam, 0x85, 0x77);
+ err += sn9c102_i2c_write(cam, 0x86, 0x87);
+ err += sn9c102_i2c_write(cam, 0x87, 0x95);
+ err += sn9c102_i2c_write(cam, 0x88, 0xAF);
+ err += sn9c102_i2c_write(cam, 0x89, 0xC7);
+ err += sn9c102_i2c_write(cam, 0x8A, 0xDF);
+ err += sn9c102_i2c_write(cam, 0x8B, 0x99);
+ err += sn9c102_i2c_write(cam, 0x8C, 0x99);
+ err += sn9c102_i2c_write(cam, 0x8D, 0xCF);
+ err += sn9c102_i2c_write(cam, 0x8E, 0x20);
+ err += sn9c102_i2c_write(cam, 0x8F, 0x26);
+ err += sn9c102_i2c_write(cam, 0x90, 0x10);
+ err += sn9c102_i2c_write(cam, 0x91, 0x0C);
+ err += sn9c102_i2c_write(cam, 0x92, 0x25);
+ err += sn9c102_i2c_write(cam, 0x93, 0x00);
+ err += sn9c102_i2c_write(cam, 0x94, 0x50);
+ err += sn9c102_i2c_write(cam, 0x95, 0x50);
+ err += sn9c102_i2c_write(cam, 0x96, 0x00);
+ err += sn9c102_i2c_write(cam, 0x97, 0x01);
+ err += sn9c102_i2c_write(cam, 0x98, 0x10);
+ err += sn9c102_i2c_write(cam, 0x99, 0x40);
+ err += sn9c102_i2c_write(cam, 0x9A, 0x40);
+ err += sn9c102_i2c_write(cam, 0x9B, 0x20);
+ err += sn9c102_i2c_write(cam, 0x9C, 0x00);
+ err += sn9c102_i2c_write(cam, 0x9D, 0x99);
+ err += sn9c102_i2c_write(cam, 0x9E, 0x7F);
+ err += sn9c102_i2c_write(cam, 0x9F, 0x00);
+ err += sn9c102_i2c_write(cam, 0xA0, 0x00);
+ err += sn9c102_i2c_write(cam, 0xA1, 0x00);
+
+ return err;
+}
+
+
+static int ov7660_get_ctrl(struct sn9c102_device* cam,
+ struct v4l2_control* ctrl)
+{
+ int err = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
+ return -EIO;
+ break;
+ case V4L2_CID_DO_WHITE_BALANCE:
+ ctrl->value = sn9c102_pread_reg(cam, 0x02);
+ ctrl->value = (ctrl->value & 0x04) ? 1 : 0;
+ break;
+ case V4L2_CID_RED_BALANCE:
+ ctrl->value = sn9c102_pread_reg(cam, 0x05);
+ ctrl->value &= 0x7f;
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ ctrl->value = sn9c102_pread_reg(cam, 0x06);
+ ctrl->value &= 0x7f;
+ break;
+ case SN9C102_V4L2_CID_GREEN_BALANCE:
+ ctrl->value = sn9c102_pread_reg(cam, 0x07);
+ ctrl->value &= 0x7f;
+ break;
+ case V4L2_CID_GAIN:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
+ return -EIO;
+ ctrl->value &= 0x7f;
+ break;
+ case V4L2_CID_AUTOGAIN:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0)
+ return -EIO;
+ ctrl->value &= 0x01;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err ? -EIO : 0;
+}
+
+
+static int ov7660_set_ctrl(struct sn9c102_device* cam,
+ const struct v4l2_control* ctrl)
+{
+ int err = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
+ break;
+ case V4L2_CID_DO_WHITE_BALANCE:
+ err += sn9c102_write_reg(cam, 0x43 | (ctrl->value << 2), 0x02);
+ break;
+ case V4L2_CID_RED_BALANCE:
+ err += sn9c102_write_reg(cam, ctrl->value, 0x05);
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ err += sn9c102_write_reg(cam, ctrl->value, 0x06);
+ break;
+ case SN9C102_V4L2_CID_GREEN_BALANCE:
+ err += sn9c102_write_reg(cam, ctrl->value, 0x07);
+ break;
+ case V4L2_CID_GAIN:
+ err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ err += sn9c102_i2c_write(cam, 0x13, 0xf0 | ctrl->value |
+ (ctrl->value << 1));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err ? -EIO : 0;
+}
+
+
+static int ov7660_set_crop(struct sn9c102_device* cam,
+ const struct v4l2_rect* rect)
+{
+ struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ int err = 0;
+ u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
+ v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+
+ err += sn9c102_write_reg(cam, h_start, 0x12);
+ err += sn9c102_write_reg(cam, v_start, 0x13);
+
+ return err;
+}
+
+
+static int ov7660_set_pix_format(struct sn9c102_device* cam,
+ const struct v4l2_pix_format* pix)
+{
+ int r0, err = 0;
+
+ r0 = sn9c102_pread_reg(cam, 0x01);
+
+ if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
+ err += sn9c102_write_reg(cam, r0 | 0x40, 0x01);
+ err += sn9c102_write_reg(cam, 0xa2, 0x17);
+ err += sn9c102_i2c_write(cam, 0x11, 0x00);
+ } else {
+ err += sn9c102_write_reg(cam, r0 | 0x40, 0x01);
+ err += sn9c102_write_reg(cam, 0xa2, 0x17);
+ err += sn9c102_i2c_write(cam, 0x11, 0x0d);
+ }
+
+ return err;
+}
+
+
+static struct sn9c102_sensor ov7660 = {
+ .name = "OV7660",
+ .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+ .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120,
+ .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
+ .frequency = SN9C102_I2C_100KHZ,
+ .interface = SN9C102_I2C_2WIRES,
+ .i2c_slave_id = 0x21,
+ .init = &ov7660_init,
+ .qctrl = {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "global gain",
+ .minimum = 0x00,
+ .maximum = 0x7f,
+ .step = 0x01,
+ .default_value = 0x0a,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x01,
+ .default_value = 0x50,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_DO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "night mode",
+ .minimum = 0x00,
+ .maximum = 0x01,
+ .step = 0x01,
+ .default_value = 0x00,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "red balance",
+ .minimum = 0x00,
+ .maximum = 0x7f,
+ .step = 0x01,
+ .default_value = 0x1f,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "blue balance",
+ .minimum = 0x00,
+ .maximum = 0x7f,
+ .step = 0x01,
+ .default_value = 0x1e,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto adjust",
+ .minimum = 0x00,
+ .maximum = 0x01,
+ .step = 0x01,
+ .default_value = 0x00,
+ .flags = 0,
+ },
+ {
+ .id = SN9C102_V4L2_CID_GREEN_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "green balance",
+ .minimum = 0x00,
+ .maximum = 0x7f,
+ .step = 0x01,
+ .default_value = 0x20,
+ .flags = 0,
+ },
+ },
+ .get_ctrl = &ov7660_get_ctrl,
+ .set_ctrl = &ov7660_set_ctrl,
+ .cropcap = {
+ .bounds = {
+ .left = 0,
+ .top = 0,
+ .width = 640,
+ .height = 480,
+ },
+ .defrect = {
+ .left = 0,
+ .top = 0,
+ .width = 640,
+ .height = 480,
+ },
+ },
+ .set_crop = &ov7660_set_crop,
+ .pix_format = {
+ .width = 640,
+ .height = 480,
+ .pixelformat = V4L2_PIX_FMT_JPEG,
+ .priv = 8,
+ },
+ .set_pix_format = &ov7660_set_pix_format
+};
+
+
+int sn9c102_probe_ov7660(struct sn9c102_device* cam)
+{
+ int pid, ver, err = 0;
+
+ err += sn9c102_write_reg(cam, 0x01, 0xf1);
+ err += sn9c102_write_reg(cam, 0x00, 0xf1);
+ err += sn9c102_write_reg(cam, 0x01, 0x01);
+ err += sn9c102_write_reg(cam, 0x00, 0x01);
+ err += sn9c102_write_reg(cam, 0x28, 0x17);
+
+ pid = sn9c102_i2c_try_read(cam, &ov7660, 0x0a);
+ ver = sn9c102_i2c_try_read(cam, &ov7660, 0x0b);
+ if (err || pid < 0 || ver < 0)
+ return -EIO;
+ if (pid != 0x76 || ver != 0x60)
+ return -ENODEV;
+ sn9c102_attach_sensor(cam, &ov7660);
+
+ return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_pas106b.c b/drivers/media/video/sn9c102/sn9c102_pas106b.c
index 9915944235e..8d79a5fae5d 100644
--- a/drivers/media/video/sn9c102/sn9c102_pas106b.c
+++ b/drivers/media/video/sn9c102/sn9c102_pas106b.c
@@ -1,8 +1,8 @@
/***************************************************************************
- * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for PAS106B image sensor connected to the SN9C1xx PC Camera *
* Controllers *
* *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* 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 *
@@ -143,7 +143,7 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam,
static int pas106b_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
- struct sn9c102_sensor* s = &pas106b;
+ struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
@@ -172,6 +172,7 @@ static int pas106b_set_pix_format(struct sn9c102_device* cam,
static struct sn9c102_sensor pas106b = {
.name = "PAS106B",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_2WIRES,
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bca.c b/drivers/media/video/sn9c102/sn9c102_pas202bca.c
deleted file mode 100644
index c8f1ae2152b..00000000000
--- a/drivers/media/video/sn9c102/sn9c102_pas202bca.c
+++ /dev/null
@@ -1,238 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera *
- * Controllers *
- * *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include <linux/delay.h>
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor pas202bca;
-
-
-static int pas202bca_init(struct sn9c102_device* cam)
-{
- int err = 0;
-
- err += sn9c102_write_reg(cam, 0x00, 0x10);
- err += sn9c102_write_reg(cam, 0x00, 0x11);
- err += sn9c102_write_reg(cam, 0x00, 0x14);
- err += sn9c102_write_reg(cam, 0x20, 0x17);
- err += sn9c102_write_reg(cam, 0x30, 0x19);
- err += sn9c102_write_reg(cam, 0x09, 0x18);
-
- err += sn9c102_i2c_write(cam, 0x02, 0x14);
- err += sn9c102_i2c_write(cam, 0x03, 0x40);
- err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
- err += sn9c102_i2c_write(cam, 0x0e, 0x01);
- err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
- err += sn9c102_i2c_write(cam, 0x10, 0x08);
- err += sn9c102_i2c_write(cam, 0x13, 0x63);
- err += sn9c102_i2c_write(cam, 0x15, 0x70);
- err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
- msleep(400);
-
- return err;
-}
-
-
-static int pas202bca_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
-{
- int err = 0;
-
- if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
- err += sn9c102_write_reg(cam, 0x24, 0x17);
- else
- err += sn9c102_write_reg(cam, 0x20, 0x17);
-
- return err;
-}
-
-
-static int pas202bca_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
-{
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
- err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
- break;
- case V4L2_CID_RED_BALANCE:
- err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
- break;
- case V4L2_CID_BLUE_BALANCE:
- err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
- break;
- case V4L2_CID_GAIN:
- err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
- break;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
- break;
- case SN9C102_V4L2_CID_DAC_MAGNITUDE:
- err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
- break;
- default:
- return -EINVAL;
- }
- err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
- return err ? -EIO : 0;
-}
-
-
-static int pas202bca_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
-{
- struct sn9c102_sensor* s = &pas202bca;
- int err = 0;
- u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3,
- v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
-
- err += sn9c102_write_reg(cam, h_start, 0x12);
- err += sn9c102_write_reg(cam, v_start, 0x13);
-
- return err;
-}
-
-
-static struct sn9c102_sensor pas202bca = {
- .name = "PAS202BCA",
- .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
- .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
- .interface = SN9C102_I2C_2WIRES,
- .i2c_slave_id = 0x40,
- .init = &pas202bca_init,
- .qctrl = {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x01e5,
- .maximum = 0x3fff,
- .step = 0x0001,
- .default_value = 0x01e5,
- .flags = 0,
- },
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "global gain",
- .minimum = 0x00,
- .maximum = 0x1f,
- .step = 0x01,
- .default_value = 0x0c,
- .flags = 0,
- },
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x01,
- .flags = 0,
- },
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x05,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "DAC magnitude",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = 0x04,
- .flags = 0,
- },
- },
- .set_ctrl = &pas202bca_set_ctrl,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- },
- .set_crop = &pas202bca_set_crop,
- .pix_format = {
- .width = 640,
- .height = 480,
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
- .priv = 8,
- },
- .set_pix_format = &pas202bca_set_pix_format
-};
-
-
-int sn9c102_probe_pas202bca(struct sn9c102_device* cam)
-{
- const struct usb_device_id pas202bca_id_table[] = {
- { USB_DEVICE(0x0c45, 0x60af), },
- { }
- };
- int err = 0;
-
- if (!sn9c102_match_id(cam,pas202bca_id_table))
- return -ENODEV;
-
- err += sn9c102_write_reg(cam, 0x01, 0x01);
- err += sn9c102_write_reg(cam, 0x40, 0x01);
- err += sn9c102_write_reg(cam, 0x28, 0x17);
- if (err)
- return -EIO;
-
- if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */
- return -ENODEV;
-
- sn9c102_attach_sensor(cam, &pas202bca);
-
- return 0;
-}
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
index e3c1178e339..7894f01b56e 100644
--- a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
+++ b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
@@ -1,13 +1,13 @@
/***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for PAS202BCB image sensor connected to the SN9C1xx PC Camera *
* Controllers *
* *
* Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio *
* <medaglia@undl.org.br> *
* http://cadu.homelinux.com:8080/ *
* *
- * DAC Magnitude, exposure and green gain controls added by *
- * Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Support for SN9C103, DAC Magnitude, exposure and green gain controls *
+ * added by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* 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 *
@@ -35,12 +35,54 @@ static int pas202bcb_init(struct sn9c102_device* cam)
{
int err = 0;
+ switch (sn9c102_get_bridge(cam)) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
err += sn9c102_write_reg(cam, 0x00, 0x10);
err += sn9c102_write_reg(cam, 0x00, 0x11);
err += sn9c102_write_reg(cam, 0x00, 0x14);
err += sn9c102_write_reg(cam, 0x20, 0x17);
err += sn9c102_write_reg(cam, 0x30, 0x19);
err += sn9c102_write_reg(cam, 0x09, 0x18);
+ break;
+ case BRIDGE_SN9C103:
+ err += sn9c102_write_reg(cam, 0x00, 0x02);
+ err += sn9c102_write_reg(cam, 0x00, 0x03);
+ err += sn9c102_write_reg(cam, 0x1a, 0x04);
+ err += sn9c102_write_reg(cam, 0x20, 0x05);
+ err += sn9c102_write_reg(cam, 0x20, 0x06);
+ err += sn9c102_write_reg(cam, 0x20, 0x07);
+ err += sn9c102_write_reg(cam, 0x00, 0x10);
+ err += sn9c102_write_reg(cam, 0x00, 0x11);
+ err += sn9c102_write_reg(cam, 0x00, 0x14);
+ err += sn9c102_write_reg(cam, 0x20, 0x17);
+ err += sn9c102_write_reg(cam, 0x30, 0x19);
+ err += sn9c102_write_reg(cam, 0x09, 0x18);
+ err += sn9c102_write_reg(cam, 0x02, 0x1c);
+ err += sn9c102_write_reg(cam, 0x03, 0x1d);
+ err += sn9c102_write_reg(cam, 0x0f, 0x1e);
+ err += sn9c102_write_reg(cam, 0x0c, 0x1f);
+ err += sn9c102_write_reg(cam, 0x00, 0x20);
+ err += sn9c102_write_reg(cam, 0x10, 0x21);
+ err += sn9c102_write_reg(cam, 0x20, 0x22);
+ err += sn9c102_write_reg(cam, 0x30, 0x23);
+ err += sn9c102_write_reg(cam, 0x40, 0x24);
+ err += sn9c102_write_reg(cam, 0x50, 0x25);
+ err += sn9c102_write_reg(cam, 0x60, 0x26);
+ err += sn9c102_write_reg(cam, 0x70, 0x27);
+ err += sn9c102_write_reg(cam, 0x80, 0x28);
+ err += sn9c102_write_reg(cam, 0x90, 0x29);
+ err += sn9c102_write_reg(cam, 0xa0, 0x2a);
+ err += sn9c102_write_reg(cam, 0xb0, 0x2b);
+ err += sn9c102_write_reg(cam, 0xc0, 0x2c);
+ err += sn9c102_write_reg(cam, 0xd0, 0x2d);
+ err += sn9c102_write_reg(cam, 0xe0, 0x2e);
+ err += sn9c102_write_reg(cam, 0xf0, 0x2f);
+ err += sn9c102_write_reg(cam, 0xff, 0x30);
+ break;
+ default:
+ break;
+ }
err += sn9c102_i2c_write(cam, 0x02, 0x14);
err += sn9c102_i2c_write(cam, 0x03, 0x40);
@@ -107,7 +149,7 @@ static int pas202bcb_set_pix_format(struct sn9c102_device* cam,
int err = 0;
if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
- err += sn9c102_write_reg(cam, 0x24, 0x17);
+ err += sn9c102_write_reg(cam, 0x28, 0x17);
else
err += sn9c102_write_reg(cam, 0x20, 0x17);
@@ -152,11 +194,23 @@ static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
static int pas202bcb_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
- struct sn9c102_sensor* s = &pas202bcb;
+ struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
int err = 0;
- u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
+ u8 h_start = 0,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
+ switch (sn9c102_get_bridge(cam)) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4;
+ break;
+ case BRIDGE_SN9C103:
+ h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3;
+ break;
+ default:
+ break;
+ }
+
err += sn9c102_write_reg(cam, h_start, 0x12);
err += sn9c102_write_reg(cam, v_start, 0x13);
@@ -166,8 +220,8 @@ static int pas202bcb_set_crop(struct sn9c102_device* cam,
static struct sn9c102_sensor pas202bcb = {
.name = "PAS202BCB",
- .maintainer = "Carlos Eduardo Medaglia Dyonisio "
- "<medaglia@undl.org.br>",
+ .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_2WIRES,
@@ -191,7 +245,7 @@ static struct sn9c102_sensor pas202bcb = {
.minimum = 0x00,
.maximum = 0x1f,
.step = 0x01,
- .default_value = 0x0c,
+ .default_value = 0x0b,
.flags = 0,
},
{
@@ -201,7 +255,7 @@ static struct sn9c102_sensor pas202bcb = {
.minimum = 0x00,
.maximum = 0x0f,
.step = 0x01,
- .default_value = 0x01,
+ .default_value = 0x00,
.flags = 0,
},
{
@@ -271,16 +325,27 @@ int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
* Minimal initialization to enable the I2C communication
* NOTE: do NOT change the values!
*/
- err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
- err += sn9c102_write_reg(cam, 0x40, 0x01); /* sensor power on */
- err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
- if (err)
- return -EIO;
+ switch (sn9c102_get_bridge(cam)) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ err += sn9c102_write_reg(cam, 0x01, 0x01); /* power down */
+ err += sn9c102_write_reg(cam, 0x40, 0x01); /* power on */
+ err += sn9c102_write_reg(cam, 0x28, 0x17); /* clock 24 MHz */
+ break;
+ case BRIDGE_SN9C103: /* do _not_ change anything! */
+ err += sn9c102_write_reg(cam, 0x09, 0x01);
+ err += sn9c102_write_reg(cam, 0x44, 0x01);
+ err += sn9c102_write_reg(cam, 0x44, 0x02);
+ err += sn9c102_write_reg(cam, 0x29, 0x17);
+ break;
+ default:
+ break;
+ }
r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00);
r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01);
- if (r0 < 0 || r1 < 0)
+ if (err || r0 < 0 || r1 < 0)
return -EIO;
pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h
index 2a874ee6f9f..05f2942639c 100644
--- a/drivers/media/video/sn9c102/sn9c102_sensor.h
+++ b/drivers/media/video/sn9c102/sn9c102_sensor.h
@@ -1,7 +1,7 @@
/***************************************************************************
- * API for image sensors connected to the SN9C10x PC Camera Controllers *
+ * API for image sensors connected to the SN9C1xx PC Camera Controllers *
* *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* 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 *
@@ -36,14 +36,13 @@ struct sn9c102_sensor;
/*
OVERVIEW.
This is a small interface that allows you to add support for any CCD/CMOS
- image sensors connected to the SN9C10X bridges. The entire API is documented
+ image sensors connected to the SN9C1XX bridges. The entire API is documented
below. In the most general case, to support a sensor there are three steps
you have to follow:
1) define the main "sn9c102_sensor" structure by setting the basic fields;
2) write a probing function to be called by the core module when the USB
camera is recognized, then add both the USB ids and the name of that
- function to the two corresponding tables SENSOR_TABLE and ID_TABLE (see
- below);
+ function to the two corresponding tables in sn9c102_devtable.h;
3) implement the methods that you want/need (and fill the rest of the main
structure accordingly).
"sn9c102_pas106b.c" is an example of all this stuff. Remember that you do
@@ -54,42 +53,21 @@ struct sn9c102_sensor;
/*****************************************************************************/
-/*
- Probing functions: on success, you must attach the sensor to the camera
- by calling sn9c102_attach_sensor() provided below.
- To enable the I2C communication, you might need to perform a really basic
- initialization of the SN9C10X chip by using the write function declared
- ahead.
- Functions must return 0 on success, the appropriate error otherwise.
-*/
-extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
-extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
-extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas202bca(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
-extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
-extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
-
-/*
- Add the above entries to this table. Be sure to add the entry in the right
- place, since, on failure, the next probing routine is called according to
- the order of the list below, from top to bottom.
-*/
-#define SN9C102_SENSOR_TABLE \
-static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \
- &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ \
- &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ \
- &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ \
- &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ \
- &sn9c102_probe_pas202bca, /* detection mostly based on USB pid/vid */ \
- &sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */ \
- &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \
- &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \
- NULL, \
+enum sn9c102_bridge {
+ BRIDGE_SN9C101 = 0x01,
+ BRIDGE_SN9C102 = 0x02,
+ BRIDGE_SN9C103 = 0x04,
+ BRIDGE_SN9C105 = 0x08,
+ BRIDGE_SN9C120 = 0x10,
};
-/* Device identification */
+/* Return the bridge name */
+enum sn9c102_bridge sn9c102_get_bridge(struct sn9c102_device* cam);
+
+/* Return a pointer the sensor struct attached to the camera */
+struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam);
+
+/* Identify a device */
extern struct sn9c102_device*
sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id);
@@ -99,68 +77,8 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
struct sn9c102_sensor* sensor);
/*
- Each SN9C10x camera has proper PID/VID identifiers.
- SN9C103 supports multiple interfaces, but we only handle the video class
- interface.
-*/
-#define SN9C102_USB_DEVICE(vend, prod, intclass) \
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
- USB_DEVICE_ID_MATCH_INT_CLASS, \
- .idVendor = (vend), \
- .idProduct = (prod), \
- .bInterfaceClass = (intclass)
-
-#define SN9C102_ID_TABLE \
-static const struct usb_device_id sn9c102_id_table[] = { \
- { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */ \
- { USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */ \
- { USB_DEVICE(0x0c45, 0x6007), }, \
- { USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */ \
- { USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */ \
- { USB_DEVICE(0x0c45, 0x6024), }, \
- { USB_DEVICE(0x0c45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */ \
- { USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */ \
- { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */ \
- { USB_DEVICE(0x0c45, 0x602a), }, /* HV7131D */ \
- { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */ \
- { USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */ \
- { USB_DEVICE(0x0c45, 0x602d), }, \
- { USB_DEVICE(0x0c45, 0x602e), }, /* OV7630 */ \
- { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x6080, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x6082, 0xff), }, /* MI0343 & MI0360 */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x6083, 0xff), }, /* HV7131[D|E1] */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131/R */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60a2, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60a3, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60a8, 0xff), }, /* PAS106B */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x60aa, 0xff), }, /* TAS5130D1B */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x60ab, 0xff), }, /* TAS5110C1B */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x60ac, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60ae, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60af, 0xff), }, /* PAS202BCB */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x60b0, 0xff), }, /* OV7630 (?) */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x60b2, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60b3, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60b8, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60ba, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60bb, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60bc, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60be, 0xff), }, \
- { } \
-};
-
-/*****************************************************************************/
-
-/*
Read/write routines: they always return -1 on error, 0 or the read value
- otherwise. NOTE that a real read operation is not supported by the SN9C10X
+ otherwise. NOTE that a real read operation is not supported by the SN9C1XX
chip for some of its registers. To work around this problem, a pseudo-read
call is provided instead: it returns the last successfully written value
on the register (0 if it has never been written), the usual -1 on error.
@@ -176,7 +94,7 @@ extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*,
These must be used if and only if the sensor doesn't implement the standard
I2C protocol. There are a number of good reasons why you must use the
single-byte versions of these functions: do not abuse. The first function
- writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C10X
+ writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C1XX
chip. The second one programs the registers 0x09 and 0x10 with data0 and
data1, and places the n bytes read from the sensor register table in the
buffer pointed by 'buffer'. Both the functions return -1 on error; the write
@@ -200,16 +118,6 @@ extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index);
extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index);
extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index);
-/*
- NOTE: there are no exported debugging functions. To uniform the output you
- must use the dev_info()/dev_warn()/dev_err() macros defined in device.h,
- already included here, the argument being the struct device '&usbdev->dev'
- of the sensor structure. Do NOT use these macros before the sensor is
- attached or the kernel will crash! However, you should not need to notify
- the user about common errors or other messages, since this is done by the
- master module.
-*/
-
/*****************************************************************************/
enum sn9c102_i2c_sysfs_ops {
@@ -227,17 +135,19 @@ enum sn9c102_i2c_interface {
SN9C102_I2C_3WIRES,
};
-#define SN9C102_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
+#define SN9C102_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10)
struct sn9c102_sensor {
char name[32], /* sensor name */
maintainer[64]; /* name of the mantainer <email> */
+ enum sn9c102_bridge supported_bridge; /* supported SN9C1xx bridges */
+
/* Supported operations through the 'sysfs' interface */
enum sn9c102_i2c_sysfs_ops sysfs_ops;
/*
- These sensor capabilities must be provided if the SN9C10X controller
+ These sensor capabilities must be provided if the SN9C1XX controller
needs to communicate through the sensor serial interface by using
at least one of the i2c functions available.
*/
@@ -260,7 +170,7 @@ struct sn9c102_sensor {
/*
This function will be called after the sensor has been attached.
It should be used to initialize the sensor only, but may also
- configure part of the SN9C10X chip if necessary. You don't need to
+ configure part of the SN9C1XX chip if necessary. You don't need to
setup picture settings like brightness, contrast, etc.. here, if
the corrisponding controls are implemented (see below), since
they are adjusted in the core driver by calling the set_ctrl()
@@ -300,7 +210,7 @@ struct sn9c102_sensor {
It is not always true that the largest achievable active window can
cover the whole array of pixels. The V4L2 API defines another
area called "source rectangle", which, in turn, is a subrectangle of
- the active window. The SN9C10X chip is always programmed to read the
+ the active window. The SN9C1XX chip is always programmed to read the
source rectangle.
The bounds of both the active window and the source rectangle are
specified in the cropcap substructures 'bounds' and 'defrect'.
@@ -326,13 +236,13 @@ struct sn9c102_sensor {
const struct v4l2_rect* rect);
/*
To be called on VIDIOC_C_SETCROP. The core module always calls a
- default routine which configures the appropriate SN9C10X regs (also
+ default routine which configures the appropriate SN9C1XX regs (also
scaling), but you may need to override/adjust specific stuff.
'rect' contains width and height values that are multiple of 16: in
case you override the default function, you always have to program
the chip to match those values; on error return the corresponding
error code without rolling back.
- NOTE: in case, you must program the SN9C10X chip to get rid of
+ NOTE: in case, you must program the SN9C1XX chip to get rid of
blank pixels or blank lines at the _start_ of each line or
frame after each HSYNC or VSYNC, so that the image starts with
real RGB data (see regs 0x12, 0x13) (having set H_SIZE and,
@@ -344,16 +254,16 @@ struct sn9c102_sensor {
/*
What you have to define here are: 1) initial 'width' and 'height' of
the target rectangle 2) the initial 'pixelformat', which can be
- either V4L2_PIX_FMT_SN9C10X (for compressed video) or
- V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate the
- number of bits per pixel for uncompressed video, 8 or 9 (despite the
- current value of 'pixelformat').
+ either V4L2_PIX_FMT_SN9C10X, V4L2_PIX_FMT_JPEG (for ompressed video)
+ or V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate
+ the number of bits per pixel for uncompressed video, 8 or 9 (despite
+ the current value of 'pixelformat').
NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4
of cropcap.defrect.width and cropcap.defrect.height. I
suggest 1/1.
NOTE 2: The initial compression quality is defined by the first bit
of reg 0x17 during the initialization of the image sensor.
- NOTE 3: as said above, you have to program the SN9C10X chip to get
+ NOTE 3: as said above, you have to program the SN9C1XX chip to get
rid of any blank pixels, so that the output of the sensor
matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR).
*/
@@ -378,12 +288,12 @@ struct sn9c102_sensor {
/*****************************************************************************/
/* Private ioctl's for control settings supported by some image sensors */
-#define SN9C102_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
-#define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
-#define SN9C102_V4L2_CID_RESET_LEVEL V4L2_CID_PRIVATE_BASE + 2
-#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3
-#define SN9C102_V4L2_CID_GAMMA V4L2_CID_PRIVATE_BASE + 4
-#define SN9C102_V4L2_CID_BAND_FILTER V4L2_CID_PRIVATE_BASE + 5
-#define SN9C102_V4L2_CID_BRIGHT_LEVEL V4L2_CID_PRIVATE_BASE + 6
+#define SN9C102_V4L2_CID_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0)
+#define SN9C102_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 1)
+#define SN9C102_V4L2_CID_RESET_LEVEL (V4L2_CID_PRIVATE_BASE + 2)
+#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE (V4L2_CID_PRIVATE_BASE + 3)
+#define SN9C102_V4L2_CID_GAMMA (V4L2_CID_PRIVATE_BASE + 4)
+#define SN9C102_V4L2_CID_BAND_FILTER (V4L2_CID_PRIVATE_BASE + 5)
+#define SN9C102_V4L2_CID_BRIGHT_LEVEL (V4L2_CID_PRIVATE_BASE + 6)
#endif /* _SN9C102_SENSOR_H_ */
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
index 294eb02fbd8..90023ad63ad 100644
--- a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
+++ b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
@@ -1,8 +1,8 @@
/***************************************************************************
- * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for TAS5110C1B image sensor connected to the SN9C1xx PC Camera *
* Controllers *
* *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* 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 *
@@ -64,7 +64,7 @@ static int tas5110c1b_set_ctrl(struct sn9c102_device* cam,
static int tas5110c1b_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
- struct sn9c102_sensor* s = &tas5110c1b;
+ struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
@@ -98,6 +98,7 @@ static int tas5110c1b_set_pix_format(struct sn9c102_device* cam,
static struct sn9c102_sensor tas5110c1b = {
.name = "TAS5110C1B",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
.sysfs_ops = SN9C102_I2C_WRITE,
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_3WIRES,
@@ -145,6 +146,7 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
const struct usb_device_id tas5110c1b_id_table[] = {
{ USB_DEVICE(0x0c45, 0x6001), },
{ USB_DEVICE(0x0c45, 0x6005), },
+ { USB_DEVICE(0x0c45, 0x6007), },
{ USB_DEVICE(0x0c45, 0x60ab), },
{ }
};
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
index 9ecb09032b6..cb1b318bc1f 100644
--- a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
+++ b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
@@ -1,8 +1,8 @@
/***************************************************************************
- * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for TAS5130D1B image sensor connected to the SN9C1xx PC Camera *
* Controllers *
* *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* 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 *
@@ -65,7 +65,7 @@ static int tas5130d1b_set_ctrl(struct sn9c102_device* cam,
static int tas5130d1b_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
- struct sn9c102_sensor* s = &tas5130d1b;
+ struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12;
int err = 0;
@@ -99,6 +99,7 @@ static int tas5130d1b_set_pix_format(struct sn9c102_device* cam,
static struct sn9c102_sensor tas5130d1b = {
.name = "TAS5130D1B",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
.sysfs_ops = SN9C102_I2C_WRITE,
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_3WIRES,
@@ -154,6 +155,7 @@ static struct sn9c102_sensor tas5130d1b = {
int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
{
const struct usb_device_id tas5130d1b_id_table[] = {
+ { USB_DEVICE(0x0c45, 0x6024), },
{ USB_DEVICE(0x0c45, 0x6025), },
{ USB_DEVICE(0x0c45, 0x60aa), },
{ }
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
index 7ea9132a196..3ae5a9cd2e2 100644
--- a/drivers/media/video/tvmixer.c
+++ b/drivers/media/video/tvmixer.c
@@ -212,8 +212,7 @@ static int tvmixer_release(struct inode *inode, struct file *file)
return -ENODEV;
}
- if (client->adapter->owner)
- module_put(client->adapter->owner);
+ module_put(client->adapter->owner);
return 0;
}
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index bc0a4fc27b2..d5ec05f56ad 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -950,25 +950,19 @@ static int tvp5150_command(struct i2c_client *c,
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_INT_G_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
{
struct v4l2_register *reg = arg;
- if (reg->i2c_id != I2C_DRIVERID_TVP5150)
- return -EINVAL;
- reg->val = tvp5150_read(c, reg->reg & 0xff);
- break;
- }
-
- case VIDIOC_INT_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
-
- if (reg->i2c_id != I2C_DRIVERID_TVP5150)
+ if (!v4l2_chip_match_i2c_client(c, reg->match_type, reg->match_chip))
return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- tvp5150_write(c, reg->reg & 0xff, reg->val & 0xff);
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ reg->val = tvp5150_read(c, reg->reg & 0xff);
+ else
+ tvp5150_write(c, reg->reg & 0xff, reg->val & 0xff);
break;
}
#endif
diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c
index fc52201d607..28d1133a3b7 100644
--- a/drivers/media/video/upd64031a.c
+++ b/drivers/media/video/upd64031a.c
@@ -162,27 +162,19 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *
break;
#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_INT_G_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
{
struct v4l2_register *reg = arg;
- if (reg->i2c_id != I2C_DRIVERID_UPD64031A)
- return -EINVAL;
- reg->val = upd64031a_read(client, reg->reg & 0xff);
- break;
- }
-
- case VIDIOC_INT_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
- u8 addr = reg->reg & 0xff;
- u8 val = reg->val & 0xff;
-
- if (reg->i2c_id != I2C_DRIVERID_UPD64031A)
+ if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- upd64031a_write(client, addr, val);
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ reg->val = upd64031a_read(client, reg->reg & 0xff);
+ else
+ upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff);
break;
}
#endif
diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c
index c3a7ffe5c26..fe38224150d 100644
--- a/drivers/media/video/upd64083.c
+++ b/drivers/media/video/upd64083.c
@@ -139,27 +139,19 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a
break;
#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_INT_G_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
{
struct v4l2_register *reg = arg;
- if (reg->i2c_id != I2C_DRIVERID_UPD64083)
- return -EINVAL;
- reg->val = upd64083_read(client, reg->reg & 0xff);
- break;
- }
-
- case VIDIOC_INT_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
- u8 addr = reg->reg & 0xff;
- u8 val = reg->val & 0xff;
-
- if (reg->i2c_id != I2C_DRIVERID_UPD64083)
+ if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- upd64083_write(client, addr, val);
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ reg->val = upd64083_read(client, reg->reg & 0xff);
+ else
+ upd64083_write(client, reg->reg & 0xff, reg->val & 0xff);
break;
}
#endif
diff --git a/drivers/media/video/usbvision/Kconfig b/drivers/media/video/usbvision/Kconfig
index fc24ef05b3f..c43a5d89909 100644
--- a/drivers/media/video/usbvision/Kconfig
+++ b/drivers/media/video/usbvision/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_USBVISION
tristate "USB video devices based on Nogatech NT1003/1004/1005"
- depends on I2C && VIDEO_V4L2
+ depends on I2C && VIDEO_V4L2 && USB
select VIDEO_TUNER
select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
---help---
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index 901f664dc6d..f2154dc072e 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -138,7 +138,7 @@ static void *usbvision_rvmalloc(unsigned long size)
return mem;
}
-void usbvision_rvfree(void *mem, unsigned long size)
+static void usbvision_rvfree(void *mem, unsigned long size)
{
unsigned long adr;
@@ -1852,28 +1852,33 @@ int usbvision_set_output(struct usb_usbvision *usbvision, int width,
/*
* usbvision_frames_alloc
- * allocate the maximum frames this driver can manage
+ * allocate the required frames
*/
-int usbvision_frames_alloc(struct usb_usbvision *usbvision)
+int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames)
{
int i;
- /* Allocate memory for the frame buffers */
- usbvision->max_frame_size = MAX_FRAME_SIZE;
- usbvision->fbuf_size = USBVISION_NUMFRAMES * usbvision->max_frame_size;
- usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size);
+ /*needs to be page aligned cause the buffers can be mapped individually! */
+ usbvision->max_frame_size = PAGE_ALIGN(usbvision->curwidth *
+ usbvision->curheight *
+ usbvision->palette.bytes_per_pixel);
- if(usbvision->fbuf == NULL) {
- err("%s: unable to allocate %d bytes for fbuf ",
- __FUNCTION__, usbvision->fbuf_size);
- return -ENOMEM;
+ /* Try to do my best to allocate the frames the user want in the remaining memory */
+ usbvision->num_frames = number_of_frames;
+ while (usbvision->num_frames > 0) {
+ usbvision->fbuf_size = usbvision->num_frames * usbvision->max_frame_size;
+ if((usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size))) {
+ break;
+ }
+ usbvision->num_frames--;
}
+
spin_lock_init(&usbvision->queue_lock);
init_waitqueue_head(&usbvision->wait_frame);
init_waitqueue_head(&usbvision->wait_stream);
/* Allocate all buffers */
- for (i = 0; i < USBVISION_NUMFRAMES; i++) {
+ for (i = 0; i < usbvision->num_frames; i++) {
usbvision->frame[i].index = i;
usbvision->frame[i].grabstate = FrameState_Unused;
usbvision->frame[i].data = usbvision->fbuf +
@@ -1887,7 +1892,8 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision)
usbvision->frame[i].height = usbvision->curheight;
usbvision->frame[i].bytes_read = 0;
}
- return 0;
+ PDEBUG(DBG_FUNC, "allocated %d frames (%d bytes per frame)",usbvision->num_frames,usbvision->max_frame_size);
+ return usbvision->num_frames;
}
/*
@@ -1897,9 +1903,13 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision)
void usbvision_frames_free(struct usb_usbvision *usbvision)
{
/* Have to free all that memory */
+ PDEBUG(DBG_FUNC, "free %d frames",usbvision->num_frames);
+
if (usbvision->fbuf != NULL) {
usbvision_rvfree(usbvision->fbuf, usbvision->fbuf_size);
usbvision->fbuf = NULL;
+
+ usbvision->num_frames = 0;
}
}
/*
@@ -2351,6 +2361,32 @@ int usbvision_setup(struct usb_usbvision *usbvision,int format)
return USBVISION_IS_OPERATIONAL(usbvision);
}
+int usbvision_set_alternate(struct usb_usbvision *dev)
+{
+ int errCode, prev_alt = dev->ifaceAlt;
+ int i;
+
+ dev->ifaceAlt=0;
+ for(i=0;i< dev->num_alt; i++)
+ if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->ifaceAlt])
+ dev->ifaceAlt=i;
+
+ if (dev->ifaceAlt != prev_alt) {
+ dev->isocPacketSize = dev->alt_max_pkt_size[dev->ifaceAlt];
+ PDEBUG(DBG_FUNC,"setting alternate %d with wMaxPacketSize=%u", dev->ifaceAlt,dev->isocPacketSize);
+ errCode = usb_set_interface(dev->dev, dev->iface, dev->ifaceAlt);
+ if (errCode < 0) {
+ err ("cannot change alternate number to %d (error=%i)",
+ dev->ifaceAlt, errCode);
+ return errCode;
+ }
+ }
+
+ PDEBUG(DBG_ISOC, "ISO Packet Length:%d", dev->isocPacketSize);
+
+ return 0;
+}
+
/*
* usbvision_init_isoc()
*
@@ -2368,15 +2404,13 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
scratch_reset(usbvision);
/* Alternate interface 1 is is the biggest frame size */
- errCode = usb_set_interface(dev, usbvision->iface, usbvision->ifaceAltActive);
+ errCode = usbvision_set_alternate(usbvision);
if (errCode < 0) {
usbvision->last_error = errCode;
return -EBUSY;
}
regValue = (16 - usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F;
- usbvision->isocPacketSize = (regValue == 0) ? 0 : (regValue * 64) - 1;
- PDEBUG(DBG_ISOC, "ISO Packet Length:%d", usbvision->isocPacketSize);
usbvision->usb_bandwidth = regValue >> 1;
PDEBUG(DBG_ISOC, "USB Bandwidth Usage: %dMbit/Sec", usbvision->usb_bandwidth);
@@ -2462,8 +2496,9 @@ void usbvision_stop_isoc(struct usb_usbvision *usbvision)
if (!usbvision->remove_pending) {
/* Set packet size to 0 */
+ usbvision->ifaceAlt=0;
errCode = usb_set_interface(usbvision->dev, usbvision->iface,
- usbvision->ifaceAltInactive);
+ usbvision->ifaceAlt);
if (errCode < 0) {
err("%s: usb_set_interface() failed: error %d", __FUNCTION__, errCode);
usbvision->last_error = errCode;
@@ -2490,6 +2525,7 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs);
usbvision->ctl_input = channel;
route.input = SAA7115_COMPOSITE1;
+ route.output = 0;
call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input);
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index af33653f0db..6fc14557d62 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -230,7 +230,7 @@ static ssize_t show_hue(struct class_device *cd, char *buf)
ctrl.value = 0;
if(usbvision->user)
call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
- return sprintf(buf, "%d\n", ctrl.value >> 8);
+ return sprintf(buf, "%d\n", ctrl.value);
}
static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
@@ -243,7 +243,7 @@ static ssize_t show_contrast(struct class_device *cd, char *buf)
ctrl.value = 0;
if(usbvision->user)
call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
- return sprintf(buf, "%d\n", ctrl.value >> 8);
+ return sprintf(buf, "%d\n", ctrl.value);
}
static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
@@ -256,7 +256,7 @@ static ssize_t show_brightness(struct class_device *cd, char *buf)
ctrl.value = 0;
if(usbvision->user)
call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
- return sprintf(buf, "%d\n", ctrl.value >> 8);
+ return sprintf(buf, "%d\n", ctrl.value);
}
static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
@@ -269,7 +269,7 @@ static ssize_t show_saturation(struct class_device *cd, char *buf)
ctrl.value = 0;
if(usbvision->user)
call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
- return sprintf(buf, "%d\n", ctrl.value >> 8);
+ return sprintf(buf, "%d\n", ctrl.value);
}
static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
@@ -391,19 +391,14 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
if (usbvision->user)
errCode = -EBUSY;
else {
- /* Allocate memory for the frame buffers */
- errCode = usbvision_frames_alloc(usbvision);
- if(!errCode) {
- /* Allocate memory for the scratch ring buffer */
- errCode = usbvision_scratch_alloc(usbvision);
- if ((!errCode) && (isocMode==ISOC_MODE_COMPRESS)) {
- /* Allocate intermediate decompression buffers only if needed */
- errCode = usbvision_decompress_alloc(usbvision);
- }
+ /* Allocate memory for the scratch ring buffer */
+ errCode = usbvision_scratch_alloc(usbvision);
+ if (isocMode==ISOC_MODE_COMPRESS) {
+ /* Allocate intermediate decompression buffers only if needed */
+ errCode = usbvision_decompress_alloc(usbvision);
}
if (errCode) {
/* Deallocate all buffers if trouble */
- usbvision_frames_free(usbvision);
usbvision_scratch_free(usbvision);
usbvision_decompress_free(usbvision);
}
@@ -476,6 +471,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
usbvision_decompress_free(usbvision);
usbvision_frames_free(usbvision);
+ usbvision_empty_framequeues(usbvision);
usbvision_scratch_free(usbvision);
usbvision->user--;
@@ -489,7 +485,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
up(&usbvision->lock);
if (usbvision->remove_pending) {
- info("%s: Final disconnect", __FUNCTION__);
+ printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
usbvision_release(usbvision);
}
@@ -519,44 +515,32 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
#ifdef CONFIG_VIDEO_ADV_DEBUG
/* ioctls to allow direct acces to the NT100x registers */
- case VIDIOC_INT_G_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
{
struct v4l2_register *reg = arg;
int errCode;
- if (reg->i2c_id != 0)
- return -EINVAL;
- /* NT100x has a 8-bit register space */
- errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
- if (errCode < 0) {
- err("%s: VIDIOC_INT_G_REGISTER failed: error %d", __FUNCTION__, errCode);
- }
- else {
- reg->val=(unsigned char)errCode;
- PDEBUG(DBG_IOCTL, "VIDIOC_INT_G_REGISTER reg=0x%02X, value=0x%02X",
- (unsigned int)reg->reg, reg->val);
- errCode = 0; // No error
- }
- return errCode;
- }
- case VIDIOC_INT_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
- int errCode;
-
- if (reg->i2c_id != 0)
+ if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
+ /* NT100x has a 8-bit register space */
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
+ else
+ errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
if (errCode < 0) {
- err("%s: VIDIOC_INT_S_REGISTER failed: error %d", __FUNCTION__, errCode);
- }
- else {
- PDEBUG(DBG_IOCTL, "VIDIOC_INT_S_REGISTER reg=0x%02X, value=0x%02X",
- (unsigned int)reg->reg, reg->val);
- errCode = 0;
+ err("%s: VIDIOC_DBG_%c_REGISTER failed: error %d", __FUNCTION__,
+ cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S', errCode);
+ return errCode;
}
+ if (cmd == VIDIOC_DBG_S_REGISTER)
+ reg->val = (u8)errCode;
+
+ PDEBUG(DBG_IOCTL, "VIDIOC_DBG_%c_REGISTER reg=0x%02X, value=0x%02X",
+ cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S',
+ (unsigned int)reg->reg, (unsigned int)reg->val);
return 0;
}
#endif
@@ -792,8 +776,8 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_G_CTRL:
{
struct v4l2_control *ctrl = arg;
- PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
+ PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
return 0;
}
case VIDIOC_S_CTRL:
@@ -821,7 +805,9 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
return ret;
}
+ usbvision_frames_free(usbvision);
usbvision_empty_framequeues(usbvision);
+ vr->count = usbvision_frames_alloc(usbvision,vr->count);
usbvision->curFrame = NULL;
@@ -838,7 +824,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
return -EINVAL;
}
- if(vb->index>=USBVISION_NUMFRAMES) {
+ if(vb->index>=usbvision->num_frames) {
return -EINVAL;
}
// Updating the corresponding frame state
@@ -852,7 +838,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
vb->flags |= V4L2_BUF_FLAG_MAPPED;
vb->memory = V4L2_MEMORY_MMAP;
- vb->m.offset = vb->index*usbvision->max_frame_size;
+ vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
vb->memory = V4L2_MEMORY_MMAP;
vb->field = V4L2_FIELD_NONE;
@@ -871,7 +857,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
return -EINVAL;
}
- if(vb->index>=USBVISION_NUMFRAMES) {
+ if(vb->index>=usbvision->num_frames) {
return -EINVAL;
}
@@ -1041,6 +1027,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
if ((ret = usbvision_stream_interrupt(usbvision)))
return ret;
}
+ usbvision_frames_free(usbvision);
usbvision_empty_framequeues(usbvision);
usbvision->curFrame = NULL;
@@ -1087,12 +1074,24 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL))
return -EFAULT;
- /* no stream is running, make it running ! */
- usbvision->streaming = Stream_On;
- call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
+ /* This entry point is compatible with the mmap routines so that a user can do either
+ VIDIOC_QBUF/VIDIOC_DQBUF to get frames or call read on the device. */
+ if(!usbvision->num_frames) {
+ /* First, allocate some frames to work with if this has not been done with
+ VIDIOC_REQBUF */
+ usbvision_frames_free(usbvision);
+ usbvision_empty_framequeues(usbvision);
+ usbvision_frames_alloc(usbvision,USBVISION_NUMFRAMES);
+ }
+
+ if(usbvision->streaming != Stream_On) {
+ /* no stream is running, make it running ! */
+ usbvision->streaming = Stream_On;
+ call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
+ }
- /* First, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */
- for(i=0;i<USBVISION_NUMFRAMES;i++) {
+ /* Then, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */
+ for(i=0;i<usbvision->num_frames;i++) {
frame = &usbvision->frame[i];
if(frame->grabstate == FrameState_Unused) {
/* Mark it as ready and enqueue frame */
@@ -1169,6 +1168,8 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
struct video_device *dev = video_devdata(file);
struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ PDEBUG(DBG_MMAP, "mmap");
+
down(&usbvision->lock);
if (!USBVISION_IS_OPERATIONAL(usbvision)) {
@@ -1177,16 +1178,16 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
}
if (!(vma->vm_flags & VM_WRITE) ||
- size != PAGE_ALIGN(usbvision->curwidth*usbvision->curheight*usbvision->palette.bytes_per_pixel)) {
+ size != PAGE_ALIGN(usbvision->max_frame_size)) {
up(&usbvision->lock);
return -EINVAL;
}
- for (i = 0; i < USBVISION_NUMFRAMES; i++) {
- if (((usbvision->max_frame_size*i) >> PAGE_SHIFT) == vma->vm_pgoff)
+ for (i = 0; i < usbvision->num_frames; i++) {
+ if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) == vma->vm_pgoff)
break;
}
- if (i == USBVISION_NUMFRAMES) {
+ if (i == usbvision->num_frames) {
PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range");
up(&usbvision->lock);
return -EINVAL;
@@ -1242,6 +1243,13 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
}
}
+ /* Alternate interface 1 is is the biggest frame size */
+ errCode = usbvision_set_alternate(usbvision);
+ if (errCode < 0) {
+ usbvision->last_error = errCode;
+ return -EBUSY;
+ }
+
// If so far no errors then we shall start the radio
usbvision->radio = 1;
call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type);
@@ -1273,6 +1281,11 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
down(&usbvision->lock);
+ /* Set packet size to 0 */
+ usbvision->ifaceAlt=0;
+ errCode = usb_set_interface(usbvision->dev, usbvision->iface,
+ usbvision->ifaceAlt);
+
usbvision_audio_off(usbvision);
usbvision->radio=0;
usbvision->user--;
@@ -1285,7 +1298,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
up(&usbvision->lock);
if (usbvision->remove_pending) {
- info("%s: Final disconnect", __FUNCTION__);
+ printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
usbvision_release(usbvision);
}
@@ -1611,7 +1624,7 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr)<0) {
goto err_exit;
}
- info("USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]", usbvision->nr,usbvision->vdev->minor & 0x1f);
+ printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n", usbvision->nr,usbvision->vdev->minor & 0x1f);
// Radio Device:
if (usbvision_device_data[usbvision->DevModel].Radio) {
@@ -1623,7 +1636,7 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr)<0) {
goto err_exit;
}
- info("USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]", usbvision->nr, usbvision->rdev->minor & 0x1f);
+ printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n", usbvision->nr, usbvision->rdev->minor & 0x1f);
}
// vbi Device:
if (usbvision_device_data[usbvision->DevModel].vbi) {
@@ -1634,7 +1647,7 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
if (video_register_device(usbvision->vbi, VFL_TYPE_VBI, vbi_nr)<0) {
goto err_exit;
}
- info("USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)", usbvision->nr,usbvision->vbi->minor & 0x1f);
+ printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n", usbvision->nr,usbvision->vbi->minor & 0x1f);
}
// all done
return 0;
@@ -1764,15 +1777,17 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision)
*/
static int __devinit usbvision_probe(struct usb_interface *intf, const struct usb_device_id *devid)
{
- struct usb_device *dev = interface_to_usbdev(intf);
+ struct usb_device *dev = usb_get_dev(interface_to_usbdev(intf));
+ struct usb_interface *uif;
__u8 ifnum = intf->altsetting->desc.bInterfaceNumber;
const struct usb_host_interface *interface;
struct usb_usbvision *usbvision = NULL;
const struct usb_endpoint_descriptor *endpoint;
- int model;
+ int model,i;
PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u",
dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
+
/* Is it an USBVISION video dev? */
model = 0;
for(model = 0; usbvision_device_data[model].idVendor; model++) {
@@ -1783,7 +1798,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us
continue;
}
- info("%s: %s found", __FUNCTION__, usbvision_device_data[model].ModelString);
+ printk(KERN_INFO "%s: %s found\n", __FUNCTION__, usbvision_device_data[model].ModelString);
break;
}
@@ -1799,7 +1814,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us
endpoint = &interface->endpoint[1].desc;
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) {
err("%s: interface %d. has non-ISO endpoint!", __FUNCTION__, ifnum);
- err("%s: Endpoint attribures %d", __FUNCTION__, endpoint->bmAttributes);
+ err("%s: Endpoint attributes %d", __FUNCTION__, endpoint->bmAttributes);
return -ENODEV;
}
if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
@@ -1826,6 +1841,28 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us
down(&usbvision->lock);
+ /* compute alternate max packet sizes */
+ uif = dev->actconfig->interface[0];
+
+ usbvision->num_alt=uif->num_altsetting;
+ PDEBUG(DBG_PROBE, "Alternate settings: %i",usbvision->num_alt);
+ usbvision->alt_max_pkt_size = kmalloc(32*
+ usbvision->num_alt,GFP_KERNEL);
+ if (usbvision->alt_max_pkt_size == NULL) {
+ err("usbvision: out of memory!\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < usbvision->num_alt ; i++) {
+ u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
+ wMaxPacketSize);
+ usbvision->alt_max_pkt_size[i] =
+ (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+ PDEBUG(DBG_PROBE, "Alternate setting %i, max size= %i",i,
+ usbvision->alt_max_pkt_size[i]);
+ }
+
+
usbvision->nr = usbvision_nr++;
usbvision->have_tuner = usbvision_device_data[model].Tuner;
@@ -1838,8 +1875,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us
usbvision->DevModel = model;
usbvision->remove_pending = 0;
usbvision->iface = ifnum;
- usbvision->ifaceAltInactive = 0;
- usbvision->ifaceAltActive = 1;
+ usbvision->ifaceAlt = 0;
usbvision->video_endp = endpoint->bEndpointAddress;
usbvision->isocPacketSize = 0;
usbvision->usb_bandwidth = 0;
@@ -1895,7 +1931,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
up(&usbvision->lock);
if (usbvision->user) {
- info("%s: In use, disconnect pending", __FUNCTION__);
+ printk(KERN_INFO "%s: In use, disconnect pending\n", __FUNCTION__);
wake_up_interruptible(&usbvision->wait_frame);
wake_up_interruptible(&usbvision->wait_stream);
}
@@ -2061,7 +2097,7 @@ static int __init usbvision_init(void)
errCode = usb_register(&usbvision_driver);
if (errCode == 0) {
- info(DRIVER_DESC " : " USBVISION_VERSION_STRING);
+ printk(KERN_INFO DRIVER_DESC " : " USBVISION_VERSION_STRING "\n");
PDEBUG(DBG_PROBE, "success");
}
return errCode;
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
index e2bcaba9387..ad6afd3e42a 100644
--- a/drivers/media/video/usbvision/usbvision.h
+++ b/drivers/media/video/usbvision/usbvision.h
@@ -33,6 +33,7 @@
#include <linux/list.h>
#include <linux/usb.h>
+#include <linux/i2c.h>
#include <media/v4l2-common.h>
#include <media/tuner.h>
#include <linux/videodev2.h>
@@ -396,8 +397,11 @@ struct usb_usbvision {
/* Device structure */
struct usb_device *dev;
+ /* usb transfer */
+ int num_alt; /* Number of alternative settings */
+ unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
unsigned char iface; /* Video interface number */
- unsigned char ifaceAltActive, ifaceAltInactive; /* Alt settings */
+ unsigned char ifaceAlt; /* Alt settings */
unsigned char Vin_Reg2_Preset;
struct semaphore lock;
struct timer_list powerOffTimer;
@@ -421,6 +425,7 @@ struct usb_usbvision {
wait_queue_head_t wait_stream; /* Processes waiting */
struct usbvision_frame *curFrame; // pointer to current frame, set by usbvision_find_header
struct usbvision_frame frame[USBVISION_NUMFRAMES]; // frame buffer
+ int num_frames; // number of frames allocated
struct usbvision_sbuf sbuf[USBVISION_NUMSBUF]; // S buffering
volatile int remove_pending; /* If set then about to exit */
@@ -486,12 +491,11 @@ int usbvision_init_i2c(struct usb_usbvision *usbvision);
void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void *arg);
/* defined in usbvision-core.c */
-void usbvision_rvfree(void *mem, unsigned long size);
int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg);
int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg,
unsigned char value);
-int usbvision_frames_alloc(struct usb_usbvision *usbvision);
+int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames);
void usbvision_frames_free(struct usb_usbvision *usbvision);
int usbvision_scratch_alloc(struct usb_usbvision *usbvision);
void usbvision_scratch_free(struct usb_usbvision *usbvision);
@@ -502,6 +506,7 @@ int usbvision_setup(struct usb_usbvision *usbvision,int format);
int usbvision_init_isoc(struct usb_usbvision *usbvision);
int usbvision_restart_isoc(struct usb_usbvision *usbvision);
void usbvision_stop_isoc(struct usb_usbvision *usbvision);
+int usbvision_set_alternate(struct usb_usbvision *dev);
int usbvision_set_audio(struct usb_usbvision *usbvision, int AudioChannel);
int usbvision_audio_off(struct usb_usbvision *usbvision);
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index 8a13e595304..d2c1ae0dbfb 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -11,7 +11,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Author: Bill Dirks <bdirks@pacbell.net>
+ * Author: Bill Dirks <bill@thedirks.org>
* et al.
*
*/
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index b8ee37ded3c..54747606eae 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -12,7 +12,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Author: Bill Dirks <bdirks@pacbell.net>
+ * Author: Bill Dirks <bill@thedirks.org>
* based on code by Alan Cox, <alan@cymru.net>
*
*/
@@ -51,6 +51,7 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/errno.h>
+#include <linux/i2c.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/pgtable.h>
@@ -271,11 +272,6 @@ char *v4l2_type_names[] = {
[V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "slicec-vbi-out",
};
-static char *v4l2_memory_names[] = {
- [V4L2_MEMORY_MMAP] = "mmap",
- [V4L2_MEMORY_USERPTR] = "userptr",
- [V4L2_MEMORY_OVERLAY] = "overlay",
-};
#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown"
@@ -370,13 +366,21 @@ static const char *v4l2_ioctls[] = {
[_IOC_NR(VIDIOC_ENUMAUDOUT)] = "VIDIOC_ENUMAUDOUT",
[_IOC_NR(VIDIOC_G_PRIORITY)] = "VIDIOC_G_PRIORITY",
[_IOC_NR(VIDIOC_S_PRIORITY)] = "VIDIOC_S_PRIORITY",
-#if 1
[_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP",
-#endif
[_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS",
[_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS",
[_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS",
- [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS"
+ [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS",
+#if 1
+ [_IOC_NR(VIDIOC_ENUM_FRAMESIZES)] = "VIDIOC_ENUM_FRAMESIZES",
+ [_IOC_NR(VIDIOC_ENUM_FRAMEINTERVALS)] = "VIDIOC_ENUM_FRAMEINTERVALS",
+ [_IOC_NR(VIDIOC_G_ENC_INDEX)] = "VIDIOC_G_ENC_INDEX",
+ [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD",
+ [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD",
+
+ [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER",
+ [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER",
+#endif
};
#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
@@ -401,8 +405,6 @@ static const char *v4l2_int_ioctls[] = {
[_IOC_NR(TDA9887_SET_CONFIG)] = "TDA9887_SET_CONFIG",
[_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE",
- [_IOC_NR(VIDIOC_INT_S_REGISTER)] = "VIDIOC_INT_S_REGISTER",
- [_IOC_NR(VIDIOC_INT_G_REGISTER)] = "VIDIOC_INT_G_REGISTER",
[_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET",
[_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ",
[_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE",
@@ -419,14 +421,6 @@ static const char *v4l2_int_ioctls[] = {
};
#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
-static void v4l_print_pix_fmt (char *s, struct v4l2_pix_format *fmt)
-{
- printk ("%s: width=%d, height=%d, format=%d, field=%s, "
- "bytesperline=%d sizeimage=%d, colorspace=%d\n", s,
- fmt->width,fmt->height,fmt->pixelformat,
- prt_names(fmt->field,v4l2_field_names),
- fmt->bytesperline,fmt->sizeimage,fmt->colorspace);
-};
/* Common ioctl debug function. This function can be used by
external ioctl messages as well as internal V4L ioctl */
@@ -466,576 +460,6 @@ void v4l_printk_ioctl(unsigned int cmd)
}
}
-/* Common ioctl debug function. This function can be used by
- external ioctl messages as well as internal V4L ioctl and its
- arguments */
-void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
-{
- printk(s);
- printk(": ");
- v4l_printk_ioctl(cmd);
- switch (cmd) {
- case VIDIOC_INT_G_CHIP_IDENT:
- {
- enum v4l2_chip_ident *p=arg;
- printk ("%s: chip ident=%d\n", s, *p);
- break;
- }
- case VIDIOC_G_PRIORITY:
- case VIDIOC_S_PRIORITY:
- {
- enum v4l2_priority *p=arg;
- printk ("%s: priority=%d\n", s, *p);
- break;
- }
- case VIDIOC_INT_S_TUNER_MODE:
- {
- enum v4l2_tuner_type *p=arg;
- printk ("%s: tuner type=%d\n", s, *p);
- break;
- }
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case DECODER_SET_VBI_BYPASS:
- case DECODER_ENABLE_OUTPUT:
- case DECODER_GET_STATUS:
- case DECODER_SET_OUTPUT:
- case DECODER_SET_INPUT:
- case DECODER_SET_GPIO:
- case DECODER_SET_NORM:
- case VIDIOCCAPTURE:
- case VIDIOCSYNC:
- case VIDIOCSWRITEMODE:
-#endif
- case TUNER_SET_TYPE_ADDR:
- case TUNER_SET_STANDBY:
- case TDA9887_SET_CONFIG:
-#ifdef __OLD_VIDIOC_
- case VIDIOC_OVERLAY_OLD:
-#endif
- case VIDIOC_STREAMOFF:
- case VIDIOC_G_OUTPUT:
- case VIDIOC_S_OUTPUT:
- case VIDIOC_STREAMON:
- case VIDIOC_G_INPUT:
- case VIDIOC_OVERLAY:
- case VIDIOC_S_INPUT:
- {
- int *p=arg;
- printk ("%s: value=%d\n", s, *p);
- break;
- }
- case VIDIOC_G_AUDIO:
- case VIDIOC_S_AUDIO:
- case VIDIOC_ENUMAUDIO:
-#ifdef __OLD_VIDIOC_
- case VIDIOC_G_AUDIO_OLD:
-#endif
- {
- struct v4l2_audio *p=arg;
-
- printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n",
- s,p->index, p->name,p->capability, p->mode);
- break;
- }
- case VIDIOC_G_AUDOUT:
- case VIDIOC_S_AUDOUT:
- case VIDIOC_ENUMAUDOUT:
-#ifdef __OLD_VIDIOC_
- case VIDIOC_G_AUDOUT_OLD:
-#endif
- {
- struct v4l2_audioout *p=arg;
- printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n", s,
- p->index, p->name, p->capability,p->mode);
- break;
- }
- case VIDIOC_QBUF:
- case VIDIOC_DQBUF:
- case VIDIOC_QUERYBUF:
- {
- struct v4l2_buffer *p=arg;
- struct v4l2_timecode *tc=&p->timecode;
- printk ("%s: %02ld:%02d:%02d.%08ld index=%d, type=%s, "
- "bytesused=%d, flags=0x%08x, "
- "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n",
- s,
- (p->timestamp.tv_sec/3600),
- (int)(p->timestamp.tv_sec/60)%60,
- (int)(p->timestamp.tv_sec%60),
- p->timestamp.tv_usec,
- p->index,
- prt_names(p->type,v4l2_type_names),
- p->bytesused,p->flags,
- p->field,p->sequence,
- prt_names(p->memory,v4l2_memory_names),
- p->m.userptr);
- printk ("%s: timecode= %02d:%02d:%02d type=%d, "
- "flags=0x%08x, frames=%d, userbits=0x%08x\n",
- s,tc->hours,tc->minutes,tc->seconds,
- tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
- break;
- }
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *p=arg;
- printk ("%s: driver=%s, card=%s, bus=%s, version=0x%08x, "
- "capabilities=0x%08x\n", s,
- p->driver,p->card,p->bus_info,
- p->version,
- p->capabilities);
- break;
- }
- case VIDIOC_G_CTRL:
- case VIDIOC_S_CTRL:
-#ifdef __OLD_VIDIOC_
- case VIDIOC_S_CTRL_OLD:
-#endif
- {
- struct v4l2_control *p=arg;
- printk ("%s: id=%d, value=%d\n", s, p->id, p->value);
- break;
- }
- case VIDIOC_G_EXT_CTRLS:
- case VIDIOC_S_EXT_CTRLS:
- case VIDIOC_TRY_EXT_CTRLS:
- {
- struct v4l2_ext_controls *p = arg;
- int i;
-
- printk("%s: ctrl_class=%d, count=%d\n", s, p->ctrl_class, p->count);
- for (i = 0; i < p->count; i++) {
- struct v4l2_ext_control *c = &p->controls[i];
- if (cmd == VIDIOC_G_EXT_CTRLS)
- printk("%s: id=%d\n", s, c->id);
- else
- printk("%s: id=%d, value=%d\n", s, c->id, c->value);
- }
- break;
- }
- case VIDIOC_G_CROP:
- case VIDIOC_S_CROP:
- {
- struct v4l2_crop *p=arg;
- /*FIXME: Should also show rect structs */
- printk ("%s: type=%d\n", s, p->type);
- break;
- }
- case VIDIOC_CROPCAP:
-#ifdef __OLD_VIDIOC_
- case VIDIOC_CROPCAP_OLD:
-#endif
- {
- struct v4l2_cropcap *p=arg;
- /*FIXME: Should also show rect structs */
- printk ("%s: type=%d\n", s, p->type);
- break;
- }
- case VIDIOC_INT_DECODE_VBI_LINE:
- {
- struct v4l2_decode_vbi_line *p=arg;
- printk ("%s: is_second_field=%d, ptr=0x%08lx, line=%d, "
- "type=%d\n", s,
- p->is_second_field,(unsigned long)p->p,p->line,p->type);
- break;
- }
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *p=arg;
- printk ("%s: index=%d, type=%d, flags=%d, description=%s,"
- " pixelformat=%d\n", s,
- p->index, p->type, p->flags,p->description,
- p->pixelformat);
-
- break;
- }
- case VIDIOC_G_FMT:
- case VIDIOC_S_FMT:
- case VIDIOC_TRY_FMT:
- {
- struct v4l2_format *p=arg;
- printk ("%s: type=%s\n", s,
- prt_names(p->type,v4l2_type_names));
- switch (p->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- v4l_print_pix_fmt (s, &p->fmt.pix);
- break;
- default:
- break;
- }
- }
- case VIDIOC_G_FBUF:
- case VIDIOC_S_FBUF:
- {
- struct v4l2_framebuffer *p=arg;
- printk ("%s: capability=%d, flags=%d, base=0x%08lx\n", s,
- p->capability,p->flags, (unsigned long)p->base);
- v4l_print_pix_fmt (s, &p->fmt);
- break;
- }
- case VIDIOC_G_FREQUENCY:
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *p=arg;
- printk ("%s: tuner=%d, type=%d, frequency=%d\n", s,
- p->tuner,p->type,p->frequency);
- break;
- }
- case VIDIOC_ENUMINPUT:
- {
- struct v4l2_input *p=arg;
- printk ("%s: index=%d, name=%s, type=%d, audioset=%d, "
- "tuner=%d, std=%Ld, status=%d\n", s,
- p->index,p->name,p->type,p->audioset,
- p->tuner,
- (unsigned long long)p->std,
- p->status);
- break;
- }
- case VIDIOC_G_JPEGCOMP:
- case VIDIOC_S_JPEGCOMP:
- {
- struct v4l2_jpegcompression *p=arg;
- printk ("%s: quality=%d, APPn=%d, APP_len=%d, COM_len=%d,"
- " jpeg_markers=%d\n", s,
- p->quality,p->APPn,p->APP_len,
- p->COM_len,p->jpeg_markers);
- break;
- }
- case VIDIOC_G_MODULATOR:
- case VIDIOC_S_MODULATOR:
- {
- struct v4l2_modulator *p=arg;
- printk ("%s: index=%d, name=%s, capability=%d, rangelow=%d,"
- " rangehigh=%d, txsubchans=%d\n", s,
- p->index, p->name,p->capability,p->rangelow,
- p->rangehigh,p->txsubchans);
- break;
- }
- case VIDIOC_G_MPEGCOMP:
- case VIDIOC_S_MPEGCOMP:
- {
- struct v4l2_mpeg_compression *p=arg;
- /*FIXME: Several fields not shown */
- printk ("%s: ts_pid_pmt=%d, ts_pid_audio=%d, ts_pid_video=%d, "
- "ts_pid_pcr=%d, ps_size=%d, au_sample_rate=%d, "
- "au_pesid=%c, vi_frame_rate=%d, vi_frames_per_gop=%d, "
- "vi_bframes_count=%d, vi_pesid=%c\n", s,
- p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video,
- p->ts_pid_pcr, p->ps_size, p->au_sample_rate,
- p->au_pesid, p->vi_frame_rate,
- p->vi_frames_per_gop, p->vi_bframes_count,
- p->vi_pesid);
- break;
- }
- case VIDIOC_ENUMOUTPUT:
- {
- struct v4l2_output *p=arg;
- printk ("%s: index=%d, name=%s,type=%d, audioset=%d, "
- "modulator=%d, std=%Ld\n",
- s,p->index,p->name,p->type,p->audioset,
- p->modulator,
- (unsigned long long)p->std);
- break;
- }
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *p=arg;
- printk ("%s: id=%d, type=%d, name=%s, min/max=%d/%d,"
- " step=%d, default=%d, flags=0x%08x\n", s,
- p->id,p->type,p->name,p->minimum,p->maximum,
- p->step,p->default_value,p->flags);
- break;
- }
- case VIDIOC_QUERYMENU:
- {
- struct v4l2_querymenu *p=arg;
- printk ("%s: id=%d, index=%d, name=%s\n", s,
- p->id,p->index,p->name);
- break;
- }
- case VIDIOC_INT_G_REGISTER:
- case VIDIOC_INT_S_REGISTER:
- {
- struct v4l2_register *p=arg;
- printk ("%s: i2c_id=%d, reg=%lu, val=%d\n", s,
- p->i2c_id,p->reg,p->val);
-
- break;
- }
- case VIDIOC_REQBUFS:
- {
- struct v4l2_requestbuffers *p=arg;
- printk ("%s: count=%d, type=%s, memory=%s\n", s,
- p->count,
- prt_names(p->type,v4l2_type_names),
- prt_names(p->memory,v4l2_memory_names));
- break;
- }
- case VIDIOC_INT_S_AUDIO_ROUTING:
- case VIDIOC_INT_S_VIDEO_ROUTING:
- case VIDIOC_INT_G_AUDIO_ROUTING:
- case VIDIOC_INT_G_VIDEO_ROUTING:
- {
- struct v4l2_routing *p=arg;
- printk ("%s: input=0x%x, output=0x%x\n", s, p->input, p->output);
- break;
- }
- case VIDIOC_INT_S_CRYSTAL_FREQ:
- {
- struct v4l2_crystal_freq *p=arg;
- printk ("%s: freq=%u, flags=0x%x\n", s, p->freq, p->flags);
- break;
- }
- case VIDIOC_G_SLICED_VBI_CAP:
- {
- struct v4l2_sliced_vbi_cap *p=arg;
- printk ("%s: service_set=%d\n", s,
- p->service_set);
- break;
- }
- case VIDIOC_INT_S_VBI_DATA:
- case VIDIOC_INT_G_VBI_DATA:
- {
- struct v4l2_sliced_vbi_data *p=arg;
- printk ("%s: id=%d, field=%d, line=%d\n", s,
- p->id, p->field, p->line);
- break;
- }
- case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *p=arg;
- printk ("%s: index=%d, id=%Ld, name=%s, fps=%d/%d, "
- "framelines=%d\n", s, p->index,
- (unsigned long long)p->id, p->name,
- p->frameperiod.numerator,
- p->frameperiod.denominator,
- p->framelines);
-
- break;
- }
- case VIDIOC_G_PARM:
- case VIDIOC_S_PARM:
-#ifdef __OLD_VIDIOC_
- case VIDIOC_S_PARM_OLD:
-#endif
- {
- struct v4l2_streamparm *p=arg;
- printk ("%s: type=%d\n", s, p->type);
-
- break;
- }
- case VIDIOC_G_TUNER:
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *p=arg;
- printk ("%s: index=%d, name=%s, type=%d, capability=%d, "
- "rangelow=%d, rangehigh=%d, signal=%d, afc=%d, "
- "rxsubchans=%d, audmode=%d\n", s,
- p->index, p->name, p->type,
- p->capability, p->rangelow,p->rangehigh,
- p->rxsubchans, p->audmode, p->signal,
- p->afc);
- break;
- }
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCGVBIFMT:
- case VIDIOCSVBIFMT:
- {
- struct vbi_format *p=arg;
- printk ("%s: sampling_rate=%d, samples_per_line=%d, "
- "sample_format=%d, start=%d/%d, count=%d/%d, flags=%d\n", s,
- p->sampling_rate,p->samples_per_line,
- p->sample_format,p->start[0],p->start[1],
- p->count[0],p->count[1],p->flags);
- break;
- }
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- {
- struct video_audio *p=arg;
- printk ("%s: audio=%d, volume=%d, bass=%d, treble=%d, "
- "flags=%d, name=%s, mode=%d, balance=%d, step=%d\n",
- s,p->audio,p->volume,p->bass, p->treble,
- p->flags,p->name,p->mode,p->balance,p->step);
- break;
- }
- case VIDIOCGFBUF:
- case VIDIOCSFBUF:
- {
- struct video_buffer *p=arg;
- printk ("%s: base=%08lx, height=%d, width=%d, depth=%d, "
- "bytesperline=%d\n", s,
- (unsigned long) p->base, p->height, p->width,
- p->depth,p->bytesperline);
- break;
- }
- case VIDIOCGCAP:
- {
- struct video_capability *p=arg;
- printk ("%s: name=%s, type=%d, channels=%d, audios=%d, "
- "maxwidth=%d, maxheight=%d, minwidth=%d, minheight=%d\n",
- s,p->name,p->type,p->channels,p->audios,
- p->maxwidth,p->maxheight,p->minwidth,
- p->minheight);
-
- break;
- }
- case VIDIOCGCAPTURE:
- case VIDIOCSCAPTURE:
- {
- struct video_capture *p=arg;
- printk ("%s: x=%d, y=%d, width=%d, height=%d, decimation=%d,"
- " flags=%d\n", s,
- p->x, p->y,p->width, p->height,
- p->decimation,p->flags);
- break;
- }
- case VIDIOCGCHAN:
- case VIDIOCSCHAN:
- {
- struct video_channel *p=arg;
- printk ("%s: channel=%d, name=%s, tuners=%d, flags=%d, "
- "type=%d, norm=%d\n", s,
- p->channel,p->name,p->tuners,
- p->flags,p->type,p->norm);
-
- break;
- }
- case VIDIOCSMICROCODE:
- {
- struct video_code *p=arg;
- printk ("%s: loadwhat=%s, datasize=%d\n", s,
- p->loadwhat,p->datasize);
- break;
- }
- case DECODER_GET_CAPABILITIES:
- {
- struct video_decoder_capability *p=arg;
- printk ("%s: flags=%d, inputs=%d, outputs=%d\n", s,
- p->flags,p->inputs,p->outputs);
- break;
- }
- case DECODER_INIT:
- {
- struct video_decoder_init *p=arg;
- printk ("%s: len=%c\n", s, p->len);
- break;
- }
- case VIDIOCGPLAYINFO:
- {
- struct video_info *p=arg;
- printk ("%s: frame_count=%d, h_size=%d, v_size=%d, "
- "smpte_timecode=%d, picture_type=%d, "
- "temporal_reference=%d, user_data=%s\n", s,
- p->frame_count, p->h_size,
- p->v_size, p->smpte_timecode,
- p->picture_type, p->temporal_reference,
- p->user_data);
- break;
- }
- case VIDIOCKEY:
- {
- struct video_key *p=arg;
- printk ("%s: key=%s, flags=%d\n", s,
- p->key, p->flags);
- break;
- }
- case VIDIOCGMBUF:
- {
- struct video_mbuf *p=arg;
- printk ("%s: size=%d, frames=%d, offsets=0x%08lx\n", s,
- p->size,
- p->frames,
- (unsigned long)p->offsets);
- break;
- }
- case VIDIOCMCAPTURE:
- {
- struct video_mmap *p=arg;
- printk ("%s: frame=%d, height=%d, width=%d, format=%d\n", s,
- p->frame,
- p->height, p->width,
- p->format);
- break;
- }
- case VIDIOCGPICT:
- case VIDIOCSPICT:
- case DECODER_SET_PICTURE:
- {
- struct video_picture *p=arg;
-
- printk ("%s: brightness=%d, hue=%d, colour=%d, contrast=%d,"
- " whiteness=%d, depth=%d, palette=%d\n", s,
- p->brightness, p->hue, p->colour,
- p->contrast, p->whiteness, p->depth,
- p->palette);
- break;
- }
- case VIDIOCSPLAYMODE:
- {
- struct video_play_mode *p=arg;
- printk ("%s: mode=%d, p1=%d, p2=%d\n", s,
- p->mode,p->p1,p->p2);
- break;
- }
- case VIDIOCGTUNER:
- case VIDIOCSTUNER:
- {
- struct video_tuner *p=arg;
- printk ("%s: tuner=%d, name=%s, rangelow=%ld, rangehigh=%ld, "
- "flags=%d, mode=%d, signal=%d\n", s,
- p->tuner, p->name,p->rangelow, p->rangehigh,
- p->flags,p->mode, p->signal);
- break;
- }
- case VIDIOCGUNIT:
- {
- struct video_unit *p=arg;
- printk ("%s: video=%d, vbi=%d, radio=%d, audio=%d, "
- "teletext=%d\n", s,
- p->video,p->vbi,p->radio,p->audio,p->teletext);
- break;
- }
- case VIDIOCGWIN:
- case VIDIOCSWIN:
- {
- struct video_window *p=arg;
- printk ("%s: x=%d, y=%d, width=%d, height=%d, chromakey=%d,"
- " flags=%d, clipcount=%d\n", s,
- p->x, p->y,p->width, p->height,
- p->chromakey,p->flags,
- p->clipcount);
- break;
- }
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- {
- unsigned long *p=arg;
- printk ("%s: value=%lu\n", s, *p);
- break;
- }
-#endif
- case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- case VIDIOC_INT_I2S_CLOCK_FREQ:
- case VIDIOC_INT_S_STANDBY:
- case VIDIOC_INT_RESET:
- {
- u32 *p=arg;
-
- printk ("%s: value=%d\n", s, *p);
- break;
- }
- case VIDIOC_G_STD:
- case VIDIOC_S_STD:
- case VIDIOC_QUERYSTD:
- {
- v4l2_std_id *p=arg;
-
- printk ("%s: value=%Lu\n", s, (unsigned long long)*p);
- break;
- }
- }
-}
/* ----------------------------------------------------------------- */
@@ -1529,6 +953,28 @@ u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
return **ctrl_classes;
}
+int v4l2_chip_match_i2c_client(struct i2c_client *c, u32 match_type, u32 match_chip)
+{
+ switch (match_type) {
+ case V4L2_CHIP_MATCH_I2C_DRIVER:
+ return (c != NULL && c->driver != NULL && c->driver->id == match_chip);
+ case V4L2_CHIP_MATCH_I2C_ADDR:
+ return (c != NULL && c->addr == match_chip);
+ default:
+ return 0;
+ }
+}
+
+int v4l2_chip_match_host(u32 match_type, u32 match_chip)
+{
+ switch (match_type) {
+ case V4L2_CHIP_MATCH_HOST:
+ return match_chip == 0;
+ default:
+ return 0;
+ }
+}
+
/* ----------------------------------------------------------------- */
EXPORT_SYMBOL(v4l2_norm_to_name);
@@ -1544,7 +990,6 @@ EXPORT_SYMBOL(v4l2_prio_check);
EXPORT_SYMBOL(v4l2_field_names);
EXPORT_SYMBOL(v4l2_type_names);
EXPORT_SYMBOL(v4l_printk_ioctl);
-EXPORT_SYMBOL(v4l_printk_ioctl_arg);
EXPORT_SYMBOL(v4l2_ctrl_next);
EXPORT_SYMBOL(v4l2_ctrl_check);
@@ -1553,6 +998,9 @@ EXPORT_SYMBOL(v4l2_ctrl_query_menu);
EXPORT_SYMBOL(v4l2_ctrl_query_fill);
EXPORT_SYMBOL(v4l2_ctrl_query_fill_std);
+EXPORT_SYMBOL(v4l2_chip_match_i2c_client);
+EXPORT_SYMBOL(v4l2_chip_match_host);
+
/*
* Local variables:
* c-basic-offset: 8
diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
index 6504a586684..459786ff459 100644
--- a/drivers/media/video/video-buf.c
+++ b/drivers/media/video/video-buf.c
@@ -148,6 +148,8 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n",
data,size,dma->nr_pages);
+ dma->varea = (void *) data;
+
down_read(&current->mm->mmap_sem);
err = get_user_pages(current,current->mm,
data & PAGE_MASK, dma->nr_pages,
@@ -285,6 +287,7 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma)
vfree(dma->vmalloc);
dma->vmalloc = NULL;
+ dma->varea = NULL;
if (dma->bus_addr) {
dma->bus_addr = 0;
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index a786c1f5b96..011938fb7e0 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -1342,6 +1342,42 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
ret=vfd->vidioc_s_jpegcomp(file, fh, p);
break;
}
+ case VIDIOC_G_ENC_INDEX:
+ {
+ struct v4l2_enc_idx *p=arg;
+
+ if (!vfd->vidioc_g_enc_index)
+ break;
+ ret=vfd->vidioc_g_enc_index(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "entries=%d, entries_cap=%d\n",
+ p->entries,p->entries_cap);
+ break;
+ }
+ case VIDIOC_ENCODER_CMD:
+ {
+ struct v4l2_encoder_cmd *p=arg;
+
+ if (!vfd->vidioc_encoder_cmd)
+ break;
+ ret=vfd->vidioc_encoder_cmd(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "cmd=%d, flags=%d\n",
+ p->cmd,p->flags);
+ break;
+ }
+ case VIDIOC_TRY_ENCODER_CMD:
+ {
+ struct v4l2_encoder_cmd *p=arg;
+
+ if (!vfd->vidioc_try_encoder_cmd)
+ break;
+ ret=vfd->vidioc_try_encoder_cmd(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "cmd=%d, flags=%d\n",
+ p->cmd,p->flags);
+ break;
+ }
case VIDIOC_G_PARM:
{
struct v4l2_streamparm *p=arg;
@@ -1453,6 +1489,26 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
ret=vfd->vidioc_log_status(file, fh);
break;
}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ case VIDIOC_DBG_G_REGISTER:
+ {
+ struct v4l2_register *p=arg;
+ if (!capable(CAP_SYS_ADMIN))
+ ret=-EPERM;
+ else if (vfd->vidioc_g_register)
+ ret=vfd->vidioc_g_register(file, fh, p);
+ break;
+ }
+ case VIDIOC_DBG_S_REGISTER:
+ {
+ struct v4l2_register *p=arg;
+ if (!capable(CAP_SYS_ADMIN))
+ ret=-EPERM;
+ else if (vfd->vidioc_s_register)
+ ret=vfd->vidioc_s_register(file, fh, p);
+ break;
+ }
+#endif
} /* switch */
if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index cfb6b1f0402..f7e1d191037 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -145,7 +145,9 @@ struct vivi_buffer {
struct vivi_fmt *fmt;
+#ifdef CONFIG_VIVI_SCATTER
struct sg_to_addr *to_addr;
+#endif
};
struct vivi_dmaqueue {
@@ -230,6 +232,7 @@ static u8 bars[8][3] = {
#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
#define TSTAMP_MIN_X 64
+#ifdef CONFIG_VIVI_SCATTER
static void prep_to_addr(struct sg_to_addr to_addr[],
struct videobuf_buffer *vb)
{
@@ -262,14 +265,24 @@ static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
return (p1);
}
+#endif
+#ifdef CONFIG_VIVI_SCATTER
static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
int hmax, int line, char *timestr)
+#else
+static void gen_line(char *basep,int inipos,int wmax,
+ int hmax, int line, char *timestr)
+#endif
{
- int w,i,j,pos=inipos,pgpos,oldpg,y;
- char *p,*s,*basep;
- struct page *pg;
+ int w,i,j,pos=inipos,y;
+ char *p,*s;
u8 chr,r,g,b,color;
+#ifdef CONFIG_VIVI_SCATTER
+ int pgpos,oldpg;
+ char *basep;
+ struct page *pg;
+
unsigned long flags;
spinlock_t spinlock;
@@ -280,6 +293,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT);
spin_lock_irqsave(&spinlock,flags);
basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset;
+#endif
/* We will just duplicate the second pixel at the packet */
wmax/=2;
@@ -291,6 +305,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
b=bars[w*7/wmax][2];
for (color=0;color<4;color++) {
+#ifdef CONFIG_VIVI_SCATTER
pgpos=get_addr_pos(pos,pages,to_addr);
if (pgpos!=oldpg) {
pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT);
@@ -299,6 +314,9 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
oldpg=pgpos;
}
p=basep+pos-to_addr[pgpos].pos;
+#else
+ p=basep+pos;
+#endif
switch (color) {
case 0:
@@ -343,6 +361,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
pos=inipos+j*2;
for (color=0;color<4;color++) {
+#ifdef CONFIG_VIVI_SCATTER
pgpos=get_addr_pos(pos,pages,to_addr);
if (pgpos!=oldpg) {
pg=pfn_to_page(sg_dma_address(
@@ -356,6 +375,9 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
oldpg=pgpos;
}
p=basep+pos-to_addr[pgpos].pos;
+#else
+ p=basep+pos;
+#endif
y=TO_Y(r,g,b);
@@ -380,19 +402,27 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
end:
+#ifdef CONFIG_VIVI_SCATTER
kunmap_atomic(basep, KM_BOUNCE_READ);
spin_unlock_irqrestore(&spinlock,flags);
-
+#else
+ return;
+#endif
}
static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
{
int h,pos=0;
int hmax = buf->vb.height;
int wmax = buf->vb.width;
- struct videobuf_buffer *vb=&buf->vb;
- struct sg_to_addr *to_addr=buf->to_addr;
struct timeval ts;
+#ifdef CONFIG_VIVI_SCATTER
+ struct sg_to_addr *to_addr=buf->to_addr;
+ struct videobuf_buffer *vb=&buf->vb;
+#else
+ char *tmpbuf;
+#endif
+#ifdef CONFIG_VIVI_SCATTER
/* Test if DMA mapping is ready */
if (!sg_dma_address(&vb->dma.sglist[0]))
return;
@@ -401,9 +431,28 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
/* Check if there is enough memory */
BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2);
+#else
+ if (buf->vb.dma.varea) {
+ tmpbuf=kmalloc (wmax*2, GFP_KERNEL);
+ } else {
+ tmpbuf=buf->vb.dma.vmalloc;
+ }
+
+#endif
for (h=0;h<hmax;h++) {
+#ifdef CONFIG_VIVI_SCATTER
gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr);
+#else
+ if (buf->vb.dma.varea) {
+ gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr);
+ /* FIXME: replacing to __copy_to_user */
+ if (copy_to_user(buf->vb.dma.varea+pos,tmpbuf,wmax*2)!=0)
+ dprintk(2,"vivifill copy_to_user failed.\n");
+ } else {
+ gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr);
+ }
+#endif
pos += wmax*2;
}
@@ -429,7 +478,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
dev->h,dev->m,dev->s,(dev->us+500)/1000);
dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr,
- (unsigned long)buf->vb.dma.vmalloc,pos);
+ (unsigned long)buf->vb.dma.varea,pos);
/* Advice that buffer was filled */
buf->vb.state = STATE_DONE;
@@ -471,11 +520,12 @@ static void vivi_thread_tick(struct vivi_dmaqueue *dma_q)
/* Fill buffer */
vivi_fillbuff(dev,buf);
- }
- if (list_empty(&dma_q->active)) {
- del_timer(&dma_q->timeout);
- } else {
- mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+
+ if (list_empty(&dma_q->active)) {
+ del_timer(&dma_q->timeout);
+ } else {
+ mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+ }
}
if (bc != 1)
dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
@@ -522,6 +572,8 @@ static int vivi_thread(void *data)
dprintk(1,"thread started\n");
+ mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+
for (;;) {
vivi_sleep(dma_q);
@@ -538,7 +590,6 @@ static int vivi_start_thread(struct vivi_dmaqueue *dma_q)
dma_q->ini_jiffies=jiffies;
dprintk(1,"%s\n",__FUNCTION__);
- init_waitqueue_head(&dma_q->wq);
dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi");
@@ -546,6 +597,9 @@ static int vivi_start_thread(struct vivi_dmaqueue *dma_q)
printk(KERN_ERR "vivi: kernel_thread() failed\n");
return PTR_ERR(dma_q->kthread);
}
+ /* Wakes thread */
+ wake_up_interruptible(&dma_q->wq);
+
dprintk(1,"returning from %s\n",__FUNCTION__);
return 0;
}
@@ -663,9 +717,11 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
if (in_interrupt())
BUG();
+#ifdef CONFIG_VIVI_SCATTER
/*FIXME: Maybe a spinlock is required here */
kfree(buf->to_addr);
buf->to_addr=NULL;
+#endif
videobuf_waiton(&buf->vb,0,0);
videobuf_dma_unmap(vq, &buf->vb.dma);
@@ -711,11 +767,12 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
buf->vb.state = STATE_PREPARED;
+#ifdef CONFIG_VIVI_SCATTER
if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) {
rc=-ENOMEM;
goto fail;
}
-
+#endif
return 0;
fail:
@@ -780,6 +837,7 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb
free_buffer(vq,buf);
}
+#ifdef CONFIG_VIVI_SCATTER
static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents,
int direction)
{
@@ -812,6 +870,7 @@ static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages,
// flush_write_buffers();
return 0;
}
+#endif
static struct videobuf_queue_ops vivi_video_qops = {
.buf_setup = buffer_setup,
@@ -820,9 +879,9 @@ static struct videobuf_queue_ops vivi_video_qops = {
.buf_release = buffer_release,
/* Non-pci handling routines */
- .vb_map_sg = vivi_map_sg,
- .vb_dma_sync_sg = vivi_dma_sync_sg,
- .vb_unmap_sg = vivi_unmap_sg,
+// .vb_map_sg = vivi_map_sg,
+// .vb_dma_sync_sg = vivi_dma_sync_sg,
+// .vb_unmap_sg = vivi_unmap_sg,
};
/* ------------------------------------------------------------------
@@ -1200,11 +1259,19 @@ static int vivi_open(struct inode *inode, struct file *file)
sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
dev->h,dev->m,dev->s,(dev->us+500)/1000);
+#ifdef CONFIG_VIVI_SCATTER
+ videobuf_queue_init(&fh->vb_vidq,VIDEOBUF_DMA_SCATTER, &vivi_video_qops,
+ NULL, NULL,
+ fh->type,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct vivi_buffer),fh);
+#else
videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops,
NULL, NULL,
fh->type,
V4L2_FIELD_INTERLACED,
sizeof(struct vivi_buffer),fh);
+#endif
return 0;
}
@@ -1352,6 +1419,7 @@ static int __init vivi_init(void)
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
INIT_LIST_HEAD(&dev->vidq.queued);
+ init_waitqueue_head(&dev->vidq.wq);
/* initialize locks */
init_MUTEX(&dev->lock);
diff --git a/drivers/media/video/zc0301/zc0301.h b/drivers/media/video/zc0301/zc0301.h
index b9c93b8c16f..710f12eb912 100644
--- a/drivers/media/video/zc0301/zc0301.h
+++ b/drivers/media/video/zc0301/zc0301.h
@@ -1,7 +1,7 @@
/***************************************************************************
- * V4L2 driver for ZC0301 Image Processor and Control Chip *
+ * V4L2 driver for ZC0301[P] Image Processor and Control Chip *
* *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* 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 *
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index 8da7f15f629..f1120551c70 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -1,7 +1,7 @@
/***************************************************************************
* Video4Linux2 driver for ZC0301[P] Image Processor and Control Chip *
* *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* Informations about the chip internals needed to enable the I2C protocol *
* have been taken from the documentation of the ZC030x Video4Linux1 *
@@ -52,8 +52,8 @@
#define ZC0301_MODULE_AUTHOR "(C) 2006 Luca Risolia"
#define ZC0301_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.05"
-#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 5)
+#define ZC0301_MODULE_VERSION "1:1.07"
+#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 7)
/*****************************************************************************/
@@ -89,7 +89,7 @@ MODULE_PARM_DESC(force_munmap,
"\ndetected camera."
"\n 0 = do not force memory unmapping"
"\n 1 = force memory unmapping (save memory)"
- "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
+ "\nDefault value is "__MODULE_STRING(ZC0301_FORCE_MUNMAP)"."
"\n");
static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] =
@@ -136,7 +136,8 @@ zc0301_request_buffers(struct zc0301_device* cam, u32 count,
cam->nbuffers = count;
while (cam->nbuffers > 0) {
- if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+ if ((buff = vmalloc_32_user(cam->nbuffers *
+ PAGE_ALIGN(imagesize))))
break;
cam->nbuffers--;
}
@@ -430,7 +431,8 @@ static int zc0301_start_transfer(struct zc0301_device* cam)
struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
usb_ifnum_to_if(udev, 0),
ZC0301_ALTERNATE_SETTING);
- const unsigned int psz = altsetting->endpoint[0].desc.wMaxPacketSize;
+ const unsigned int psz = le16_to_cpu(altsetting->
+ endpoint[0].desc.wMaxPacketSize);
struct urb* urb;
s8 i, j;
int err = 0;
@@ -489,7 +491,7 @@ static int zc0301_start_transfer(struct zc0301_device* cam)
return 0;
free_urbs:
- for (i = 0; i < ZC0301_URBS; i++)
+ for (i = 0; (i < ZC0301_URBS) && cam->urb[i]; i++)
usb_free_urb(cam->urb[i]);
free_buffers:
@@ -1288,6 +1290,35 @@ zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
static int
+zc0301_vidioc_enum_framesizes(struct zc0301_device* cam, void __user * arg)
+{
+ struct v4l2_frmsizeenum frmsize;
+
+ if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
+ return -EFAULT;
+
+ if (frmsize.index != 0 && frmsize.index != 1)
+ return -EINVAL;
+
+ if (frmsize.pixel_format != V4L2_PIX_FMT_JPEG)
+ return -EINVAL;
+
+ frmsize.type = V4L2_FRMSIZE_TYPE_DISCRETE;
+
+ if (frmsize.index == 1) {
+ frmsize.discrete.width = cam->sensor.cropcap.defrect.width;
+ frmsize.discrete.height = cam->sensor.cropcap.defrect.height;
+ }
+ memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
+
+ if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+static int
zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg)
{
struct v4l2_fmtdesc fmtd;
@@ -1295,6 +1326,9 @@ zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg)
if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
return -EFAULT;
+ if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
if (fmtd.index == 0) {
strcpy(fmtd.description, "JPEG");
fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
@@ -1795,6 +1829,9 @@ static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_S_FMT:
return zc0301_vidioc_try_s_fmt(cam, cmd, arg);
+ case VIDIOC_ENUM_FRAMESIZES:
+ return zc0301_vidioc_enum_framesizes(cam, arg);
+
case VIDIOC_G_JPEGCOMP:
return zc0301_vidioc_g_jpegcomp(cam, arg);
@@ -1830,6 +1867,7 @@ static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_QUERYSTD:
case VIDIOC_ENUMSTD:
case VIDIOC_QUERYMENU:
+ case VIDIOC_ENUM_FRAMEINTERVALS:
return -EINVAL;
default:
@@ -1876,6 +1914,7 @@ static const struct file_operations zc0301_fops = {
.open = zc0301_open,
.release = zc0301_release,
.ioctl = zc0301_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.read = zc0301_read,
.poll = zc0301_poll,
.mmap = zc0301_mmap,
@@ -1913,7 +1952,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
mutex_init(&cam->dev_mutex);
DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
- "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
+ "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
for (i = 0; zc0301_sensor_table[i]; i++) {
err = zc0301_sensor_table[i](cam);
diff --git a/drivers/media/video/zc0301/zc0301_pas202bcb.c b/drivers/media/video/zc0301/zc0301_pas202bcb.c
index ecfd39a56df..3efb92a0d0d 100644
--- a/drivers/media/video/zc0301/zc0301_pas202bcb.c
+++ b/drivers/media/video/zc0301/zc0301_pas202bcb.c
@@ -1,8 +1,8 @@
/***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the ZC0301[P] Image *
+ * Plug-in for PAS202BCB image sensor connected to the ZC0301 Image *
* Processor and Control Chip *
* *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
* driver maintained by Michel Xhaard <mxhaard@magic.fr> *
diff --git a/drivers/media/video/zc0301/zc0301_pb0330.c b/drivers/media/video/zc0301/zc0301_pb0330.c
index ed8542e6c50..5784b1d1491 100644
--- a/drivers/media/video/zc0301/zc0301_pb0330.c
+++ b/drivers/media/video/zc0301/zc0301_pb0330.c
@@ -1,8 +1,8 @@
/***************************************************************************
- * Plug-in for PB-0330 image sensor connected to the ZC0301[P] Image *
+ * Plug-in for PB-0330 image sensor connected to the ZC0301P Image *
* Processor and Control Chip *
* *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
* driver maintained by Michel Xhaard <mxhaard@magic.fr> *
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
index 3daf049a288..44e82cff931 100644
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ b/drivers/media/video/zc0301/zc0301_sensor.h
@@ -1,8 +1,8 @@
/***************************************************************************
- * API for image sensors connected to the ZC0301 Image Processor and *
+ * API for image sensors connected to the ZC0301[P] Image Processor and *
* Control Chip *
* *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* 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 *
@@ -70,7 +70,7 @@ static const struct usb_device_id zc0301_id_table[] = { \
{ ZC0301_USB_DEVICE(0x041e, 0x4036, 0xff), }, /* HV7131 */ \
{ ZC0301_USB_DEVICE(0x041e, 0x403a, 0xff), }, /* HV7131 */ \
{ ZC0301_USB_DEVICE(0x0458, 0x7007, 0xff), }, /* TAS5130 */ \
- { ZC0301_USB_DEVICE(0x0458, 0x700C, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x0458, 0x700c, 0xff), }, /* TAS5130 */ \
{ ZC0301_USB_DEVICE(0x0458, 0x700f, 0xff), }, /* TAS5130 */ \
{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
{ ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */ \
@@ -93,9 +93,9 @@ extern int zc0301_i2c_read(struct zc0301_device*, u16 address, u8 length);
/*****************************************************************************/
-#define ZC0301_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
-#define ZC0301_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
-#define ZC0301_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
+#define ZC0301_MAX_CTRLS (V4L2_CID_LASTP1 - V4L2_CID_BASE + 10)
+#define ZC0301_V4L2_CID_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0)
+#define ZC0301_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 1)
struct zc0301_sensor {
char name[32];
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index 5c5a1e2dda8..c707c8ebc1a 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -1131,7 +1131,7 @@ static struct platform_driver sm501_plat_drv = {
static int __init sm501_base_init(void)
{
platform_driver_register(&sm501_plat_drv);
- return pci_module_init(&sm501_pci_drv);
+ return pci_register_driver(&sm501_pci_drv);
}
static void __exit sm501_base_exit(void)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 5046a166134..4a73e8b2428 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -376,10 +376,11 @@ static inline void mmc_set_ios(struct mmc_host *host)
{
struct mmc_ios *ios = &host->ios;
- pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n",
+ pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u "
+ "width %u timing %u\n",
mmc_hostname(host), ios->clock, ios->bus_mode,
ios->power_mode, ios->chip_select, ios->vdd,
- ios->bus_width);
+ ios->bus_width, ios->timing);
host->ops->set_ios(host, ios);
}
@@ -809,6 +810,7 @@ static void mmc_power_up(struct mmc_host *host)
host->ios.chip_select = MMC_CS_DONTCARE;
host->ios.power_mode = MMC_POWER_UP;
host->ios.bus_width = MMC_BUS_WIDTH_1;
+ host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host);
mmc_delay(1);
@@ -828,6 +830,7 @@ static void mmc_power_off(struct mmc_host *host)
host->ios.chip_select = MMC_CS_DONTCARE;
host->ios.power_mode = MMC_POWER_OFF;
host->ios.bus_width = MMC_BUS_WIDTH_1;
+ host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host);
}
@@ -1112,46 +1115,50 @@ static void mmc_process_ext_csds(struct mmc_host *host)
continue;
}
- /* Activate highspeed support. */
- cmd.opcode = MMC_SWITCH;
- cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
- (EXT_CSD_HS_TIMING << 16) |
- (1 << 8) |
- EXT_CSD_CMD_SET_NORMAL;
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ if (host->caps & MMC_CAP_MMC_HIGHSPEED) {
+ /* Activate highspeed support. */
+ cmd.opcode = MMC_SWITCH;
+ cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+ (EXT_CSD_HS_TIMING << 16) |
+ (1 << 8) |
+ EXT_CSD_CMD_SET_NORMAL;
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err != MMC_ERR_NONE) {
- printk("%s: failed to switch card to mmc v4 "
- "high-speed mode.\n",
- mmc_hostname(card->host));
- continue;
- }
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE) {
+ printk("%s: failed to switch card to mmc v4 "
+ "high-speed mode.\n",
+ mmc_hostname(card->host));
+ continue;
+ }
- mmc_card_set_highspeed(card);
+ mmc_card_set_highspeed(card);
- /* Check for host support for wide-bus modes. */
- if (!(host->caps & MMC_CAP_4_BIT_DATA)) {
- continue;
+ host->ios.timing = MMC_TIMING_SD_HS;
+ mmc_set_ios(host);
}
- /* Activate 4-bit support. */
- cmd.opcode = MMC_SWITCH;
- cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
- (EXT_CSD_BUS_WIDTH << 16) |
- (EXT_CSD_BUS_WIDTH_4 << 8) |
- EXT_CSD_CMD_SET_NORMAL;
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ /* Check for host support for wide-bus modes. */
+ if (host->caps & MMC_CAP_4_BIT_DATA) {
+ /* Activate 4-bit support. */
+ cmd.opcode = MMC_SWITCH;
+ cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+ (EXT_CSD_BUS_WIDTH << 16) |
+ (EXT_CSD_BUS_WIDTH_4 << 8) |
+ EXT_CSD_CMD_SET_NORMAL;
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err != MMC_ERR_NONE) {
- printk("%s: failed to switch card to "
- "mmc v4 4-bit bus mode.\n",
- mmc_hostname(card->host));
- continue;
- }
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE) {
+ printk("%s: failed to switch card to "
+ "mmc v4 4-bit bus mode.\n",
+ mmc_hostname(card->host));
+ continue;
+ }
- host->ios.bus_width = MMC_BUS_WIDTH_4;
+ host->ios.bus_width = MMC_BUS_WIDTH_4;
+ mmc_set_ios(host);
+ }
}
kfree(ext_csd);
@@ -1241,6 +1248,9 @@ static void mmc_read_switch_caps(struct mmc_host *host)
unsigned char *status;
struct scatterlist sg;
+ if (!(host->caps & MMC_CAP_SD_HIGHSPEED))
+ return;
+
status = kmalloc(64, GFP_KERNEL);
if (!status) {
printk(KERN_WARNING "%s: Unable to allocate buffer for "
@@ -1332,6 +1342,9 @@ static void mmc_read_switch_caps(struct mmc_host *host)
}
mmc_card_set_highspeed(card);
+
+ host->ios.timing = MMC_TIMING_SD_HS;
+ mmc_set_ios(host);
}
kfree(status);
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 7522f76b15e..d749f08601b 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -606,7 +606,6 @@ static void sdhci_finish_command(struct sdhci_host *host)
static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
{
int div;
- u8 ctrl;
u16 clk;
unsigned long timeout;
@@ -615,13 +614,6 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
- ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
- if (clock > 25000000)
- ctrl |= SDHCI_CTRL_HISPD;
- else
- ctrl &= ~SDHCI_CTRL_HISPD;
- writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
-
if (clock == 0)
goto out;
@@ -761,10 +753,17 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
sdhci_set_power(host, ios->vdd);
ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
+
if (ios->bus_width == MMC_BUS_WIDTH_4)
ctrl |= SDHCI_CTRL_4BITBUS;
else
ctrl &= ~SDHCI_CTRL_4BITBUS;
+
+ if (ios->timing == MMC_TIMING_SD_HS)
+ ctrl |= SDHCI_CTRL_HISPD;
+ else
+ ctrl &= ~SDHCI_CTRL_HISPD;
+
writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
mmiowb();
@@ -994,7 +993,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
intmask = readl(host->ioaddr + SDHCI_INT_STATUS);
- if (!intmask) {
+ if (!intmask || intmask == 0xffffffff) {
result = IRQ_NONE;
goto out;
}
@@ -1080,6 +1079,13 @@ static int sdhci_suspend (struct pci_dev *pdev, pm_message_t state)
pci_save_state(pdev);
pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+
+ for (i = 0;i < chip->num_slots;i++) {
+ if (!chip->hosts[i])
+ continue;
+ free_irq(chip->hosts[i]->irq, chip->hosts[i]);
+ }
+
pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -1108,6 +1114,11 @@ static int sdhci_resume (struct pci_dev *pdev)
continue;
if (chip->hosts[i]->flags & SDHCI_USE_DMA)
pci_set_master(pdev);
+ ret = request_irq(chip->hosts[i]->irq, sdhci_irq,
+ IRQF_SHARED, chip->hosts[i]->slot_descr,
+ chip->hosts[i]);
+ if (ret)
+ return ret;
sdhci_init(chip->hosts[i]);
mmiowb();
ret = mmc_resume_host(chip->hosts[i]->mmc);
@@ -1274,6 +1285,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
mmc->f_max = host->max_clk;
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
+ if (caps & SDHCI_CAN_DO_HISPD)
+ mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+
mmc->ocr_avail = 0;
if (caps & SDHCI_CAN_VDD_330)
mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
@@ -1282,13 +1296,6 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
if (caps & SDHCI_CAN_VDD_180)
mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;
- if ((host->max_clk > 25000000) && !(caps & SDHCI_CAN_DO_HISPD)) {
- printk(KERN_ERR "%s: Controller reports > 25 MHz base clock,"
- " but no high speed support.\n",
- host->slot_descr);
- mmc->f_max = 25000000;
- }
-
if (mmc->ocr_avail == 0) {
printk(KERN_ERR "%s: Hardware doesn't report any "
"support voltages.\n", host->slot_descr);
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index e3acd398fb3..1f644584046 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -359,6 +359,8 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
+ cfi->chips[i].ref_point_counter = 0;
+ init_waitqueue_head(&(cfi->chips[i].wq));
}
map->fldrv = &cfi_amdstd_chipdrv;
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c
index 69d49e0250a..b344ff858b2 100644
--- a/drivers/mtd/chips/cfi_cmdset_0020.c
+++ b/drivers/mtd/chips/cfi_cmdset_0020.c
@@ -158,6 +158,8 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary)
cfi->chips[i].word_write_time = 128;
cfi->chips[i].buffer_write_time = 128;
cfi->chips[i].erase_time = 1024;
+ cfi->chips[i].ref_point_counter = 0;
+ init_waitqueue_head(&(cfi->chips[i].wq));
}
return cfi_staa_setup(map);
diff --git a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c
index b1104fe1f20..1c3b34ad732 100644
--- a/drivers/mtd/maps/dilnetpc.c
+++ b/drivers/mtd/maps/dilnetpc.c
@@ -402,8 +402,8 @@ static int __init init_dnpc(void)
++higlvl_partition_info[i].name;
}
- printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n",
- is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys);
+ printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%llx\n",
+ is_dnp ? "DNPC" : "ADNP", dnpc_map.size, (unsigned long long)dnpc_map.phys);
dnpc_map.virt = ioremap_nocache(dnpc_map.phys, dnpc_map.size);
diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c
index 0bc013fd66a..aa64a475278 100644
--- a/drivers/mtd/maps/esb2rom.c
+++ b/drivers/mtd/maps/esb2rom.c
@@ -30,7 +30,7 @@
#define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */
-#define BIOS_CNTL 0xDC
+#define BIOS_CNTL 0xDC
#define BIOS_LOCK_ENABLE 0x02
#define BIOS_WRITE_ENABLE 0x01
@@ -145,7 +145,7 @@ static void esb2rom_cleanup(struct esb2rom_window *window)
}
static int __devinit esb2rom_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
struct esb2rom_window *window = &esb2rom_window;
@@ -185,7 +185,7 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev,
/* Find a region continuous to the end of the ROM window */
window->phys = 0;
pci_read_config_word(pdev, FWH_DEC_EN1, &word);
- printk(KERN_DEBUG "pci_read_config_byte : %x\n", word);
+ printk(KERN_DEBUG "pci_read_config_word : %x\n", word);
if ((word & FWH_8MiB) == FWH_8MiB)
window->phys = 0xff400000;
@@ -212,6 +212,11 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev,
else if ((word & FWH_0_5MiB) == FWH_0_5MiB)
window->phys = 0xfff80000;
+ if (window->phys == 0) {
+ printk(KERN_ERR MOD_NAME ": Rom window is closed\n");
+ goto out;
+ }
+
/* reserved 0x0020 and 0x0010 */
window->phys -= 0x400000UL;
window->size = (0xffffffffUL - window->phys) + 1UL;
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 880580c44e0..41844ea0246 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -727,6 +727,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd.erasesize = subdev[0]->erasesize;
concat->mtd.writesize = subdev[0]->writesize;
concat->mtd.oobsize = subdev[0]->oobsize;
+ concat->mtd.oobavail = subdev[0]->oobavail;
if (subdev[0]->writev)
concat->mtd.writev = concat_writev;
if (subdev[0]->read_oob)
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 633def3fb08..1af989023c6 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -200,6 +200,11 @@ static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
return -EINVAL;
instr->addr += part->offset;
ret = part->master->erase(part->master, instr);
+ if (ret) {
+ if (instr->fail_addr != 0xffffffff)
+ instr->fail_addr -= part->offset;
+ instr->addr -= part->offset;
+ }
return ret;
}
@@ -338,6 +343,7 @@ int add_mtd_partitions(struct mtd_info *master,
slave->mtd.size = parts[i].size;
slave->mtd.writesize = master->writesize;
slave->mtd.oobsize = master->oobsize;
+ slave->mtd.oobavail = master->oobavail;
slave->mtd.subpage_sft = master->subpage_sft;
slave->mtd.name = parts[i].name;
@@ -559,4 +565,3 @@ EXPORT_SYMBOL_GPL(deregister_mtd_parser);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
MODULE_DESCRIPTION("Generic support for partitioning of MTD devices");
-
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index 12608c13cce..595208f965a 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -114,7 +114,7 @@ module_param(no_autopart, int, 0);
static int show_firmware_partition = 0;
module_param(show_firmware_partition, int, 0);
-#ifdef MTD_NAND_DISKONCHIP_BBTWRITE
+#ifdef CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE
static int inftl_bbt_write = 1;
#else
static int inftl_bbt_write = 0;
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index acaf97bc80d..6af37b8cff6 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2524,6 +2524,7 @@ int nand_scan_tail(struct mtd_info *mtd)
for (i = 0; chip->ecc.layout->oobfree[i].length; i++)
chip->ecc.layout->oobavail +=
chip->ecc.layout->oobfree[i].length;
+ mtd->oobavail = chip->ecc.layout->oobavail;
/*
* Set the number of read / write steps for one page depending on ECC
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 0ddfd6de75c..5fac4c421a2 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -473,7 +473,7 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u
ecc_code[1] = ecc >> 8;
ecc_code[2] = ecc >> 16;
- pr_debug("%s: returning ecc %06x\n", __func__, ecc);
+ pr_debug("%s: returning ecc %06lx\n", __func__, ecc);
return 0;
}
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 7f1cb6e5dcc..9e14a26ca4e 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -4,6 +4,11 @@
* Copyright (C) 2005-2007 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
*
+ * Credits:
+ * Adrian Hunter <ext-adrian.hunter@nokia.com>:
+ * auto-placement support, read-while load support, various fixes
+ * Copyright (C) Nokia Corporation, 2007
+ *
* 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.
@@ -831,7 +836,7 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col
int readcol = column;
int readend = column + thislen;
int lastgap = 0;
- uint8_t *oob_buf = this->page_buf + mtd->writesize;
+ uint8_t *oob_buf = this->oob_buf;
for (free = this->ecclayout->oobfree; free->length; ++free) {
if (readcol >= lastgap)
@@ -849,7 +854,8 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col
int n = ed - st;
memcpy(buf, oob_buf + st, n);
buf += n;
- }
+ } else
+ break;
}
return 0;
}
@@ -947,9 +953,9 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
/**
* onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band
- * @mtd: MTD device structure
- * @from: offset to read from
- * @ops: oob operation description structure
+ * @param mtd: MTD device structure
+ * @param from: offset to read from
+ * @param ops: oob operation description structure
*/
static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
@@ -1017,7 +1023,7 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state)
* onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan
* @param mtd MTD device structure
* @param from offset to read from
- * @param @ops oob operation description structure
+ * @param ops oob operation description structure
*
* OneNAND read out-of-band data from the spare area for bbt scan
*/
@@ -1093,7 +1099,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
{
struct onenand_chip *this = mtd->priv;
- char *readp = this->page_buf + mtd->writesize;
+ char oobbuf[64];
int status, i;
this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize);
@@ -1102,9 +1108,9 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to
if (status)
return status;
- this->read_bufferram(mtd, ONENAND_SPARERAM, readp, 0, mtd->oobsize);
- for(i = 0; i < mtd->oobsize; i++)
- if (buf[i] != 0xFF && buf[i] != readp[i])
+ this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
+ for (i = 0; i < mtd->oobsize; i++)
+ if (buf[i] != 0xFF && buf[i] != oobbuf[i])
return -EBADMSG;
return 0;
@@ -1290,7 +1296,8 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
int n = ed - st;
memcpy(oob_buf + st, buf, n);
buf += n;
- }
+ } else
+ break;
}
return 0;
}
@@ -1312,6 +1319,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
struct onenand_chip *this = mtd->priv;
int column, ret = 0, oobsize;
int written = 0;
+ u_char *oobbuf;
DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
@@ -1331,7 +1339,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
}
/* For compatibility with NAND: Do not allow write past end of page */
- if (column + len > oobsize) {
+ if (unlikely(column + len > oobsize)) {
printk(KERN_ERR "onenand_write_oob: "
"Attempt to write past end of page\n");
return -EINVAL;
@@ -1348,6 +1356,8 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
/* Grab the lock and see if the device is available */
onenand_get_device(mtd, FL_WRITING);
+ oobbuf = this->oob_buf;
+
/* Loop until all data write */
while (written < len) {
int thislen = min_t(int, oobsize, len - written);
@@ -1358,12 +1368,12 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
/* We send data to spare ram with oobsize
* to prevent byte access */
- memset(this->page_buf, 0xff, mtd->oobsize);
+ memset(oobbuf, 0xff, mtd->oobsize);
if (mode == MTD_OOB_AUTO)
- onenand_fill_auto_oob(mtd, this->page_buf, buf, column, thislen);
+ onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);
else
- memcpy(this->page_buf + column, buf, thislen);
- this->write_bufferram(mtd, ONENAND_SPARERAM, this->page_buf, 0, mtd->oobsize);
+ memcpy(oobbuf + column, buf, thislen);
+ this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
@@ -1375,7 +1385,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
break;
}
- ret = onenand_verify_oob(mtd, this->page_buf, to);
+ ret = onenand_verify_oob(mtd, oobbuf, to);
if (ret) {
printk(KERN_ERR "onenand_write_oob: verify failed %d\n", ret);
break;
@@ -1400,9 +1410,9 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
/**
* onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band
- * @mtd: MTD device structure
- * @from: offset to read from
- * @ops: oob operation description structure
+ * @param mtd: MTD device structure
+ * @param to: offset to write
+ * @param ops: oob operation description structure
*/
static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
@@ -1616,6 +1626,7 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
* @param mtd MTD device structure
* @param ofs offset relative to mtd start
* @param len number of bytes to lock or unlock
+ * @param cmd lock or unlock command
*
* Lock or unlock one or more blocks
*/
@@ -2117,10 +2128,11 @@ static void onenand_check_features(struct mtd_info *mtd)
}
/**
- * onenand_print_device_info - Print device ID
+ * onenand_print_device_info - Print device & version ID
* @param device device ID
+ * @param version version ID
*
- * Print device ID
+ * Print device & version ID
*/
static void onenand_print_device_info(int device, int version)
{
@@ -2320,15 +2332,25 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
/* Allocate buffers, if necessary */
if (!this->page_buf) {
- size_t len;
- len = mtd->writesize + mtd->oobsize;
- this->page_buf = kmalloc(len, GFP_KERNEL);
+ this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
if (!this->page_buf) {
printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n");
return -ENOMEM;
}
this->options |= ONENAND_PAGEBUF_ALLOC;
}
+ if (!this->oob_buf) {
+ this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
+ if (!this->oob_buf) {
+ printk(KERN_ERR "onenand_scan(): Can't allocate oob_buf\n");
+ if (this->options & ONENAND_PAGEBUF_ALLOC) {
+ this->options &= ~ONENAND_PAGEBUF_ALLOC;
+ kfree(this->page_buf);
+ }
+ return -ENOMEM;
+ }
+ this->options |= ONENAND_OOBBUF_ALLOC;
+ }
this->state = FL_READY;
init_waitqueue_head(&this->wq);
@@ -2367,6 +2389,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
for (i = 0; this->ecclayout->oobfree[i].length; i++)
this->ecclayout->oobavail +=
this->ecclayout->oobfree[i].length;
+ mtd->oobavail = this->ecclayout->oobavail;
mtd->ecclayout = this->ecclayout;
@@ -2424,9 +2447,11 @@ void onenand_release(struct mtd_info *mtd)
kfree(bbm->bbt);
kfree(this->bbm);
}
- /* Buffer allocated by onenand_scan */
+ /* Buffers allocated by onenand_scan */
if (this->options & ONENAND_PAGEBUF_ALLOC)
kfree(this->page_buf);
+ if (this->options & ONENAND_OOBBUF_ALLOC)
+ kfree(this->oob_buf);
}
EXPORT_SYMBOL_GPL(onenand_scan);
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 716a47210aa..b406ecfa726 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -822,11 +822,17 @@ static int vortex_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct vortex_private *vp = netdev_priv(dev);
+ int err;
if (dev && vp) {
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- pci_enable_device(pdev);
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_WARNING "%s: Could not enable device \n",
+ dev->name);
+ return err;
+ }
pci_set_master(pdev);
if (request_irq(dev->irq, vp->full_bus_master_rx ?
&boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev)) {
@@ -852,19 +858,7 @@ static struct eisa_device_id vortex_eisa_ids[] = {
};
MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids);
-static int vortex_eisa_probe(struct device *device);
-static int vortex_eisa_remove(struct device *device);
-
-static struct eisa_driver vortex_eisa_driver = {
- .id_table = vortex_eisa_ids,
- .driver = {
- .name = "3c59x",
- .probe = vortex_eisa_probe,
- .remove = vortex_eisa_remove
- }
-};
-
-static int vortex_eisa_probe(struct device *device)
+static int __init vortex_eisa_probe(struct device *device)
{
void __iomem *ioaddr;
struct eisa_device *edev;
@@ -887,7 +881,7 @@ static int vortex_eisa_probe(struct device *device)
return 0;
}
-static int vortex_eisa_remove(struct device *device)
+static int __devexit vortex_eisa_remove(struct device *device)
{
struct eisa_device *edev;
struct net_device *dev;
@@ -912,7 +906,17 @@ static int vortex_eisa_remove(struct device *device)
free_netdev(dev);
return 0;
}
-#endif
+
+static struct eisa_driver vortex_eisa_driver = {
+ .id_table = vortex_eisa_ids,
+ .driver = {
+ .name = "3c59x",
+ .probe = vortex_eisa_probe,
+ .remove = __devexit_p(vortex_eisa_remove)
+ }
+};
+
+#endif /* CONFIG_EISA */
/* returns count found (>= 0), or negative on error */
static int __init vortex_eisa_init(void)
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 6f93a765e56..12c8453f44b 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -448,8 +448,7 @@ static void cp_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
spin_lock_irqsave(&cp->lock, flags);
cp->cpcmd &= ~RxVlanOn;
cpw16(CpCmd, cp->cpcmd);
- if (cp->vlgrp)
- cp->vlgrp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(cp->vlgrp, vid, NULL);
spin_unlock_irqrestore(&cp->lock, flags);
}
#endif /* CP_VLAN_TAG_USED */
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 9d5c083f333..5ff0922e628 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -430,10 +430,10 @@ config HPLANCE
config LASI_82596
tristate "Lasi ethernet"
- depends on NET_ETHERNET && PARISC && GSC_LASI
+ depends on NET_ETHERNET && GSC
help
- Say Y here to support the on-board Intel 82596 ethernet controller
- built into Hewlett-Packard PA-RISC machines.
+ Say Y here to support the builtin Intel 82596 ethernet controller
+ found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet.
config MIPS_JAZZ_SONIC
tristate "MIPS JAZZ onboard SONIC Ethernet support"
@@ -2245,7 +2245,7 @@ config BNX2
config SPIDER_NET
tristate "Spider Gigabit Ethernet driver"
- depends on PCI && PPC_IBM_CELL_BLADE
+ depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB)
select FW_LOADER
help
This driver supports the Gigabit Ethernet chips present on the
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 33c6645455a..7138e0e025b 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -2293,10 +2293,7 @@ static void ace_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
local_irq_save(flags);
ace_mask_irq(dev);
-
- if (ap->vlgrp)
- ap->vlgrp->vlan_devices[vid] = NULL;
-
+ vlan_group_set_device(ap->vlgrp, vid, NULL);
ace_unmask_irq(dev);
local_irq_restore(flags);
}
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index 9c399aaefbd..962c954c2d5 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -1737,8 +1737,7 @@ static void amd8111e_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid
{
struct amd8111e_priv *lp = netdev_priv(dev);
spin_lock_irq(&lp->lock);
- if (lp->vlgrp)
- lp->vlgrp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(lp->vlgrp, vid, NULL);
spin_unlock_irq(&lp->lock);
}
#endif
diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c
index 65673485bb6..88d4f70035b 100644
--- a/drivers/net/atl1/atl1_main.c
+++ b/drivers/net/atl1/atl1_main.c
@@ -1252,8 +1252,7 @@ static void atl1_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
spin_lock_irqsave(&adapter->lock, flags);
/* atl1_irq_disable(adapter); */
- if (adapter->vlgrp)
- adapter->vlgrp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(adapter->vlgrp, vid, NULL);
/* atl1_irq_enable(adapter); */
spin_unlock_irqrestore(&adapter->lock, flags);
/* We don't do Vlan filtering */
@@ -1266,7 +1265,7 @@ static void atl1_restore_vlan(struct atl1_adapter *adapter)
if (adapter->vlgrp) {
u16 vid;
for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
- if (!adapter->vlgrp->vlan_devices[vid])
+ if (!vlan_group_get_device(adapter->vlgrp, vid))
continue;
atl1_vlan_rx_add_vid(adapter->netdev, vid);
}
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 5a96d7611af..c12e5ea6181 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -4467,9 +4467,7 @@ bnx2_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
struct bnx2 *bp = netdev_priv(dev);
bnx2_netif_stop(bp);
-
- if (bp->vlgrp)
- bp->vlgrp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(bp->vlgrp, vid, NULL);
bnx2_set_rx_mode(dev);
bnx2_netif_start(bp);
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index a7c8f98a890..e4724d874e7 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -60,6 +60,7 @@
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
+#include <linux/igmp.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <net/sock.h>
@@ -488,9 +489,9 @@ static void bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid)
/* Save and then restore vlan_dev in the grp array,
* since the slave's driver might clear it.
*/
- vlan_dev = bond->vlgrp->vlan_devices[vid];
+ vlan_dev = vlan_group_get_device(bond->vlgrp, vid);
slave_dev->vlan_rx_kill_vid(slave_dev, vid);
- bond->vlgrp->vlan_devices[vid] = vlan_dev;
+ vlan_group_set_device(bond->vlgrp, vid, vlan_dev);
}
}
@@ -550,9 +551,9 @@ static void bond_del_vlans_from_slave(struct bonding *bond, struct net_device *s
/* Save and then restore vlan_dev in the grp array,
* since the slave's driver might clear it.
*/
- vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id];
+ vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
slave_dev->vlan_rx_kill_vid(slave_dev, vlan->vlan_id);
- bond->vlgrp->vlan_devices[vlan->vlan_id] = vlan_dev;
+ vlan_group_set_device(bond->vlgrp, vlan->vlan_id, vlan_dev);
}
unreg:
@@ -861,6 +862,28 @@ static void bond_mc_delete(struct bonding *bond, void *addr, int alen)
}
}
+
+/*
+ * Retrieve the list of registered multicast addresses for the bonding
+ * device and retransmit an IGMP JOIN request to the current active
+ * slave.
+ */
+static void bond_resend_igmp_join_requests(struct bonding *bond)
+{
+ struct in_device *in_dev;
+ struct ip_mc_list *im;
+
+ rcu_read_lock();
+ in_dev = __in_dev_get_rcu(bond->dev);
+ if (in_dev) {
+ for (im = in_dev->mc_list; im; im = im->next) {
+ ip_mc_rejoin_group(im);
+ }
+ }
+
+ rcu_read_unlock();
+}
+
/*
* Totally destroys the mc_list in bond
*/
@@ -874,6 +897,7 @@ static void bond_mc_list_destroy(struct bonding *bond)
kfree(dmi);
dmi = bond->mc_list;
}
+ bond->mc_list = NULL;
}
/*
@@ -967,6 +991,7 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active, struct
for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) {
dev_mc_add(new_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
}
+ bond_resend_igmp_join_requests(bond);
}
}
@@ -2397,7 +2422,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
vlan_id = 0;
list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
vlan_list) {
- vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id];
+ vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
if (vlan_dev == rt->u.dst.dev) {
vlan_id = vlan->vlan_id;
dprintk("basa: vlan match on %s %d\n",
@@ -2444,7 +2469,7 @@ static void bond_send_gratuitous_arp(struct bonding *bond)
}
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
- vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id];
+ vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
if (vlan->vlan_ip) {
bond_arp_send(slave->dev, ARPOP_REPLY, vlan->vlan_ip,
vlan->vlan_ip, vlan->vlan_id);
@@ -3371,7 +3396,7 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event,
list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
vlan_list) {
- vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id];
+ vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
if (vlan_dev == event_dev) {
switch (event) {
case NETDEV_UP:
@@ -3423,15 +3448,21 @@ void bond_register_arp(struct bonding *bond)
{
struct packet_type *pt = &bond->arp_mon_pt;
+ if (pt->type)
+ return;
+
pt->type = htons(ETH_P_ARP);
- pt->dev = NULL; /*bond->dev;XXX*/
+ pt->dev = bond->dev;
pt->func = bond_arp_rcv;
dev_add_pack(pt);
}
void bond_unregister_arp(struct bonding *bond)
{
- dev_remove_pack(&bond->arp_mon_pt);
+ struct packet_type *pt = &bond->arp_mon_pt;
+
+ dev_remove_pack(pt);
+ pt->type = 0;
}
/*---------------------------- Hashing Policies -----------------------------*/
@@ -4011,42 +4042,6 @@ out:
return 0;
}
-static void bond_activebackup_xmit_copy(struct sk_buff *skb,
- struct bonding *bond,
- struct slave *slave)
-{
- struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
- struct ethhdr *eth_data;
- u8 *hwaddr;
- int res;
-
- if (!skb2) {
- printk(KERN_ERR DRV_NAME ": Error: "
- "bond_activebackup_xmit_copy(): skb_copy() failed\n");
- return;
- }
-
- skb2->mac.raw = (unsigned char *)skb2->data;
- eth_data = eth_hdr(skb2);
-
- /* Pick an appropriate source MAC address
- * -- use slave's perm MAC addr, unless used by bond
- * -- otherwise, borrow active slave's perm MAC addr
- * since that will not be used
- */
- hwaddr = slave->perm_hwaddr;
- if (!memcmp(eth_data->h_source, hwaddr, ETH_ALEN))
- hwaddr = bond->curr_active_slave->perm_hwaddr;
-
- /* Set source MAC address appropriately */
- memcpy(eth_data->h_source, hwaddr, ETH_ALEN);
-
- res = bond_dev_queue_xmit(bond, skb2, slave->dev);
- if (res)
- dev_kfree_skb(skb2);
-
- return;
-}
/*
* in active-backup mode, we know that bond->curr_active_slave is always valid if
@@ -4067,21 +4062,6 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
if (!bond->curr_active_slave)
goto out;
- /* Xmit IGMP frames on all slaves to ensure rapid fail-over
- for multicast traffic on snooping switches */
- if (skb->protocol == __constant_htons(ETH_P_IP) &&
- skb->nh.iph->protocol == IPPROTO_IGMP) {
- struct slave *slave, *active_slave;
- int i;
-
- active_slave = bond->curr_active_slave;
- bond_for_each_slave_from_to(bond, slave, i, active_slave->next,
- active_slave->prev)
- if (IS_UP(slave->dev) &&
- (slave->link == BOND_LINK_UP))
- bond_activebackup_xmit_copy(skb, bond, slave);
- }
-
res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev);
out:
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index 7d0f24f6977..125c9b10586 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -889,8 +889,7 @@ static void vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
struct adapter *adapter = dev->priv;
spin_lock_irq(&adapter->async_lock);
- if (adapter->vlan_grp)
- adapter->vlan_grp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(adapter->vlan_grp, vid, NULL);
spin_unlock_irq(&adapter->async_lock);
}
#endif
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index 89a682702fa..326d4a66512 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -1696,6 +1696,7 @@ irqreturn_t t1_interrupt(int irq, void *cookie)
{
int work_done;
struct adapter *adapter = cookie;
+ struct respQ *Q = &adapter->sge->respQ;
spin_lock(&adapter->async_lock);
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 5c97a64451c..80c3d8f268a 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -74,6 +74,11 @@ enum { /* adapter flags */
struct rx_desc;
struct rx_sw_desc;
+struct sge_fl_page {
+ struct skb_frag_struct frag;
+ unsigned char *va;
+};
+
struct sge_fl { /* SGE per free-buffer list state */
unsigned int buf_size; /* size of each Rx buffer */
unsigned int credits; /* # of available Rx buffers */
@@ -81,11 +86,13 @@ struct sge_fl { /* SGE per free-buffer list state */
unsigned int cidx; /* consumer index */
unsigned int pidx; /* producer index */
unsigned int gen; /* free list generation */
+ unsigned int cntxt_id; /* SGE context id for the free list */
+ struct sge_fl_page page;
struct rx_desc *desc; /* address of HW Rx descriptor ring */
struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */
dma_addr_t phys_addr; /* physical address of HW ring start */
- unsigned int cntxt_id; /* SGE context id for the free list */
unsigned long empty; /* # of times queue ran out of buffers */
+ unsigned long alloc_failed; /* # of times buffer allocation failed */
};
/*
@@ -121,6 +128,8 @@ struct sge_rspq { /* state for an SGE response queue */
unsigned long empty; /* # of times queue ran out of credits */
unsigned long nomem; /* # of responses deferred due to no mem */
unsigned long unhandled_irqs; /* # of spurious intrs */
+ unsigned long starved;
+ unsigned long restarted;
};
struct tx_desc;
diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/cxgb3/cxgb3_ioctl.h
index a94281861a6..0a82fcddf2d 100644
--- a/drivers/net/cxgb3/cxgb3_ioctl.h
+++ b/drivers/net/cxgb3/cxgb3_ioctl.h
@@ -36,28 +36,17 @@
* Ioctl commands specific to this driver.
*/
enum {
- CHELSIO_SETREG = 1024,
- CHELSIO_GETREG,
- CHELSIO_SETTPI,
- CHELSIO_GETTPI,
- CHELSIO_GETMTUTAB,
- CHELSIO_SETMTUTAB,
- CHELSIO_GETMTU,
- CHELSIO_SET_PM,
- CHELSIO_GET_PM,
- CHELSIO_GET_TCAM,
- CHELSIO_SET_TCAM,
- CHELSIO_GET_TCB,
- CHELSIO_GET_MEM,
- CHELSIO_LOAD_FW,
- CHELSIO_GET_PROTO,
- CHELSIO_SET_PROTO,
- CHELSIO_SET_TRACE_FILTER,
- CHELSIO_SET_QSET_PARAMS,
- CHELSIO_GET_QSET_PARAMS,
- CHELSIO_SET_QSET_NUM,
- CHELSIO_GET_QSET_NUM,
- CHELSIO_SET_PKTSCHED,
+ CHELSIO_GETMTUTAB = 1029,
+ CHELSIO_SETMTUTAB = 1030,
+ CHELSIO_SET_PM = 1032,
+ CHELSIO_GET_PM = 1033,
+ CHELSIO_GET_MEM = 1038,
+ CHELSIO_LOAD_FW = 1041,
+ CHELSIO_SET_TRACE_FILTER = 1044,
+ CHELSIO_SET_QSET_PARAMS = 1045,
+ CHELSIO_GET_QSET_PARAMS = 1046,
+ CHELSIO_SET_QSET_NUM = 1047,
+ CHELSIO_GET_QSET_NUM = 1048,
};
struct ch_reg {
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 43583ed655a..7ff834e45d6 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -434,27 +434,25 @@ static int setup_sge_qsets(struct adapter *adap)
static ssize_t attr_show(struct device *d, struct device_attribute *attr,
char *buf,
- ssize_t(*format) (struct adapter *, char *))
+ ssize_t(*format) (struct net_device *, char *))
{
ssize_t len;
- struct adapter *adap = to_net_dev(d)->priv;
/* Synchronize with ioctls that may shut down the device */
rtnl_lock();
- len = (*format) (adap, buf);
+ len = (*format) (to_net_dev(d), buf);
rtnl_unlock();
return len;
}
static ssize_t attr_store(struct device *d, struct device_attribute *attr,
const char *buf, size_t len,
- ssize_t(*set) (struct adapter *, unsigned int),
+ ssize_t(*set) (struct net_device *, unsigned int),
unsigned int min_val, unsigned int max_val)
{
char *endp;
ssize_t ret;
unsigned int val;
- struct adapter *adap = to_net_dev(d)->priv;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -464,7 +462,7 @@ static ssize_t attr_store(struct device *d, struct device_attribute *attr,
return -EINVAL;
rtnl_lock();
- ret = (*set) (adap, val);
+ ret = (*set) (to_net_dev(d), val);
if (!ret)
ret = len;
rtnl_unlock();
@@ -472,8 +470,9 @@ static ssize_t attr_store(struct device *d, struct device_attribute *attr,
}
#define CXGB3_SHOW(name, val_expr) \
-static ssize_t format_##name(struct adapter *adap, char *buf) \
+static ssize_t format_##name(struct net_device *dev, char *buf) \
{ \
+ struct adapter *adap = dev->priv; \
return sprintf(buf, "%u\n", val_expr); \
} \
static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
@@ -482,8 +481,10 @@ static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
return attr_show(d, attr, buf, format_##name); \
}
-static ssize_t set_nfilters(struct adapter *adap, unsigned int val)
+static ssize_t set_nfilters(struct net_device *dev, unsigned int val)
{
+ struct adapter *adap = dev->priv;
+
if (adap->flags & FULL_INIT_DONE)
return -EBUSY;
if (val && adap->params.rev == 0)
@@ -500,8 +501,10 @@ static ssize_t store_nfilters(struct device *d, struct device_attribute *attr,
return attr_store(d, attr, buf, len, set_nfilters, 0, ~0);
}
-static ssize_t set_nservers(struct adapter *adap, unsigned int val)
+static ssize_t set_nservers(struct net_device *dev, unsigned int val)
{
+ struct adapter *adap = dev->priv;
+
if (adap->flags & FULL_INIT_DONE)
return -EBUSY;
if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters)
@@ -1549,32 +1552,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
return -EFAULT;
switch (cmd) {
- case CHELSIO_SETREG:{
- struct ch_reg edata;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (copy_from_user(&edata, useraddr, sizeof(edata)))
- return -EFAULT;
- if ((edata.addr & 3) != 0
- || edata.addr >= adapter->mmio_len)
- return -EINVAL;
- writel(edata.val, adapter->regs + edata.addr);
- break;
- }
- case CHELSIO_GETREG:{
- struct ch_reg edata;
-
- if (copy_from_user(&edata, useraddr, sizeof(edata)))
- return -EFAULT;
- if ((edata.addr & 3) != 0
- || edata.addr >= adapter->mmio_len)
- return -EINVAL;
- edata.val = readl(adapter->regs + edata.addr);
- if (copy_to_user(useraddr, &edata, sizeof(edata)))
- return -EFAULT;
- break;
- }
case CHELSIO_SET_QSET_PARAMS:{
int i;
struct qset_params *q;
@@ -1838,10 +1815,10 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
return -EINVAL;
/*
- * Version scheme:
- * bits 0..9: chip version
- * bits 10..15: chip revision
- */
+ * Version scheme:
+ * bits 0..9: chip version
+ * bits 10..15: chip revision
+ */
t.version = 3 | (adapter->params.rev << 10);
if (copy_to_user(useraddr, &t, sizeof(t)))
return -EFAULT;
@@ -1890,20 +1867,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
t.trace_rx);
break;
}
- case CHELSIO_SET_PKTSCHED:{
- struct ch_pktsched_params p;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (!adapter->open_device_map)
- return -EAGAIN; /* uP and SGE must be running */
- if (copy_from_user(&p, useraddr, sizeof(p)))
- return -EFAULT;
- send_pktsched_cmd(adapter, p.sched, p.idx, p.min, p.max,
- p.binding);
- break;
-
- }
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
index b2cf5f6feb4..f6ed033efb5 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -160,14 +160,16 @@ static struct net_device *get_iff_from_mac(struct adapter *adapter,
int i;
for_each_port(adapter, i) {
- const struct vlan_group *grp;
+ struct vlan_group *grp;
struct net_device *dev = adapter->port[i];
const struct port_info *p = netdev_priv(dev);
if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) {
if (vlan && vlan != VLAN_VID_MASK) {
grp = p->vlan_grp;
- dev = grp ? grp->vlan_devices[vlan] : NULL;
+ dev = NULL;
+ if (grp)
+ dev = vlan_group_get_device(grp, vlan);
} else
while (dev->master)
dev = dev->master;
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index 3f2cf8a07c6..c23783432e5 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -45,9 +45,25 @@
#define USE_GTS 0
#define SGE_RX_SM_BUF_SIZE 1536
+
+/*
+ * If USE_RX_PAGE is defined, the small freelist populated with (partial)
+ * pages instead of skbs. Pages are carved up into RX_PAGE_SIZE chunks (must
+ * be a multiple of the host page size).
+ */
+#define USE_RX_PAGE
+#define RX_PAGE_SIZE 2048
+
+/*
+ * skb freelist packets are copied into a new skb (and the freelist one is
+ * reused) if their len is <=
+ */
#define SGE_RX_COPY_THRES 256
-# define SGE_RX_DROP_THRES 16
+/*
+ * Minimum number of freelist entries before we start dropping TUNNEL frames.
+ */
+#define SGE_RX_DROP_THRES 16
/*
* Period of the Tx buffer reclaim timer. This timer does not need to run
@@ -85,7 +101,10 @@ struct tx_sw_desc { /* SW state per Tx descriptor */
};
struct rx_sw_desc { /* SW state per Rx descriptor */
- struct sk_buff *skb;
+ union {
+ struct sk_buff *skb;
+ struct sge_fl_page page;
+ } t;
DECLARE_PCI_UNMAP_ADDR(dma_addr);
};
@@ -105,6 +124,15 @@ struct unmap_info { /* packet unmapping info, overlays skb->cb */
};
/*
+ * Holds unmapping information for Tx packets that need deferred unmapping.
+ * This structure lives at skb->head and must be allocated by callers.
+ */
+struct deferred_unmap_info {
+ struct pci_dev *pdev;
+ dma_addr_t addr[MAX_SKB_FRAGS + 1];
+};
+
+/*
* Maps a number of flits to the number of Tx descriptors that can hold them.
* The formula is
*
@@ -252,10 +280,13 @@ static void free_tx_desc(struct adapter *adapter, struct sge_txq *q,
struct pci_dev *pdev = adapter->pdev;
unsigned int cidx = q->cidx;
+ const int need_unmap = need_skb_unmap() &&
+ q->cntxt_id >= FW_TUNNEL_SGEEC_START;
+
d = &q->sdesc[cidx];
while (n--) {
if (d->skb) { /* an SGL is present */
- if (need_skb_unmap())
+ if (need_unmap)
unmap_skb(d->skb, q, cidx, pdev);
if (d->skb->priority == cidx)
kfree_skb(d->skb);
@@ -320,16 +351,27 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q)
pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr),
q->buf_size, PCI_DMA_FROMDEVICE);
- kfree_skb(d->skb);
- d->skb = NULL;
+
+ if (q->buf_size != RX_PAGE_SIZE) {
+ kfree_skb(d->t.skb);
+ d->t.skb = NULL;
+ } else {
+ if (d->t.page.frag.page)
+ put_page(d->t.page.frag.page);
+ d->t.page.frag.page = NULL;
+ }
if (++cidx == q->size)
cidx = 0;
}
+
+ if (q->page.frag.page)
+ put_page(q->page.frag.page);
+ q->page.frag.page = NULL;
}
/**
* add_one_rx_buf - add a packet buffer to a free-buffer list
- * @skb: the buffer to add
+ * @va: va of the buffer to add
* @len: the buffer length
* @d: the HW Rx descriptor to write
* @sd: the SW Rx descriptor to write
@@ -339,14 +381,13 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q)
* Add a buffer of the given length to the supplied HW and SW Rx
* descriptors.
*/
-static inline void add_one_rx_buf(struct sk_buff *skb, unsigned int len,
+static inline void add_one_rx_buf(unsigned char *va, unsigned int len,
struct rx_desc *d, struct rx_sw_desc *sd,
unsigned int gen, struct pci_dev *pdev)
{
dma_addr_t mapping;
- sd->skb = skb;
- mapping = pci_map_single(pdev, skb->data, len, PCI_DMA_FROMDEVICE);
+ mapping = pci_map_single(pdev, va, len, PCI_DMA_FROMDEVICE);
pci_unmap_addr_set(sd, dma_addr, mapping);
d->addr_lo = cpu_to_be32(mapping);
@@ -371,14 +412,47 @@ static void refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp)
{
struct rx_sw_desc *sd = &q->sdesc[q->pidx];
struct rx_desc *d = &q->desc[q->pidx];
+ struct sge_fl_page *p = &q->page;
while (n--) {
- struct sk_buff *skb = alloc_skb(q->buf_size, gfp);
+ unsigned char *va;
- if (!skb)
- break;
+ if (unlikely(q->buf_size != RX_PAGE_SIZE)) {
+ struct sk_buff *skb = alloc_skb(q->buf_size, gfp);
+
+ if (!skb) {
+ q->alloc_failed++;
+ break;
+ }
+ va = skb->data;
+ sd->t.skb = skb;
+ } else {
+ if (!p->frag.page) {
+ p->frag.page = alloc_pages(gfp, 0);
+ if (unlikely(!p->frag.page)) {
+ q->alloc_failed++;
+ break;
+ } else {
+ p->frag.size = RX_PAGE_SIZE;
+ p->frag.page_offset = 0;
+ p->va = page_address(p->frag.page);
+ }
+ }
+
+ memcpy(&sd->t, p, sizeof(*p));
+ va = p->va;
+
+ p->frag.page_offset += RX_PAGE_SIZE;
+ BUG_ON(p->frag.page_offset > PAGE_SIZE);
+ p->va += RX_PAGE_SIZE;
+ if (p->frag.page_offset == PAGE_SIZE)
+ p->frag.page = NULL;
+ else
+ get_page(p->frag.page);
+ }
+
+ add_one_rx_buf(va, q->buf_size, d, sd, q->gen, adap->pdev);
- add_one_rx_buf(skb, q->buf_size, d, sd, q->gen, adap->pdev);
d++;
sd++;
if (++q->pidx == q->size) {
@@ -413,7 +487,7 @@ static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q,
struct rx_desc *from = &q->desc[idx];
struct rx_desc *to = &q->desc[q->pidx];
- q->sdesc[q->pidx] = q->sdesc[idx];
+ memcpy(&q->sdesc[q->pidx], &q->sdesc[idx], sizeof(struct rx_sw_desc));
to->addr_lo = from->addr_lo; /* already big endian */
to->addr_hi = from->addr_hi; /* likewise */
wmb();
@@ -446,7 +520,7 @@ static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q,
* of the SW ring.
*/
static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size,
- size_t sw_size, dma_addr_t *phys, void *metadata)
+ size_t sw_size, dma_addr_t * phys, void *metadata)
{
size_t len = nelem * elem_size;
void *s = NULL;
@@ -576,61 +650,6 @@ static inline unsigned int flits_to_desc(unsigned int n)
}
/**
- * get_packet - return the next ingress packet buffer from a free list
- * @adap: the adapter that received the packet
- * @fl: the SGE free list holding the packet
- * @len: the packet length including any SGE padding
- * @drop_thres: # of remaining buffers before we start dropping packets
- *
- * Get the next packet from a free list and complete setup of the
- * sk_buff. If the packet is small we make a copy and recycle the
- * original buffer, otherwise we use the original buffer itself. If a
- * positive drop threshold is supplied packets are dropped and their
- * buffers recycled if (a) the number of remaining buffers is under the
- * threshold and the packet is too big to copy, or (b) the packet should
- * be copied but there is no memory for the copy.
- */
-static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl,
- unsigned int len, unsigned int drop_thres)
-{
- struct sk_buff *skb = NULL;
- struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
-
- prefetch(sd->skb->data);
-
- if (len <= SGE_RX_COPY_THRES) {
- skb = alloc_skb(len, GFP_ATOMIC);
- if (likely(skb != NULL)) {
- __skb_put(skb, len);
- pci_dma_sync_single_for_cpu(adap->pdev,
- pci_unmap_addr(sd,
- dma_addr),
- len, PCI_DMA_FROMDEVICE);
- memcpy(skb->data, sd->skb->data, len);
- pci_dma_sync_single_for_device(adap->pdev,
- pci_unmap_addr(sd,
- dma_addr),
- len, PCI_DMA_FROMDEVICE);
- } else if (!drop_thres)
- goto use_orig_buf;
- recycle:
- recycle_rx_buf(adap, fl, fl->cidx);
- return skb;
- }
-
- if (unlikely(fl->credits < drop_thres))
- goto recycle;
-
- use_orig_buf:
- pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
- fl->buf_size, PCI_DMA_FROMDEVICE);
- skb = sd->skb;
- skb_put(skb, len);
- __refill_fl(adap, fl);
- return skb;
-}
-
-/**
* get_imm_packet - return the next ingress packet buffer from a response
* @resp: the response descriptor containing the packet data
*
@@ -1227,6 +1246,50 @@ int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb)
}
/**
+ * deferred_unmap_destructor - unmap a packet when it is freed
+ * @skb: the packet
+ *
+ * This is the packet destructor used for Tx packets that need to remain
+ * mapped until they are freed rather than until their Tx descriptors are
+ * freed.
+ */
+static void deferred_unmap_destructor(struct sk_buff *skb)
+{
+ int i;
+ const dma_addr_t *p;
+ const struct skb_shared_info *si;
+ const struct deferred_unmap_info *dui;
+ const struct unmap_info *ui = (struct unmap_info *)skb->cb;
+
+ dui = (struct deferred_unmap_info *)skb->head;
+ p = dui->addr;
+
+ if (ui->len)
+ pci_unmap_single(dui->pdev, *p++, ui->len, PCI_DMA_TODEVICE);
+
+ si = skb_shinfo(skb);
+ for (i = 0; i < si->nr_frags; i++)
+ pci_unmap_page(dui->pdev, *p++, si->frags[i].size,
+ PCI_DMA_TODEVICE);
+}
+
+static void setup_deferred_unmapping(struct sk_buff *skb, struct pci_dev *pdev,
+ const struct sg_ent *sgl, int sgl_flits)
+{
+ dma_addr_t *p;
+ struct deferred_unmap_info *dui;
+
+ dui = (struct deferred_unmap_info *)skb->head;
+ dui->pdev = pdev;
+ for (p = dui->addr; sgl_flits >= 3; sgl++, sgl_flits -= 3) {
+ *p++ = be64_to_cpu(sgl->addr[0]);
+ *p++ = be64_to_cpu(sgl->addr[1]);
+ }
+ if (sgl_flits)
+ *p = be64_to_cpu(sgl->addr[0]);
+}
+
+/**
* write_ofld_wr - write an offload work request
* @adap: the adapter
* @skb: the packet to send
@@ -1262,8 +1325,11 @@ static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb,
sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
sgl_flits = make_sgl(skb, sgp, skb->h.raw, skb->tail - skb->h.raw,
adap->pdev);
- if (need_skb_unmap())
+ if (need_skb_unmap()) {
+ setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits);
+ skb->destructor = deferred_unmap_destructor;
((struct unmap_info *)skb->cb)->len = skb->tail - skb->h.raw;
+ }
write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits,
gen, from->wr_hi, from->wr_lo);
@@ -1617,7 +1683,6 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)(skb->data + pad);
struct port_info *pi;
- rq->eth_pkts++;
skb_pull(skb, sizeof(*p) + pad);
skb->dev = adap->port[p->iff];
skb->dev->last_rx = jiffies;
@@ -1645,6 +1710,85 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
netif_rx(skb);
}
+#define SKB_DATA_SIZE 128
+
+static void skb_data_init(struct sk_buff *skb, struct sge_fl_page *p,
+ unsigned int len)
+{
+ skb->len = len;
+ if (len <= SKB_DATA_SIZE) {
+ memcpy(skb->data, p->va, len);
+ skb->tail += len;
+ put_page(p->frag.page);
+ } else {
+ memcpy(skb->data, p->va, SKB_DATA_SIZE);
+ skb_shinfo(skb)->frags[0].page = p->frag.page;
+ skb_shinfo(skb)->frags[0].page_offset =
+ p->frag.page_offset + SKB_DATA_SIZE;
+ skb_shinfo(skb)->frags[0].size = len - SKB_DATA_SIZE;
+ skb_shinfo(skb)->nr_frags = 1;
+ skb->data_len = len - SKB_DATA_SIZE;
+ skb->tail += SKB_DATA_SIZE;
+ skb->truesize += skb->data_len;
+ }
+}
+
+/**
+* get_packet - return the next ingress packet buffer from a free list
+* @adap: the adapter that received the packet
+* @fl: the SGE free list holding the packet
+* @len: the packet length including any SGE padding
+* @drop_thres: # of remaining buffers before we start dropping packets
+*
+* Get the next packet from a free list and complete setup of the
+* sk_buff. If the packet is small we make a copy and recycle the
+* original buffer, otherwise we use the original buffer itself. If a
+* positive drop threshold is supplied packets are dropped and their
+* buffers recycled if (a) the number of remaining buffers is under the
+* threshold and the packet is too big to copy, or (b) the packet should
+* be copied but there is no memory for the copy.
+*/
+static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl,
+ unsigned int len, unsigned int drop_thres)
+{
+ struct sk_buff *skb = NULL;
+ struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
+
+ prefetch(sd->t.skb->data);
+
+ if (len <= SGE_RX_COPY_THRES) {
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (likely(skb != NULL)) {
+ struct rx_desc *d = &fl->desc[fl->cidx];
+ dma_addr_t mapping =
+ (dma_addr_t)((u64) be32_to_cpu(d->addr_hi) << 32 |
+ be32_to_cpu(d->addr_lo));
+
+ __skb_put(skb, len);
+ pci_dma_sync_single_for_cpu(adap->pdev, mapping, len,
+ PCI_DMA_FROMDEVICE);
+ memcpy(skb->data, sd->t.skb->data, len);
+ pci_dma_sync_single_for_device(adap->pdev, mapping, len,
+ PCI_DMA_FROMDEVICE);
+ } else if (!drop_thres)
+ goto use_orig_buf;
+recycle:
+ recycle_rx_buf(adap, fl, fl->cidx);
+ return skb;
+ }
+
+ if (unlikely(fl->credits < drop_thres))
+ goto recycle;
+
+use_orig_buf:
+ pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
+ fl->buf_size, PCI_DMA_FROMDEVICE);
+ skb = sd->t.skb;
+ skb_put(skb, len);
+ __refill_fl(adap, fl);
+ return skb;
+}
+
/**
* handle_rsp_cntrl_info - handles control information in a response
* @qs: the queue set corresponding to the response
@@ -1767,7 +1911,7 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs,
q->next_holdoff = q->holdoff_tmr;
while (likely(budget_left && is_new_response(r, q))) {
- int eth, ethpad = 0;
+ int eth, ethpad = 2;
struct sk_buff *skb = NULL;
u32 len, flags = ntohl(r->flags);
u32 rss_hi = *(const u32 *)r, rss_lo = r->rss_hdr.rss_hash_val;
@@ -1794,18 +1938,56 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs,
break;
}
q->imm_data++;
+ ethpad = 0;
} else if ((len = ntohl(r->len_cq)) != 0) {
- struct sge_fl *fl;
+ struct sge_fl *fl =
+ (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0];
+
+ if (fl->buf_size == RX_PAGE_SIZE) {
+ struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
+ struct sge_fl_page *p = &sd->t.page;
+
+ prefetch(p->va);
+ prefetch(p->va + L1_CACHE_BYTES);
+
+ __refill_fl(adap, fl);
+
+ pci_unmap_single(adap->pdev,
+ pci_unmap_addr(sd, dma_addr),
+ fl->buf_size,
+ PCI_DMA_FROMDEVICE);
+
+ if (eth) {
+ if (unlikely(fl->credits <
+ SGE_RX_DROP_THRES))
+ goto eth_recycle;
+
+ skb = alloc_skb(SKB_DATA_SIZE,
+ GFP_ATOMIC);
+ if (unlikely(!skb)) {
+eth_recycle:
+ q->rx_drops++;
+ recycle_rx_buf(adap, fl,
+ fl->cidx);
+ goto eth_done;
+ }
+ } else {
+ skb = alloc_skb(SKB_DATA_SIZE,
+ GFP_ATOMIC);
+ if (unlikely(!skb))
+ goto no_mem;
+ }
+
+ skb_data_init(skb, p, G_RSPD_LEN(len));
+eth_done:
+ fl->credits--;
+ q->eth_pkts++;
+ } else {
+ fl->credits--;
+ skb = get_packet(adap, fl, G_RSPD_LEN(len),
+ eth ? SGE_RX_DROP_THRES : 0);
+ }
- fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0];
- fl->credits--;
- skb = get_packet(adap, fl, G_RSPD_LEN(len),
- eth ? SGE_RX_DROP_THRES : 0);
- if (!skb)
- q->rx_drops++;
- else if (r->rss_hdr.opcode == CPL_TRACE_PKT)
- __skb_pull(skb, 2);
- ethpad = 2;
if (++fl->cidx == fl->size)
fl->cidx = 0;
} else
@@ -1829,18 +2011,23 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs,
q->credits = 0;
}
- if (likely(skb != NULL)) {
+ if (skb) {
+ /* Preserve the RSS info in csum & priority */
+ skb->csum = rss_hi;
+ skb->priority = rss_lo;
+
if (eth)
rx_eth(adap, q, skb, ethpad);
else {
- /* Preserve the RSS info in csum & priority */
- skb->csum = rss_hi;
- skb->priority = rss_lo;
- ngathered = rx_offload(&adap->tdev, q, skb,
- offload_skbs, ngathered);
+ if (unlikely(r->rss_hdr.opcode ==
+ CPL_TRACE_PKT))
+ __skb_pull(skb, ethpad);
+
+ ngathered = rx_offload(&adap->tdev, q,
+ skb, offload_skbs,
+ ngathered);
}
}
-
--budget_left;
}
@@ -2320,10 +2507,23 @@ static void sge_timer_cb(unsigned long data)
&adap->sge.qs[0].rspq.lock;
if (spin_trylock_irq(lock)) {
if (!napi_is_scheduled(qs->netdev)) {
+ u32 status = t3_read_reg(adap, A_SG_RSPQ_FL_STATUS);
+
if (qs->fl[0].credits < qs->fl[0].size)
__refill_fl(adap, &qs->fl[0]);
if (qs->fl[1].credits < qs->fl[1].size)
__refill_fl(adap, &qs->fl[1]);
+
+ if (status & (1 << qs->rspq.cntxt_id)) {
+ qs->rspq.starved++;
+ if (qs->rspq.credits) {
+ refill_rspq(adap, &qs->rspq, 1);
+ qs->rspq.credits--;
+ qs->rspq.restarted++;
+ t3_write_reg(adap, A_SG_RSPQ_FL_STATUS,
+ 1 << qs->rspq.cntxt_id);
+ }
+ }
}
spin_unlock_irq(lock);
}
@@ -2432,13 +2632,21 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3);
if (ntxq == 1) {
+#ifdef USE_RX_PAGE
+ q->fl[0].buf_size = RX_PAGE_SIZE;
+#else
q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + 2 +
sizeof(struct cpl_rx_pkt);
+#endif
q->fl[1].buf_size = MAX_FRAME_SIZE + 2 +
sizeof(struct cpl_rx_pkt);
} else {
+#ifdef USE_RX_PAGE
+ q->fl[0].buf_size = RX_PAGE_SIZE;
+#else
q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE +
sizeof(struct cpl_rx_data);
+#endif
q->fl[1].buf_size = (16 * 1024) -
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
}
@@ -2632,7 +2840,7 @@ void __devinit t3_sge_prep(struct adapter *adap, struct sge_params *p)
q->polling = adap->params.rev > 0;
q->coalesce_usecs = 5;
q->rspq_size = 1024;
- q->fl_size = 4096;
+ q->fl_size = 1024;
q->jumbo_size = 512;
q->txq_size[TXQ_ETH] = 1024;
q->txq_size[TXQ_OFLD] = 1024;
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index 365a7f5b1f9..eaa7a2e89a3 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -884,11 +884,13 @@ int t3_check_fw_version(struct adapter *adapter)
major = G_FW_VERSION_MAJOR(vers);
minor = G_FW_VERSION_MINOR(vers);
- if (type == FW_VERSION_T3 && major == 3 && minor == 1)
+ if (type == FW_VERSION_T3 && major == FW_VERSION_MAJOR &&
+ minor == FW_VERSION_MINOR)
return 0;
CH_ERR(adapter, "found wrong FW version(%u.%u), "
- "driver needs version 3.1\n", major, minor);
+ "driver needs version %u.%u\n", major, minor,
+ FW_VERSION_MAJOR, FW_VERSION_MINOR);
return -EINVAL;
}
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index 2b67dd523cc..82278f85025 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -35,5 +35,7 @@
#define DRV_DESC "Chelsio T3 Network Driver"
#define DRV_NAME "cxgb3"
/* Driver version */
-#define DRV_VERSION "1.0"
+#define DRV_VERSION "1.0-ko"
+#define FW_VERSION_MAJOR 3
+#define FW_VERSION_MINOR 2
#endif /* __CHELSIO_VERSION_H */
diff --git a/drivers/net/de600.c b/drivers/net/de600.c
index 8396e411f1c..e547ce14eef 100644
--- a/drivers/net/de600.c
+++ b/drivers/net/de600.c
@@ -38,12 +38,6 @@ static const char version[] = "de600.c: $Revision: 1.41-2.5 $, Bjorn Ekwall (bj
/* Add more time here if your adapter won't work OK: */
#define DE600_SLOW_DOWN udelay(delay_time)
- /*
- * If you still have trouble reading/writing to the adapter,
- * modify the following "#define": (see <asm/io.h> for more info)
-#define REALLY_SLOW_IO
- */
-
/* use 0 for production, 1 for verification, >2 for debug */
#ifdef DE600_DEBUG
#define PRINTK(x) if (de600_debug >= 2) printk x
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index a71023741c3..1d08e937af8 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -376,7 +376,7 @@ e1000_update_mng_vlan(struct e1000_adapter *adapter)
uint16_t vid = adapter->hw.mng_cookie.vlan_id;
uint16_t old_vid = adapter->mng_vlan_id;
if (adapter->vlgrp) {
- if (!adapter->vlgrp->vlan_devices[vid]) {
+ if (!vlan_group_get_device(adapter->vlgrp, vid)) {
if (adapter->hw.mng_cookie.status &
E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) {
e1000_vlan_rx_add_vid(netdev, vid);
@@ -386,7 +386,7 @@ e1000_update_mng_vlan(struct e1000_adapter *adapter)
if ((old_vid != (uint16_t)E1000_MNG_VLAN_NONE) &&
(vid != old_vid) &&
- !adapter->vlgrp->vlan_devices[old_vid])
+ !vlan_group_get_device(adapter->vlgrp, old_vid))
e1000_vlan_rx_kill_vid(netdev, old_vid);
} else
adapter->mng_vlan_id = vid;
@@ -1417,6 +1417,10 @@ e1000_open(struct net_device *netdev)
if ((err = e1000_setup_all_rx_resources(adapter)))
goto err_setup_rx;
+ err = e1000_request_irq(adapter);
+ if (err)
+ goto err_req_irq;
+
e1000_power_up_phy(adapter);
if ((err = e1000_up(adapter)))
@@ -1427,10 +1431,6 @@ e1000_open(struct net_device *netdev)
e1000_update_mng_vlan(adapter);
}
- err = e1000_request_irq(adapter);
- if (err)
- goto err_req_irq;
-
/* If AMT is enabled, let the firmware know that the network
* interface is now open */
if (adapter->hw.mac_type == e1000_82573 &&
@@ -1439,10 +1439,10 @@ e1000_open(struct net_device *netdev)
return E1000_SUCCESS;
-err_req_irq:
- e1000_down(adapter);
err_up:
e1000_power_down_phy(adapter);
+ e1000_free_irq(adapter);
+err_req_irq:
e1000_free_all_rx_resources(adapter);
err_setup_rx:
e1000_free_all_tx_resources(adapter);
@@ -1482,7 +1482,7 @@ e1000_close(struct net_device *netdev)
if ((adapter->hw.mng_cookie.status &
E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) &&
!(adapter->vlgrp &&
- adapter->vlgrp->vlan_devices[adapter->mng_vlan_id])) {
+ vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id))) {
e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
}
@@ -4998,10 +4998,7 @@ e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
uint32_t vfta, index;
e1000_irq_disable(adapter);
-
- if (adapter->vlgrp)
- adapter->vlgrp->vlan_devices[vid] = NULL;
-
+ vlan_group_set_device(adapter->vlgrp, vid, NULL);
e1000_irq_enable(adapter);
if ((adapter->hw.mng_cookie.status &
@@ -5027,7 +5024,7 @@ e1000_restore_vlan(struct e1000_adapter *adapter)
if (adapter->vlgrp) {
uint16_t vid;
for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
- if (!adapter->vlgrp->vlan_devices[vid])
+ if (!vlan_group_get_device(adapter->vlgrp, vid))
continue;
e1000_vlan_rx_add_vid(adapter->netdev, vid);
}
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 88ad1c8bcee..0e4042bc0a4 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -1939,8 +1939,7 @@ static void ehea_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
int index;
u64 hret;
- if (port->vgrp)
- port->vgrp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(port->vgrp, vid, NULL);
cb1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!cb1) {
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index a363148d019..46e1697d9cf 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -839,7 +839,7 @@ enum {
NV_MSIX_INT_DISABLED,
NV_MSIX_INT_ENABLED
};
-static int msix = NV_MSIX_INT_ENABLED;
+static int msix = NV_MSIX_INT_DISABLED;
/*
* DMA 64bit
@@ -3104,13 +3104,17 @@ static int nv_napi_poll(struct net_device *dev, int *budget)
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
unsigned long flags;
+ int retcode;
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
pkts = nv_rx_process(dev, limit);
- else
+ retcode = nv_alloc_rx(dev);
+ } else {
pkts = nv_rx_process_optimized(dev, limit);
+ retcode = nv_alloc_rx_optimized(dev);
+ }
- if (nv_alloc_rx(dev)) {
+ if (retcode) {
spin_lock_irqsave(&np->lock, flags);
if (!np->in_shutdown)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
@@ -5370,19 +5374,19 @@ static struct pci_device_id pci_tbl[] = {
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24),
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 1f83988a6a6..d981d4c41dd 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -1132,8 +1132,7 @@ static void gfar_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
spin_lock_irqsave(&priv->rxlock, flags);
- if (priv->vlgrp)
- priv->vlgrp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(priv->vlgrp, vid, NULL);
spin_unlock_irqrestore(&priv->rxlock, flags);
}
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 0c368288934..afc2ec72529 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -2213,8 +2213,7 @@ ixgb_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
ixgb_irq_disable(adapter);
- if(adapter->vlgrp)
- adapter->vlgrp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(adapter->vlgrp, vid, NULL);
ixgb_irq_enable(adapter);
@@ -2234,7 +2233,7 @@ ixgb_restore_vlan(struct ixgb_adapter *adapter)
if(adapter->vlgrp) {
uint16_t vid;
for(vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
- if(!adapter->vlgrp->vlan_devices[vid])
+ if(!vlan_group_get_device(adapter->vlgrp, vid))
continue;
ixgb_vlan_rx_add_vid(adapter->netdev, vid);
}
diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c
index ea392f2a5aa..452863d5d49 100644
--- a/drivers/net/lasi_82596.c
+++ b/drivers/net/lasi_82596.c
@@ -384,7 +384,7 @@ struct i596_private {
struct device *dev;
};
-static char init_setup[] =
+static const char init_setup[] =
{
0x8E, /* length, prefetch on */
0xC8, /* fifo to 8, monitor off */
@@ -683,7 +683,7 @@ static int init_i596_mem(struct net_device *dev)
enable_irq(dev->irq); /* enable IRQs from LAN */
DEB(DEB_INIT, printk("%s: queuing CmdConfigure\n", dev->name));
- memcpy(lp->cf_cmd.i596_config, init_setup, 14);
+ memcpy(lp->cf_cmd.i596_config, init_setup, sizeof(init_setup));
lp->cf_cmd.cmd.command = CmdConfigure;
CHECK_WBACK(lp, &(lp->cf_cmd), sizeof(struct cf_cmd));
i596_add_cmd(dev, &lp->cf_cmd.cmd);
@@ -1156,32 +1156,12 @@ static int __devinit i82596_probe(struct net_device *dev,
dma_addr_t dma_addr;
/* This lot is ensure things have been cache line aligned. */
- if (sizeof(struct i596_rfd) != 32) {
- printk("82596: sizeof(struct i596_rfd) = %d\n",
- (int)sizeof(struct i596_rfd));
- return -ENODEV;
- }
- if ((sizeof(struct i596_rbd) % 32) != 0) {
- printk("82596: sizeof(struct i596_rbd) = %d\n",
- (int)sizeof(struct i596_rbd));
- return -ENODEV;
- }
- if ((sizeof(struct tx_cmd) % 32) != 0) {
- printk("82596: sizeof(struct tx_cmd) = %d\n",
- (int)sizeof(struct tx_cmd));
- return -ENODEV;
- }
- if (sizeof(struct i596_tbd) != 32) {
- printk("82596: sizeof(struct i596_tbd) = %d\n",
- (int)sizeof(struct i596_tbd));
- return -ENODEV;
- }
+ BUILD_BUG_ON(sizeof(struct i596_rfd) != 32);
+ BUILD_BUG_ON(sizeof(struct i596_rbd) & 31);
+ BUILD_BUG_ON(sizeof(struct tx_cmd) & 31);
+ BUILD_BUG_ON(sizeof(struct i596_tbd) != 32);
#ifndef __LP64__
- if (sizeof(struct i596_private) > 4096) {
- printk("82596: sizeof(struct i596_private) = %d\n",
- (int)sizeof(struct i596_private));
- return -ENODEV;
- }
+ BUILD_BUG_ON(sizeof(struct i596_private) > 4096);
#endif
if (!dev->base_addr || !dev->irq)
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index d98e53efa2e..1ee27c360a4 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -147,13 +147,13 @@ static void mv643xx_eth_rx_refill_descs(struct net_device *dev)
int unaligned;
while (mp->rx_desc_count < mp->rx_ring_size) {
- skb = dev_alloc_skb(ETH_RX_SKB_SIZE + ETH_DMA_ALIGN);
+ skb = dev_alloc_skb(ETH_RX_SKB_SIZE + dma_get_cache_alignment());
if (!skb)
break;
mp->rx_desc_count++;
- unaligned = (u32)skb->data & (ETH_DMA_ALIGN - 1);
+ unaligned = (u32)skb->data & (dma_get_cache_alignment() - 1);
if (unaligned)
- skb_reserve(skb, ETH_DMA_ALIGN - unaligned);
+ skb_reserve(skb, dma_get_cache_alignment() - unaligned);
pkt_info.cmd_sts = ETH_RX_ENABLE_INTERRUPT;
pkt_info.byte_cnt = ETH_RX_SKB_SIZE;
pkt_info.buf_ptr = dma_map_single(NULL, skb->data,
@@ -787,6 +787,12 @@ static int mv643xx_eth_open(struct net_device *dev)
unsigned int size;
int err;
+ /* Clear any pending ethernet port interrupts */
+ mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
+ mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
+ /* wait for previous write to complete */
+ mv_read (MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num));
+
err = request_irq(dev->irq, mv643xx_eth_int_handler,
IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev);
if (err) {
@@ -875,10 +881,6 @@ static int mv643xx_eth_open(struct net_device *dev)
mv643xx_eth_rx_refill_descs(dev); /* Fill RX ring with skb's */
- /* Clear any pending ethernet port interrupts */
- mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
- mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
-
eth_port_start(dev);
/* Interrupt Coalescing */
@@ -1309,7 +1311,7 @@ static void mv643xx_init_ethtool_cmd(struct net_device *dev, int phy_address,
static int mv643xx_eth_probe(struct platform_device *pdev)
{
struct mv643xx_eth_platform_data *pd;
- int port_num = pdev->id;
+ int port_num;
struct mv643xx_private *mp;
struct net_device *dev;
u8 *p;
@@ -1319,6 +1321,12 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
int duplex = DUPLEX_HALF;
int speed = 0; /* default to auto-negotiation */
+ pd = pdev->dev.platform_data;
+ if (pd == NULL) {
+ printk(KERN_ERR "No mv643xx_eth_platform_data\n");
+ return -ENODEV;
+ }
+
dev = alloc_etherdev(sizeof(struct mv643xx_private));
if (!dev)
return -ENOMEM;
@@ -1331,8 +1339,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
BUG_ON(!res);
dev->irq = res->start;
- mp->port_num = port_num;
-
dev->open = mv643xx_eth_open;
dev->stop = mv643xx_eth_stop;
dev->hard_start_xmit = mv643xx_eth_start_xmit;
@@ -1373,39 +1379,40 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
spin_lock_init(&mp->lock);
+ port_num = pd->port_number;
+
/* set default config values */
eth_port_uc_addr_get(dev, dev->dev_addr);
mp->rx_ring_size = MV643XX_ETH_PORT_DEFAULT_RECEIVE_QUEUE_SIZE;
mp->tx_ring_size = MV643XX_ETH_PORT_DEFAULT_TRANSMIT_QUEUE_SIZE;
- pd = pdev->dev.platform_data;
- if (pd) {
- if (pd->mac_addr)
- memcpy(dev->dev_addr, pd->mac_addr, 6);
-
- if (pd->phy_addr || pd->force_phy_addr)
- ethernet_phy_set(port_num, pd->phy_addr);
+ if (is_valid_ether_addr(pd->mac_addr))
+ memcpy(dev->dev_addr, pd->mac_addr, 6);
- if (pd->rx_queue_size)
- mp->rx_ring_size = pd->rx_queue_size;
+ if (pd->phy_addr || pd->force_phy_addr)
+ ethernet_phy_set(port_num, pd->phy_addr);
- if (pd->tx_queue_size)
- mp->tx_ring_size = pd->tx_queue_size;
+ if (pd->rx_queue_size)
+ mp->rx_ring_size = pd->rx_queue_size;
- if (pd->tx_sram_size) {
- mp->tx_sram_size = pd->tx_sram_size;
- mp->tx_sram_addr = pd->tx_sram_addr;
- }
+ if (pd->tx_queue_size)
+ mp->tx_ring_size = pd->tx_queue_size;
- if (pd->rx_sram_size) {
- mp->rx_sram_size = pd->rx_sram_size;
- mp->rx_sram_addr = pd->rx_sram_addr;
- }
+ if (pd->tx_sram_size) {
+ mp->tx_sram_size = pd->tx_sram_size;
+ mp->tx_sram_addr = pd->tx_sram_addr;
+ }
- duplex = pd->duplex;
- speed = pd->speed;
+ if (pd->rx_sram_size) {
+ mp->rx_sram_size = pd->rx_sram_size;
+ mp->rx_sram_addr = pd->rx_sram_addr;
}
+ duplex = pd->duplex;
+ speed = pd->speed;
+
+ mp->port_num = port_num;
+
/* Hook up MII support for ethtool */
mp->mii.dev = dev;
mp->mii.mdio_read = mv643xx_mdio_read;
diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h
index 33c5fafdbbd..7d4e90cf49e 100644
--- a/drivers/net/mv643xx_eth.h
+++ b/drivers/net/mv643xx_eth.h
@@ -9,6 +9,8 @@
#include <linux/mv643xx.h>
+#include <asm/dma-mapping.h>
+
/* Checksum offload for Tx works for most packets, but
* fails if previous packet sent did not use hw csum
*/
@@ -42,23 +44,12 @@
#define MAX_DESCS_PER_SKB 1
#endif
-/*
- * The MV643XX HW requires 8-byte alignment. However, when I/O
- * is non-cache-coherent, we need to ensure that the I/O buffers
- * we use don't share cache lines with other data.
- */
-#if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_NOT_COHERENT_CACHE)
-#define ETH_DMA_ALIGN L1_CACHE_BYTES
-#else
-#define ETH_DMA_ALIGN 8
-#endif
-
#define ETH_VLAN_HLEN 4
#define ETH_FCS_LEN 4
#define ETH_HW_IP_ALIGN 2 /* hw aligns IP header */
#define ETH_WRAPPER_LEN (ETH_HW_IP_ALIGN + ETH_HLEN + \
ETH_VLAN_HLEN + ETH_FCS_LEN)
-#define ETH_RX_SKB_SIZE (dev->mtu + ETH_WRAPPER_LEN + ETH_DMA_ALIGN)
+#define ETH_RX_SKB_SIZE (dev->mtu + ETH_WRAPPER_LEN + dma_get_cache_alignment())
#define ETH_RX_QUEUES_ENABLED (1 << 0) /* use only Q0 for receive */
#define ETH_TX_QUEUES_ENABLED (1 << 0) /* use only Q0 for transmit */
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 030924fb1ab..ac02b3b60f9 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -1,7 +1,7 @@
/*************************************************************************
* myri10ge.c: Myricom Myri-10G Ethernet driver.
*
- * Copyright (C) 2005, 2006 Myricom, Inc.
+ * Copyright (C) 2005 - 2007 Myricom, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -16,17 +16,17 @@
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*
*
* If the eeprom on your board is not recent enough, you will need to get a
@@ -181,6 +181,7 @@ struct myri10ge_priv {
int intr_coal_delay;
__be32 __iomem *intr_coal_delay_ptr;
int mtrr;
+ int wc_enabled;
int wake_queue;
int stop_queue;
int down_cnt;
@@ -195,6 +196,10 @@ struct myri10ge_priv {
char *fw_name;
char eeprom_strings[MYRI10GE_EEPROM_STRINGS_SIZE];
char fw_version[128];
+ int fw_ver_major;
+ int fw_ver_minor;
+ int fw_ver_tiny;
+ int adopted_rx_filter_bug;
u8 mac_addr[6]; /* eeprom mac address */
unsigned long serial_number;
int vendor_specific_offset;
@@ -447,7 +452,6 @@ myri10ge_validate_firmware(struct myri10ge_priv *mgp,
struct mcp_gen_header *hdr)
{
struct device *dev = &mgp->pdev->dev;
- int major, minor;
/* check firmware type */
if (ntohl(hdr->mcp_type) != MCP_TYPE_ETH) {
@@ -458,9 +462,11 @@ myri10ge_validate_firmware(struct myri10ge_priv *mgp,
/* save firmware version for ethtool */
strncpy(mgp->fw_version, hdr->version, sizeof(mgp->fw_version));
- sscanf(mgp->fw_version, "%d.%d", &major, &minor);
+ sscanf(mgp->fw_version, "%d.%d.%d", &mgp->fw_ver_major,
+ &mgp->fw_ver_minor, &mgp->fw_ver_tiny);
- if (!(major == MXGEFW_VERSION_MAJOR && minor == MXGEFW_VERSION_MINOR)) {
+ if (!(mgp->fw_ver_major == MXGEFW_VERSION_MAJOR
+ && mgp->fw_ver_minor == MXGEFW_VERSION_MINOR)) {
dev_err(dev, "Found firmware version %s\n", mgp->fw_version);
dev_err(dev, "Driver needs %d.%d\n", MXGEFW_VERSION_MAJOR,
MXGEFW_VERSION_MINOR);
@@ -561,6 +567,18 @@ static int myri10ge_adopt_running_firmware(struct myri10ge_priv *mgp)
memcpy_fromio(hdr, mgp->sram + hdr_offset, bytes);
status = myri10ge_validate_firmware(mgp, hdr);
kfree(hdr);
+
+ /* check to see if adopted firmware has bug where adopting
+ * it will cause broadcasts to be filtered unless the NIC
+ * is kept in ALLMULTI mode */
+ if (mgp->fw_ver_major == 1 && mgp->fw_ver_minor == 4 &&
+ mgp->fw_ver_tiny >= 4 && mgp->fw_ver_tiny <= 11) {
+ mgp->adopted_rx_filter_bug = 1;
+ dev_warn(dev, "Adopting fw %d.%d.%d: "
+ "working around rx filter bug\n",
+ mgp->fw_ver_major, mgp->fw_ver_minor,
+ mgp->fw_ver_tiny);
+ }
return status;
}
@@ -700,6 +718,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
int status;
size_t bytes;
u32 len;
+ struct page *dmatest_page;
+ dma_addr_t dmatest_bus;
/* try to send a reset command to the card to see if it
* is alive */
@@ -709,6 +729,11 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
dev_err(&mgp->pdev->dev, "failed reset\n");
return -ENXIO;
}
+ dmatest_page = alloc_page(GFP_KERNEL);
+ if (!dmatest_page)
+ return -ENOMEM;
+ dmatest_bus = pci_map_page(mgp->pdev, dmatest_page, 0, PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
/* Now exchange information about interrupts */
@@ -747,8 +772,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
len = mgp->tx.boundary;
- cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus);
- cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus);
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
cmd.data2 = len * 0x10000;
status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0);
if (status == 0)
@@ -757,8 +782,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
else
dev_warn(&mgp->pdev->dev, "DMA read benchmark failed: %d\n",
status);
- cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus);
- cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus);
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
cmd.data2 = len * 0x1;
status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0);
if (status == 0)
@@ -768,8 +793,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
dev_warn(&mgp->pdev->dev, "DMA write benchmark failed: %d\n",
status);
- cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus);
- cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus);
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
cmd.data2 = len * 0x10001;
status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0);
if (status == 0)
@@ -779,6 +804,9 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
dev_warn(&mgp->pdev->dev,
"DMA read/write benchmark failed: %d\n", status);
+ pci_unmap_page(mgp->pdev, dmatest_bus, PAGE_SIZE, DMA_BIDIRECTIONAL);
+ put_page(dmatest_page);
+
memset(mgp->rx_done.entry, 0, bytes);
/* reset mcp/driver shared state back to 0 */
@@ -794,6 +822,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr);
myri10ge_change_promisc(mgp, 0, 0);
myri10ge_change_pause(mgp, mgp->pause);
+ if (mgp->adopted_rx_filter_bug)
+ (void)myri10ge_send_cmd(mgp, MXGEFW_ENABLE_ALLMULTI, &cmd, 1);
return status;
}
@@ -1356,7 +1386,7 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
data[i] = ((unsigned long *)&mgp->stats)[i];
data[i++] = (unsigned int)mgp->tx.boundary;
- data[i++] = (unsigned int)(mgp->mtrr >= 0);
+ data[i++] = (unsigned int)mgp->wc_enabled;
data[i++] = (unsigned int)mgp->pdev->irq;
data[i++] = (unsigned int)mgp->msi_enabled;
data[i++] = (unsigned int)mgp->read_dma;
@@ -1437,6 +1467,8 @@ static int myri10ge_allocate_rings(struct net_device *dev)
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd, 0);
tx_ring_size = cmd.data0;
status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd, 0);
+ if (status != 0)
+ return status;
rx_ring_size = cmd.data0;
tx_ring_entries = tx_ring_size / sizeof(struct mcp_kreq_ether_send);
@@ -1444,6 +1476,8 @@ static int myri10ge_allocate_rings(struct net_device *dev)
mgp->tx.mask = tx_ring_entries - 1;
mgp->rx_small.mask = mgp->rx_big.mask = rx_ring_entries - 1;
+ status = -ENOMEM;
+
/* allocate the host shadow rings */
bytes = 8 + (MYRI10GE_MAX_SEND_DESC_TSO + 4)
@@ -1716,7 +1750,7 @@ static int myri10ge_open(struct net_device *dev)
goto abort_with_irq;
}
- if (myri10ge_wcfifo && mgp->mtrr >= 0) {
+ if (myri10ge_wcfifo && mgp->wc_enabled) {
mgp->tx.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_SEND_4;
mgp->rx_small.wc_fifo =
(u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_SMALL;
@@ -2239,7 +2273,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev)
myri10ge_change_promisc(mgp, dev->flags & IFF_PROMISC, 1);
/* This firmware is known to not support multicast */
- if (!mgp->fw_multicast_support)
+ if (!mgp->fw_multicast_support || mgp->adopted_rx_filter_bug)
return;
/* Disable multicast filtering */
@@ -2491,6 +2525,12 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
bridge->vendor, bridge->device);
mgp->tx.boundary = 4096;
mgp->fw_name = myri10ge_fw_aligned;
+ } else if (bridge &&
+ bridge->vendor == PCI_VENDOR_ID_SGI &&
+ bridge->device == 0x4002 /* TIOCE pcie-port */ ) {
+ /* this pcie bridge does not support 4K rdma request */
+ mgp->tx.boundary = 2048;
+ mgp->fw_name = myri10ge_fw_aligned;
}
} else {
if (myri10ge_force_firmware == 1) {
@@ -2811,9 +2851,12 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
mgp->board_span = pci_resource_len(pdev, 0);
mgp->iomem_base = pci_resource_start(pdev, 0);
mgp->mtrr = -1;
+ mgp->wc_enabled = 0;
#ifdef CONFIG_MTRR
mgp->mtrr = mtrr_add(mgp->iomem_base, mgp->board_span,
MTRR_TYPE_WRCOMB, 1);
+ if (mgp->mtrr >= 0)
+ mgp->wc_enabled = 1;
#endif
/* Hack. need to get rid of these magic numbers */
mgp->sram_size =
@@ -2908,7 +2951,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n",
(mgp->msi_enabled ? "MSI" : "xPIC"),
netdev->irq, mgp->tx.boundary, mgp->fw_name,
- (mgp->mtrr >= 0 ? "Enabled" : "Disabled"));
+ (mgp->wc_enabled ? "Enabled" : "Disabled"));
return 0;
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index adf29dd6679..c6172a77a6d 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -260,7 +260,7 @@ static const struct {
static const struct pci_device_id natsemi_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_NS, 0x0020, 0x12d9, 0x000c, 0, 0, 0 },
- { PCI_VENDOR_ID_NS, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_NS, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
{ } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, natsemi_pci_tbl);
@@ -2024,6 +2024,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
struct netdev_private *np = netdev_priv(dev);
void __iomem * ioaddr = ns_ioaddr(dev);
unsigned entry;
+ unsigned long flags;
/* Note: Ordering is important here, set the field with the
"ownership" bit last, and only then increment cur_tx. */
@@ -2037,7 +2038,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
np->tx_ring[entry].addr = cpu_to_le32(np->tx_dma[entry]);
- spin_lock_irq(&np->lock);
+ spin_lock_irqsave(&np->lock, flags);
if (!np->hands_off) {
np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | skb->len);
@@ -2056,7 +2057,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb_irq(skb);
np->stats.tx_dropped++;
}
- spin_unlock_irq(&np->lock);
+ spin_unlock_irqrestore(&np->lock, flags);
dev->trans_start = jiffies;
@@ -2222,6 +2223,8 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do)
pkt_len = (desc_status & DescSizeMask) - 4;
if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){
if (desc_status & DescMore) {
+ unsigned long flags;
+
if (netif_msg_rx_err(np))
printk(KERN_WARNING
"%s: Oversized(?) Ethernet "
@@ -2236,12 +2239,12 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do)
* reset procedure documented in
* AN-1287. */
- spin_lock_irq(&np->lock);
+ spin_lock_irqsave(&np->lock, flags);
reset_rx(dev);
reinit_rx(dev);
writel(np->ring_dma, ioaddr + RxRingPtr);
check_link(dev);
- spin_unlock_irq(&np->lock);
+ spin_unlock_irqrestore(&np->lock, flags);
/* We'll enable RX on exit from this
* function. */
@@ -2396,8 +2399,19 @@ static struct net_device_stats *get_stats(struct net_device *dev)
#ifdef CONFIG_NET_POLL_CONTROLLER
static void natsemi_poll_controller(struct net_device *dev)
{
+ struct netdev_private *np = netdev_priv(dev);
+
disable_irq(dev->irq);
- intr_handler(dev->irq, dev);
+
+ /*
+ * A real interrupt might have already reached us at this point
+ * but NAPI might still haven't called us back. As the interrupt
+ * status register is cleared by reading, we should prevent an
+ * interrupt loss in this case...
+ */
+ if (!np->intr_status)
+ intr_handler(dev->irq, dev);
+
enable_irq(dev->irq);
}
#endif
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index 2807ef400fb..81742e4e561 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -72,6 +72,8 @@
#define FLASH_SECTOR_SIZE (64 * 1024)
#define FLASH_TOTAL_SIZE (NUM_FLASH_SECTORS * FLASH_SECTOR_SIZE)
+#define PHAN_VENDOR_ID 0x4040
+
#define RCV_DESC_RINGSIZE \
(sizeof(struct rcv_desc) * adapter->max_rx_desc_count)
#define STATUS_DESC_RINGSIZE \
@@ -82,7 +84,7 @@
(sizeof(struct netxen_cmd_buffer) * adapter->max_tx_desc_count)
#define RCV_BUFFSIZE \
(sizeof(struct netxen_rx_buffer) * rcv_desc->max_rx_desc_count)
-#define find_diff_among(a,b,range) ((a)<(b)?((b)-(a)):((b)+(range)-(a)))
+#define find_diff_among(a,b,range) ((a)<=(b)?((b)-(a)):((b)+(range)-(a)))
#define NETXEN_NETDEV_STATUS 0x1
#define NETXEN_RCV_PRODUCER_OFFSET 0
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index 6252e9a8727..986ef98db22 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -82,8 +82,7 @@ static const struct netxen_nic_stats netxen_nic_gstrings_stats[] = {
#define NETXEN_NIC_STATS_LEN ARRAY_SIZE(netxen_nic_gstrings_stats)
static const char netxen_nic_gstrings_test[][ETH_GSTRING_LEN] = {
- "Register_Test_offline", "EEPROM_Test_offline",
- "Interrupt_Test_offline", "Loopback_Test_offline",
+ "Register_Test_on_offline",
"Link_Test_on_offline"
};
@@ -394,19 +393,12 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
}
}
-static void
-netxen_nic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
- wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
- /* options can be added depending upon the mode */
- wol->wolopts = 0;
-}
-
static u32 netxen_nic_test_link(struct net_device *dev)
{
struct netxen_port *port = netdev_priv(dev);
struct netxen_adapter *adapter = port->adapter;
__u32 status;
+ int val;
/* read which mode */
if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
@@ -415,11 +407,13 @@ static u32 netxen_nic_test_link(struct net_device *dev)
NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
&status) != 0)
return -EIO;
- else
- return (netxen_get_phy_link(status));
+ else {
+ val = netxen_get_phy_link(status);
+ return !val;
+ }
} else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
- int val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
- return val == XG_LINK_UP;
+ val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
+ return (val == XG_LINK_UP) ? 0 : 1;
}
return -EIO;
}
@@ -606,100 +600,21 @@ netxen_nic_set_pauseparam(struct net_device *dev,
static int netxen_nic_reg_test(struct net_device *dev)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
- u32 data_read, data_written, save;
- __u32 mode;
-
- /*
- * first test the "Read Only" registers by writing which mode
- */
- netxen_nic_read_w0(adapter, NETXEN_NIU_MODE, &mode);
- if (netxen_get_niu_enable_ge(mode)) { /* GB Mode */
- netxen_nic_read_w0(adapter,
- NETXEN_NIU_GB_MII_MGMT_STATUS(port->portnum),
- &data_read);
-
- save = data_read;
- if (data_read)
- data_written = data_read & NETXEN_NIC_INVALID_DATA;
- else
- data_written = NETXEN_NIC_INVALID_DATA;
- netxen_nic_write_w0(adapter,
- NETXEN_NIU_GB_MII_MGMT_STATUS(port->
- portnum),
- data_written);
- netxen_nic_read_w0(adapter,
- NETXEN_NIU_GB_MII_MGMT_STATUS(port->portnum),
- &data_read);
-
- if (data_written == data_read) {
- netxen_nic_write_w0(adapter,
- NETXEN_NIU_GB_MII_MGMT_STATUS(port->
- portnum),
- save);
-
- return 0;
- }
-
- /* netxen_niu_gb_mii_mgmt_indicators is read only */
- netxen_nic_read_w0(adapter,
- NETXEN_NIU_GB_MII_MGMT_INDICATE(port->
- portnum),
- &data_read);
-
- save = data_read;
- if (data_read)
- data_written = data_read & NETXEN_NIC_INVALID_DATA;
- else
- data_written = NETXEN_NIC_INVALID_DATA;
- netxen_nic_write_w0(adapter,
- NETXEN_NIU_GB_MII_MGMT_INDICATE(port->
- portnum),
- data_written);
-
- netxen_nic_read_w0(adapter,
- NETXEN_NIU_GB_MII_MGMT_INDICATE(port->
- portnum),
- &data_read);
-
- if (data_written == data_read) {
- netxen_nic_write_w0(adapter,
- NETXEN_NIU_GB_MII_MGMT_INDICATE
- (port->portnum), save);
- return 0;
- }
+ struct netxen_adapter *adapter = netdev_priv(dev);
+ u32 data_read, data_written;
- /* netxen_niu_gb_interface_status is read only */
- netxen_nic_read_w0(adapter,
- NETXEN_NIU_GB_INTERFACE_STATUS(port->
- portnum),
- &data_read);
+ netxen_nic_read_w0(adapter, NETXEN_PCIX_PH_REG(0), &data_read);
+ if ((data_read & 0xffff) != PHAN_VENDOR_ID)
+ return 1;
- save = data_read;
- if (data_read)
- data_written = data_read & NETXEN_NIC_INVALID_DATA;
- else
- data_written = NETXEN_NIC_INVALID_DATA;
- netxen_nic_write_w0(adapter,
- NETXEN_NIU_GB_INTERFACE_STATUS(port->
- portnum),
- data_written);
+ data_written = (u32)0xa5a5a5a5;
- netxen_nic_read_w0(adapter,
- NETXEN_NIU_GB_INTERFACE_STATUS(port->
- portnum),
- &data_read);
+ netxen_nic_reg_write(adapter, CRB_SCRATCHPAD_TEST, data_written);
+ data_read = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_SCRATCHPAD_TEST));
+ if (data_written != data_read)
+ return 1;
- if (data_written == data_read) {
- netxen_nic_write_w0(adapter,
- NETXEN_NIU_GB_INTERFACE_STATUS
- (port->portnum), save);
-
- return 0;
- }
- } /* GB Mode */
- return 1;
+ return 0;
}
static int netxen_nic_diag_test_count(struct net_device *dev)
@@ -713,26 +628,20 @@ netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
{
if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* offline tests */
/* link test */
- if (!(data[4] = (u64) netxen_nic_test_link(dev)))
+ if ((data[1] = (u64) netxen_nic_test_link(dev)))
eth_test->flags |= ETH_TEST_FL_FAILED;
- if (netif_running(dev))
- dev->stop(dev);
-
/* register tests */
- if (!(data[0] = netxen_nic_reg_test(dev)))
+ if ((data[0] = netxen_nic_reg_test(dev)))
eth_test->flags |= ETH_TEST_FL_FAILED;
- /* other tests pass as of now */
- data[1] = data[2] = data[3] = 1;
- if (netif_running(dev))
- dev->open(dev);
} else { /* online tests */
- /* link test */
- if (!(data[4] = (u64) netxen_nic_test_link(dev)))
+ /* register tests */
+ if((data[0] = netxen_nic_reg_test(dev)))
eth_test->flags |= ETH_TEST_FL_FAILED;
- /* other tests pass by default */
- data[0] = data[1] = data[2] = data[3] = 1;
+ /* link test */
+ if ((data[1] = (u64) netxen_nic_test_link(dev)))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
}
}
@@ -783,7 +692,6 @@ struct ethtool_ops netxen_nic_ethtool_ops = {
.get_drvinfo = netxen_nic_get_drvinfo,
.get_regs_len = netxen_nic_get_regs_len,
.get_regs = netxen_nic_get_regs,
- .get_wol = netxen_nic_get_wol,
.get_link = ethtool_op_get_link,
.get_eeprom_len = netxen_nic_get_eeprom_len,
.get_eeprom = netxen_nic_get_eeprom,
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index 7195af3e8f3..1be55702557 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -228,7 +228,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
&adapter->ctx_desc_pdev);
printk("ctx_desc_phys_addr: 0x%llx\n",
- (u64) adapter->ctx_desc_phys_addr);
+ (unsigned long long) adapter->ctx_desc_phys_addr);
if (addr == NULL) {
DPRINTK(ERR, "bad return from pci_alloc_consistent\n");
err = -ENOMEM;
@@ -242,11 +242,13 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
adapter->cmd_consumer = (uint32_t *) (((char *)addr) +
sizeof(struct netxen_ring_ctx));
- addr = pci_alloc_consistent(adapter->ahw.pdev,
- sizeof(struct cmd_desc_type0) *
- adapter->max_tx_desc_count,
- (dma_addr_t *) & hw->cmd_desc_phys_addr);
- printk("cmd_desc_phys_addr: 0x%llx\n", (u64) hw->cmd_desc_phys_addr);
+ addr = netxen_alloc(adapter->ahw.pdev,
+ sizeof(struct cmd_desc_type0) *
+ adapter->max_tx_desc_count,
+ (dma_addr_t *) & hw->cmd_desc_phys_addr,
+ &adapter->ahw.cmd_desc_pdev);
+ printk("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");
@@ -507,8 +509,8 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw)
void netxen_load_firmware(struct netxen_adapter *adapter)
{
int i;
- long data, size = 0;
- long flashaddr = NETXEN_FLASH_BASE, memaddr = NETXEN_PHANTOM_MEM_BASE;
+ u32 data, size = 0;
+ u32 flashaddr = NETXEN_FLASH_BASE, memaddr = NETXEN_PHANTOM_MEM_BASE;
u64 off;
void __iomem *addr;
@@ -950,6 +952,7 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter)
netxen_nic_driver_name);
return;
}
+ *ptr32 = le32_to_cpu(*ptr32);
ptr32++;
addr += sizeof(u32);
}
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 2f324366784..586d32b676a 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -38,13 +38,13 @@
#include "netxen_nic_phan_reg.h"
struct crb_addr_pair {
- long addr;
- long data;
+ u32 addr;
+ u32 data;
};
#define NETXEN_MAX_CRB_XFORM 60
static unsigned int crb_addr_xform[NETXEN_MAX_CRB_XFORM];
-#define NETXEN_ADDR_ERROR ((unsigned long ) 0xffffffff )
+#define NETXEN_ADDR_ERROR (0xffffffff)
#define crb_addr_transform(name) \
crb_addr_xform[NETXEN_HW_PX_MAP_CRB_##name] = \
@@ -252,10 +252,10 @@ void netxen_initialize_adapter_ops(struct netxen_adapter *adapter)
* netxen_decode_crb_addr(0 - utility to translate from internal Phantom CRB
* address to external PCI CRB address.
*/
-unsigned long netxen_decode_crb_addr(unsigned long addr)
+u32 netxen_decode_crb_addr(u32 addr)
{
int i;
- unsigned long base_addr, offset, pci_base;
+ u32 base_addr, offset, pci_base;
crb_addr_transform_setup();
@@ -499,7 +499,10 @@ static inline int do_rom_fast_write_words(struct netxen_adapter *adapter,
while(1) {
int data1;
- do_rom_fast_read(adapter, addridx, &data1);
+ ret = do_rom_fast_read(adapter, addridx, &data1);
+ if (ret < 0)
+ return ret;
+
if (data1 == data)
break;
@@ -753,7 +756,7 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
int n, i;
int init_delay = 0;
struct crb_addr_pair *buf;
- unsigned long off;
+ u32 off;
/* resetall */
status = netxen_nic_get_board_info(adapter);
@@ -810,14 +813,13 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
if (verbose)
printk("%s: PCI: 0x%08x == 0x%08x\n",
netxen_nic_driver_name, (unsigned int)
- netxen_decode_crb_addr((unsigned long)
- addr), val);
+ netxen_decode_crb_addr(addr), val);
}
for (i = 0; i < n; i++) {
- off = netxen_decode_crb_addr((unsigned long)buf[i].addr);
+ off = netxen_decode_crb_addr(buf[i].addr);
if (off == NETXEN_ADDR_ERROR) {
- printk(KERN_ERR"CRB init value out of range %lx\n",
+ printk(KERN_ERR"CRB init value out of range %x\n",
buf[i].addr);
continue;
}
@@ -924,6 +926,10 @@ int netxen_initialize_adapter_offload(struct netxen_adapter *adapter)
void netxen_free_adapter_offload(struct netxen_adapter *adapter)
{
if (adapter->dummy_dma.addr) {
+ writel(0, NETXEN_CRB_NORMALIZE(adapter,
+ CRB_HOST_DUMMY_BUF_ADDR_HI));
+ writel(0, NETXEN_CRB_NORMALIZE(adapter,
+ CRB_HOST_DUMMY_BUF_ADDR_LO));
pci_free_consistent(adapter->ahw.pdev,
NETXEN_HOST_DUMMY_DMA_SIZE,
adapter->dummy_dma.addr,
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 225ff55527c..7d2525e76ab 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -42,8 +42,6 @@
#include <linux/dma-mapping.h>
#include <linux/vmalloc.h>
-#define PHAN_VENDOR_ID 0x4040
-
MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(NETXEN_NIC_LINUX_VERSIONID);
@@ -379,6 +377,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->tx_timeout = netxen_tx_timeout;
netdev->watchdog_timeo = HZ;
+ netxen_nic_change_mtu(netdev, netdev->mtu);
+
SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
netdev->poll = netxen_nic_poll;
netdev->weight = NETXEN_NETDEV_WEIGHT;
@@ -434,13 +434,11 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->port_count++;
adapter->port[i] = port;
}
-#ifndef CONFIG_PPC64
writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
netxen_pinit_from_rom(adapter, 0);
udelay(500);
netxen_load_firmware(adapter);
netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
-#endif
/*
* delay a while to ensure that the Pegs are up & running.
* Otherwise, we might see some flaky behaviour.
@@ -525,14 +523,17 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
if (adapter == NULL)
return;
+ if (adapter->irq)
+ free_irq(adapter->irq, adapter);
netxen_nic_stop_all_ports(adapter);
/* leave the hw in the same state as reboot */
- netxen_pinit_from_rom(adapter, 0);
writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
+ netxen_pinit_from_rom(adapter, 0);
+ udelay(500);
netxen_load_firmware(adapter);
netxen_free_adapter_offload(adapter);
- udelay(500); /* Delay for a while to drain the DMA engines */
+ mdelay(1000); /* Delay for a while to drain the DMA engines */
for (i = 0; i < adapter->port_count; i++) {
port = adapter->port[i];
if ((port) && (port->netdev)) {
@@ -543,7 +544,6 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
if ((adapter->flags & NETXEN_NIC_MSI_ENABLED))
pci_disable_msi(pdev);
- pci_set_drvdata(pdev, NULL);
if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
netxen_free_hw_resources(adapter);
@@ -554,6 +554,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
pci_release_regions(pdev);
pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
for (ctxid = 0; ctxid < MAX_RCV_CTX; ++ctxid) {
recv_ctx = &adapter->recv_ctx[ctxid];
@@ -672,8 +673,6 @@ static int netxen_nic_close(struct net_device *netdev)
if (!adapter->active_ports) {
netxen_nic_disable_int(adapter);
- if (adapter->irq)
- free_irq(adapter->irq, adapter);
cmd_buff = adapter->cmd_buf_arr;
for (i = 0; i < adapter->max_tx_desc_count; i++) {
buffrag = cmd_buff->frag_array;
@@ -1155,8 +1154,8 @@ static void __exit netxen_exit_module(void)
/*
* Wait for some time to allow the dma to drain, if any.
*/
- destroy_workqueue(netxen_workq);
pci_unregister_driver(&netxen_driver);
+ destroy_workqueue(netxen_workq);
}
module_exit(netxen_exit_module);
diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h
index 7879f855af0..0c7c94328b7 100644
--- a/drivers/net/netxen/netxen_nic_phan_reg.h
+++ b/drivers/net/netxen/netxen_nic_phan_reg.h
@@ -102,6 +102,9 @@
#define CRB_CMD_CONSUMER_OFFSET_1 NETXEN_NIC_REG(0x1b0)
#define CRB_TEMP_STATE NETXEN_NIC_REG(0x1b4)
+/* used for ethtool tests */
+#define CRB_SCRATCHPAD_TEST NETXEN_NIC_REG(0x280)
+
/*
* CrbPortPhanCntrHi/Lo is used to pass the address of HostPhantomIndex address
* which can be read by the Phantom host to get producer/consumer indexes from
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index 196993a29b0..a6f4b24b017 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -104,8 +104,6 @@ static int automatic_resume; /* experimental .. better should be zero */
static int rfdadd; /* rfdadd=1 may be better for 8K MEM cards */
static int fifo=0x8; /* don't change */
-/* #define REALLY_SLOW_IO */
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 568daeb3e9d..9ec6e9e54f4 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -514,8 +514,7 @@ static void ns83820_vlan_rx_kill_vid(struct net_device *ndev, unsigned short vid
spin_lock_irq(&dev->misc_lock);
spin_lock(&dev->tx_lock);
- if (dev->vlgrp)
- dev->vlgrp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(dev->vlgrp, vid, NULL);
spin_unlock(&dev->tx_lock);
spin_unlock_irq(&dev->misc_lock);
}
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 36f9d988278..4d94ba7899b 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -1234,14 +1234,14 @@ static void pcnet32_rx_entry(struct net_device *dev,
skb_put(skb, pkt_len); /* Make room */
pci_dma_sync_single_for_cpu(lp->pci_dev,
lp->rx_dma_addr[entry],
- PKT_BUF_SZ - 2,
+ pkt_len,
PCI_DMA_FROMDEVICE);
eth_copy_and_sum(skb,
(unsigned char *)(lp->rx_skbuff[entry]->data),
pkt_len, 0);
pci_dma_sync_single_for_device(lp->pci_dev,
lp->rx_dma_addr[entry],
- PKT_BUF_SZ - 2,
+ pkt_len,
PCI_DMA_FROMDEVICE);
}
lp->stats.rx_bytes += skb->len;
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 860bb0f60f6..ebfa2967cd6 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -7,6 +7,12 @@
*
* Version: 0.7.0
*
+ * 070228 : Fix to allow multiple sessions with same remote MAC and same
+ * session id by including the local device ifindex in the
+ * tuple identifying a session. This also ensures packets can't
+ * be injected into a session from interfaces other than the one
+ * specified by userspace. Florian Zumbiehl <florz@florz.de>
+ * (Oh, BTW, this one is YYMMDD, in case you were wondering ...)
* 220102 : Fix module use count on failure in pppoe_create, pppox_sk -acme
* 030700 : Fixed connect logic to allow for disconnect.
* 270700 : Fixed potential SMP problems; we must protect against
@@ -127,14 +133,14 @@ static struct pppox_sock *item_hash_table[PPPOE_HASH_SIZE];
* Set/get/delete/rehash items (internal versions)
*
**********************************************************************/
-static struct pppox_sock *__get_item(unsigned long sid, unsigned char *addr)
+static struct pppox_sock *__get_item(unsigned long sid, unsigned char *addr, int ifindex)
{
int hash = hash_item(sid, addr);
struct pppox_sock *ret;
ret = item_hash_table[hash];
- while (ret && !cmp_addr(&ret->pppoe_pa, sid, addr))
+ while (ret && !(cmp_addr(&ret->pppoe_pa, sid, addr) && ret->pppoe_ifindex == ifindex))
ret = ret->next;
return ret;
@@ -147,21 +153,19 @@ static int __set_item(struct pppox_sock *po)
ret = item_hash_table[hash];
while (ret) {
- if (cmp_2_addr(&ret->pppoe_pa, &po->pppoe_pa))
+ if (cmp_2_addr(&ret->pppoe_pa, &po->pppoe_pa) && ret->pppoe_ifindex == po->pppoe_ifindex)
return -EALREADY;
ret = ret->next;
}
- if (!ret) {
- po->next = item_hash_table[hash];
- item_hash_table[hash] = po;
- }
+ po->next = item_hash_table[hash];
+ item_hash_table[hash] = po;
return 0;
}
-static struct pppox_sock *__delete_item(unsigned long sid, char *addr)
+static struct pppox_sock *__delete_item(unsigned long sid, char *addr, int ifindex)
{
int hash = hash_item(sid, addr);
struct pppox_sock *ret, **src;
@@ -170,7 +174,7 @@ static struct pppox_sock *__delete_item(unsigned long sid, char *addr)
src = &item_hash_table[hash];
while (ret) {
- if (cmp_addr(&ret->pppoe_pa, sid, addr)) {
+ if (cmp_addr(&ret->pppoe_pa, sid, addr) && ret->pppoe_ifindex == ifindex) {
*src = ret->next;
break;
}
@@ -188,12 +192,12 @@ static struct pppox_sock *__delete_item(unsigned long sid, char *addr)
*
**********************************************************************/
static inline struct pppox_sock *get_item(unsigned long sid,
- unsigned char *addr)
+ unsigned char *addr, int ifindex)
{
struct pppox_sock *po;
read_lock_bh(&pppoe_hash_lock);
- po = __get_item(sid, addr);
+ po = __get_item(sid, addr, ifindex);
if (po)
sock_hold(sk_pppox(po));
read_unlock_bh(&pppoe_hash_lock);
@@ -203,7 +207,15 @@ static inline struct pppox_sock *get_item(unsigned long sid,
static inline struct pppox_sock *get_item_by_addr(struct sockaddr_pppox *sp)
{
- return get_item(sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote);
+ struct net_device *dev = NULL;
+ int ifindex;
+
+ dev = dev_get_by_name(sp->sa_addr.pppoe.dev);
+ if(!dev)
+ return NULL;
+ ifindex = dev->ifindex;
+ dev_put(dev);
+ return get_item(sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote, ifindex);
}
static inline int set_item(struct pppox_sock *po)
@@ -220,12 +232,12 @@ static inline int set_item(struct pppox_sock *po)
return i;
}
-static inline struct pppox_sock *delete_item(unsigned long sid, char *addr)
+static inline struct pppox_sock *delete_item(unsigned long sid, char *addr, int ifindex)
{
struct pppox_sock *ret;
write_lock_bh(&pppoe_hash_lock);
- ret = __delete_item(sid, addr);
+ ret = __delete_item(sid, addr, ifindex);
write_unlock_bh(&pppoe_hash_lock);
return ret;
@@ -391,7 +403,7 @@ static int pppoe_rcv(struct sk_buff *skb,
ph = (struct pppoe_hdr *) skb->nh.raw;
- po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source);
+ po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
if (po != NULL)
return sk_receive_skb(sk_pppox(po), skb, 0);
drop:
@@ -425,7 +437,7 @@ static int pppoe_disc_rcv(struct sk_buff *skb,
if (ph->code != PADT_CODE)
goto abort;
- po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source);
+ po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
if (po) {
struct sock *sk = sk_pppox(po);
@@ -517,7 +529,7 @@ static int pppoe_release(struct socket *sock)
po = pppox_sk(sk);
if (po->pppoe_pa.sid) {
- delete_item(po->pppoe_pa.sid, po->pppoe_pa.remote);
+ delete_item(po->pppoe_pa.sid, po->pppoe_pa.remote, po->pppoe_ifindex);
}
if (po->pppoe_dev)
@@ -539,7 +551,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
int sockaddr_len, int flags)
{
struct sock *sk = sock->sk;
- struct net_device *dev = NULL;
+ struct net_device *dev;
struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;
struct pppox_sock *po = pppox_sk(sk);
int error;
@@ -565,7 +577,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
pppox_unbind_sock(sk);
/* Delete the old binding */
- delete_item(po->pppoe_pa.sid,po->pppoe_pa.remote);
+ delete_item(po->pppoe_pa.sid,po->pppoe_pa.remote,po->pppoe_ifindex);
if(po->pppoe_dev)
dev_put(po->pppoe_dev);
@@ -585,6 +597,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
goto end;
po->pppoe_dev = dev;
+ po->pppoe_ifindex = dev->ifindex;
if (!(dev->flags & IFF_UP))
goto err_put;
@@ -705,7 +718,7 @@ static int pppoe_ioctl(struct socket *sock, unsigned int cmd,
break;
/* PPPoE address from the user specifies an outbound
- PPPoE address to which frames are forwarded to */
+ PPPoE address which frames are forwarded to */
err = -EFAULT;
if (copy_from_user(&po->pppoe_relay,
(void __user *)arg,
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index a142cdfd947..d3f65dab306 100755
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -39,7 +39,7 @@
#define DRV_NAME "qla3xxx"
#define DRV_STRING "QLogic ISP3XXX Network Driver"
-#define DRV_VERSION "v2.02.00-k36"
+#define DRV_VERSION "v2.03.00-k3"
#define PFX DRV_NAME " "
static const char ql3xxx_driver_name[] = DRV_NAME;
@@ -276,7 +276,8 @@ static void ql_enable_interrupts(struct ql3_adapter *qdev)
static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev,
struct ql_rcv_buf_cb *lrg_buf_cb)
{
- u64 map;
+ dma_addr_t map;
+ int err;
lrg_buf_cb->next = NULL;
if (qdev->lrg_buf_free_tail == NULL) { /* The list is empty */
@@ -287,9 +288,10 @@ static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev,
}
if (!lrg_buf_cb->skb) {
- lrg_buf_cb->skb = dev_alloc_skb(qdev->lrg_buffer_len);
+ lrg_buf_cb->skb = netdev_alloc_skb(qdev->ndev,
+ qdev->lrg_buffer_len);
if (unlikely(!lrg_buf_cb->skb)) {
- printk(KERN_ERR PFX "%s: failed dev_alloc_skb().\n",
+ printk(KERN_ERR PFX "%s: failed netdev_alloc_skb().\n",
qdev->ndev->name);
qdev->lrg_buf_skb_check++;
} else {
@@ -303,6 +305,17 @@ static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev,
qdev->lrg_buffer_len -
QL_HEADER_SPACE,
PCI_DMA_FROMDEVICE);
+ err = pci_dma_mapping_error(map);
+ if(err) {
+ printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
+ qdev->ndev->name, err);
+ dev_kfree_skb(lrg_buf_cb->skb);
+ lrg_buf_cb->skb = NULL;
+
+ qdev->lrg_buf_skb_check++;
+ return;
+ }
+
lrg_buf_cb->buf_phy_addr_low =
cpu_to_le32(LS_64BITS(map));
lrg_buf_cb->buf_phy_addr_high =
@@ -1387,6 +1400,8 @@ static void ql_link_state_machine(struct ql3_adapter *qdev)
printk(KERN_INFO PFX
"%s: Reset in progress, skip processing link "
"state.\n", qdev->ndev->name);
+
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
return;
}
@@ -1518,8 +1533,10 @@ static int ql_get_auto_cfg_status(struct ql3_adapter *qdev)
spin_lock_irqsave(&qdev->hw_lock, hw_flags);
if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
- 2) << 7))
+ 2) << 7)) {
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
return 0;
+ }
status = ql_is_auto_cfg(qdev);
ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
@@ -1533,8 +1550,10 @@ static u32 ql_get_speed(struct ql3_adapter *qdev)
spin_lock_irqsave(&qdev->hw_lock, hw_flags);
if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
- 2) << 7))
+ 2) << 7)) {
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
return 0;
+ }
status = ql_get_link_speed(qdev);
ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
@@ -1548,8 +1567,10 @@ static int ql_get_full_dup(struct ql3_adapter *qdev)
spin_lock_irqsave(&qdev->hw_lock, hw_flags);
if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
- 2) << 7))
+ 2) << 7)) {
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
return 0;
+ }
status = ql_is_link_full_dup(qdev);
ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
@@ -1615,14 +1636,16 @@ static const struct ethtool_ops ql3xxx_ethtool_ops = {
static int ql_populate_free_queue(struct ql3_adapter *qdev)
{
struct ql_rcv_buf_cb *lrg_buf_cb = qdev->lrg_buf_free_head;
- u64 map;
+ dma_addr_t map;
+ int err;
while (lrg_buf_cb) {
if (!lrg_buf_cb->skb) {
- lrg_buf_cb->skb = dev_alloc_skb(qdev->lrg_buffer_len);
+ lrg_buf_cb->skb = netdev_alloc_skb(qdev->ndev,
+ qdev->lrg_buffer_len);
if (unlikely(!lrg_buf_cb->skb)) {
printk(KERN_DEBUG PFX
- "%s: Failed dev_alloc_skb().\n",
+ "%s: Failed netdev_alloc_skb().\n",
qdev->ndev->name);
break;
} else {
@@ -1636,6 +1659,17 @@ static int ql_populate_free_queue(struct ql3_adapter *qdev)
qdev->lrg_buffer_len -
QL_HEADER_SPACE,
PCI_DMA_FROMDEVICE);
+
+ err = pci_dma_mapping_error(map);
+ if(err) {
+ printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
+ qdev->ndev->name, err);
+ dev_kfree_skb(lrg_buf_cb->skb);
+ lrg_buf_cb->skb = NULL;
+ break;
+ }
+
+
lrg_buf_cb->buf_phy_addr_low =
cpu_to_le32(LS_64BITS(map));
lrg_buf_cb->buf_phy_addr_high =
@@ -1690,11 +1724,11 @@ static void ql_update_lrg_bufq_prod_index(struct ql3_adapter *qdev)
qdev->lrg_buf_q_producer_index++;
- if (qdev->lrg_buf_q_producer_index == NUM_LBUFQ_ENTRIES)
+ if (qdev->lrg_buf_q_producer_index == qdev->num_lbufq_entries)
qdev->lrg_buf_q_producer_index = 0;
if (qdev->lrg_buf_q_producer_index ==
- (NUM_LBUFQ_ENTRIES - 1)) {
+ (qdev->num_lbufq_entries - 1)) {
lrg_buf_q_ele = qdev->lrg_buf_q_virt_addr;
}
}
@@ -1713,8 +1747,31 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
{
struct ql_tx_buf_cb *tx_cb;
int i;
+ int retval = 0;
+ if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) {
+ printk(KERN_WARNING "Frame short but, frame was padded and sent.\n");
+ }
+
tx_cb = &qdev->tx_buf[mac_rsp->transaction_id];
+
+ /* Check the transmit response flags for any errors */
+ if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) {
+ printk(KERN_ERR "Frame too short to be legal, frame not sent.\n");
+
+ qdev->stats.tx_errors++;
+ retval = -EIO;
+ goto frame_not_sent;
+ }
+
+ if(tx_cb->seg_count == 0) {
+ printk(KERN_ERR "tx_cb->seg_count == 0: %d\n", mac_rsp->transaction_id);
+
+ qdev->stats.tx_errors++;
+ retval = -EIO;
+ goto invalid_seg_count;
+ }
+
pci_unmap_single(qdev->pdev,
pci_unmap_addr(&tx_cb->map[0], mapaddr),
pci_unmap_len(&tx_cb->map[0], maplen),
@@ -1731,11 +1788,32 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
}
qdev->stats.tx_packets++;
qdev->stats.tx_bytes += tx_cb->skb->len;
+
+frame_not_sent:
dev_kfree_skb_irq(tx_cb->skb);
tx_cb->skb = NULL;
+
+invalid_seg_count:
atomic_inc(&qdev->tx_count);
}
+void ql_get_sbuf(struct ql3_adapter *qdev)
+{
+ if (++qdev->small_buf_index == NUM_SMALL_BUFFERS)
+ qdev->small_buf_index = 0;
+ qdev->small_buf_release_cnt++;
+}
+
+struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev)
+{
+ struct ql_rcv_buf_cb *lrg_buf_cb = NULL;
+ lrg_buf_cb = &qdev->lrg_buf[qdev->lrg_buf_index];
+ qdev->lrg_buf_release_cnt++;
+ if (++qdev->lrg_buf_index == qdev->num_large_buffers)
+ qdev->lrg_buf_index = 0;
+ return(lrg_buf_cb);
+}
+
/*
* The difference between 3022 and 3032 for inbound completions:
* 3022 uses two buffers per completion. The first buffer contains
@@ -1751,47 +1829,21 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
struct ib_mac_iocb_rsp *ib_mac_rsp_ptr)
{
- long int offset;
- u32 lrg_buf_phy_addr_low = 0;
struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL;
struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL;
- u32 *curr_ial_ptr;
struct sk_buff *skb;
u16 length = le16_to_cpu(ib_mac_rsp_ptr->length);
/*
* Get the inbound address list (small buffer).
*/
- offset = qdev->small_buf_index * QL_SMALL_BUFFER_SIZE;
- if (++qdev->small_buf_index == NUM_SMALL_BUFFERS)
- qdev->small_buf_index = 0;
+ ql_get_sbuf(qdev);
- curr_ial_ptr = (u32 *) (qdev->small_buf_virt_addr + offset);
- qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
- qdev->small_buf_release_cnt++;
-
- if (qdev->device_id == QL3022_DEVICE_ID) {
- /* start of first buffer (3022 only) */
- lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
- lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
- qdev->lrg_buf_release_cnt++;
- if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) {
- qdev->lrg_buf_index = 0;
- }
- curr_ial_ptr++; /* 64-bit pointers require two incs. */
- curr_ial_ptr++;
- }
+ if (qdev->device_id == QL3022_DEVICE_ID)
+ lrg_buf_cb1 = ql_get_lbuf(qdev);
/* start of second buffer */
- lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
- lrg_buf_cb2 = &qdev->lrg_buf[qdev->lrg_buf_index];
-
- /*
- * Second buffer gets sent up the stack.
- */
- qdev->lrg_buf_release_cnt++;
- if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
- qdev->lrg_buf_index = 0;
+ lrg_buf_cb2 = ql_get_lbuf(qdev);
skb = lrg_buf_cb2->skb;
qdev->stats.rx_packets++;
@@ -1819,11 +1871,8 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
struct ib_ip_iocb_rsp *ib_ip_rsp_ptr)
{
- long int offset;
- u32 lrg_buf_phy_addr_low = 0;
struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL;
struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL;
- u32 *curr_ial_ptr;
struct sk_buff *skb1 = NULL, *skb2;
struct net_device *ndev = qdev->ndev;
u16 length = le16_to_cpu(ib_ip_rsp_ptr->length);
@@ -1833,35 +1882,20 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
* Get the inbound address list (small buffer).
*/
- offset = qdev->small_buf_index * QL_SMALL_BUFFER_SIZE;
- if (++qdev->small_buf_index == NUM_SMALL_BUFFERS)
- qdev->small_buf_index = 0;
- curr_ial_ptr = (u32 *) (qdev->small_buf_virt_addr + offset);
- qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
- qdev->small_buf_release_cnt++;
+ ql_get_sbuf(qdev);
if (qdev->device_id == QL3022_DEVICE_ID) {
/* start of first buffer on 3022 */
- lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
- lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
- qdev->lrg_buf_release_cnt++;
- if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
- qdev->lrg_buf_index = 0;
+ lrg_buf_cb1 = ql_get_lbuf(qdev);
skb1 = lrg_buf_cb1->skb;
- curr_ial_ptr++; /* 64-bit pointers require two incs. */
- curr_ial_ptr++;
size = ETH_HLEN;
if (*((u16 *) skb1->data) != 0xFFFF)
size += VLAN_ETH_HLEN - ETH_HLEN;
}
/* start of second buffer */
- lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
- lrg_buf_cb2 = &qdev->lrg_buf[qdev->lrg_buf_index];
+ lrg_buf_cb2 = ql_get_lbuf(qdev);
skb2 = lrg_buf_cb2->skb;
- qdev->lrg_buf_release_cnt++;
- if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
- qdev->lrg_buf_index = 0;
skb_put(skb2, length); /* Just the second buffer length here. */
pci_unmap_single(qdev->pdev,
@@ -1914,10 +1948,13 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev,
struct net_rsp_iocb *net_rsp;
struct net_device *ndev = qdev->ndev;
unsigned long hw_flags;
+ int work_done = 0;
+
+ u32 rsp_producer_index = le32_to_cpu(*(qdev->prsp_producer_index));
/* While there are entries in the completion queue. */
- while ((cpu_to_le32(*(qdev->prsp_producer_index)) !=
- qdev->rsp_consumer_index) && (*rx_cleaned < work_to_do)) {
+ while ((rsp_producer_index !=
+ qdev->rsp_consumer_index) && (work_done < work_to_do)) {
net_rsp = qdev->rsp_current;
switch (net_rsp->opcode) {
@@ -1968,37 +2005,34 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev,
} else {
qdev->rsp_current++;
}
+
+ work_done = *tx_cleaned + *rx_cleaned;
}
- spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ if(work_done) {
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
- ql_update_lrg_bufq_prod_index(qdev);
+ ql_update_lrg_bufq_prod_index(qdev);
- if (qdev->small_buf_release_cnt >= 16) {
- while (qdev->small_buf_release_cnt >= 16) {
- qdev->small_buf_q_producer_index++;
+ if (qdev->small_buf_release_cnt >= 16) {
+ while (qdev->small_buf_release_cnt >= 16) {
+ qdev->small_buf_q_producer_index++;
- if (qdev->small_buf_q_producer_index ==
- NUM_SBUFQ_ENTRIES)
- qdev->small_buf_q_producer_index = 0;
- qdev->small_buf_release_cnt -= 8;
- }
+ if (qdev->small_buf_q_producer_index ==
+ NUM_SBUFQ_ENTRIES)
+ qdev->small_buf_q_producer_index = 0;
+ qdev->small_buf_release_cnt -= 8;
+ }
- ql_write_common_reg(qdev,
- &port_regs->CommonRegs.
- rxSmallQProducerIndex,
- qdev->small_buf_q_producer_index);
- }
+ wmb();
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ rxSmallQProducerIndex,
+ qdev->small_buf_q_producer_index);
- ql_write_common_reg(qdev,
- &port_regs->CommonRegs.rspQConsumerIndex,
- qdev->rsp_consumer_index);
- spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ }
- if (unlikely(netif_queue_stopped(qdev->ndev))) {
- if (netif_queue_stopped(qdev->ndev) &&
- (atomic_read(&qdev->tx_count) > (NUM_REQ_Q_ENTRIES / 4)))
- netif_wake_queue(qdev->ndev);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
}
return *tx_cleaned + *rx_cleaned;
@@ -2009,6 +2043,8 @@ static int ql_poll(struct net_device *ndev, int *budget)
struct ql3_adapter *qdev = netdev_priv(ndev);
int work_to_do = min(*budget, ndev->quota);
int rx_cleaned = 0, tx_cleaned = 0;
+ unsigned long hw_flags;
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
if (!netif_carrier_ok(ndev))
goto quit_polling;
@@ -2017,9 +2053,17 @@ static int ql_poll(struct net_device *ndev, int *budget)
*budget -= rx_cleaned;
ndev->quota -= rx_cleaned;
- if ((!tx_cleaned && !rx_cleaned) || !netif_running(ndev)) {
+ if( tx_cleaned + rx_cleaned != work_to_do ||
+ !netif_running(ndev)) {
quit_polling:
netif_rx_complete(ndev);
+
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.rspQConsumerIndex,
+ qdev->rsp_consumer_index);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+
ql_enable_interrupts(qdev);
return 0;
}
@@ -2073,10 +2117,9 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
spin_unlock(&qdev->adapter_lock);
} else if (value & ISP_IMR_DISABLE_CMPL_INT) {
ql_disable_interrupts(qdev);
- if (likely(netif_rx_schedule_prep(ndev)))
+ if (likely(netif_rx_schedule_prep(ndev))) {
__netif_rx_schedule(ndev);
- else
- ql_enable_interrupts(qdev);
+ }
} else {
return IRQ_NONE;
}
@@ -2093,8 +2136,12 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
* the next AOL if more frags are coming.
* That is why the frags:segment count ratio is not linear.
*/
-static int ql_get_seg_count(unsigned short frags)
+static int ql_get_seg_count(struct ql3_adapter *qdev,
+ unsigned short frags)
{
+ if (qdev->device_id == QL3022_DEVICE_ID)
+ return 1;
+
switch(frags) {
case 0: return 1; /* just the skb->data seg */
case 1: return 2; /* skb->data + 1 frag */
@@ -2139,11 +2186,13 @@ static void ql_hw_csum_setup(struct sk_buff *skb,
if (ip) {
if (ip->protocol == IPPROTO_TCP) {
- mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_TC;
+ mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_TC |
+ OB_3032MAC_IOCB_REQ_IC;
mac_iocb_ptr->ip_hdr_off = offset;
mac_iocb_ptr->ip_hdr_len = ip->ihl;
} else if (ip->protocol == IPPROTO_UDP) {
- mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_UC;
+ mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_UC |
+ OB_3032MAC_IOCB_REQ_IC;
mac_iocb_ptr->ip_hdr_off = offset;
mac_iocb_ptr->ip_hdr_len = ip->ihl;
}
@@ -2151,53 +2200,42 @@ static void ql_hw_csum_setup(struct sk_buff *skb,
}
/*
- * The difference between 3022 and 3032 sends:
- * 3022 only supports a simple single segment transmission.
- * 3032 supports checksumming and scatter/gather lists (fragments).
- * The 3032 supports sglists by using the 3 addr/len pairs (ALP)
- * in the IOCB plus a chain of outbound address lists (OAL) that
- * each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th)
- * will used to point to an OAL when more ALP entries are required.
- * The IOCB is always the top of the chain followed by one or more
- * OALs (when necessary).
+ * Map the buffers for this transmit. This will return
+ * NETDEV_TX_BUSY or NETDEV_TX_OK based on success.
*/
-static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
+static int ql_send_map(struct ql3_adapter *qdev,
+ struct ob_mac_iocb_req *mac_iocb_ptr,
+ struct ql_tx_buf_cb *tx_cb,
+ struct sk_buff *skb)
{
- struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
- struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
- struct ql_tx_buf_cb *tx_cb;
- u32 tot_len = skb->len;
struct oal *oal;
struct oal_entry *oal_entry;
- int len;
- struct ob_mac_iocb_req *mac_iocb_ptr;
- u64 map;
+ int len = skb_headlen(skb);
+ dma_addr_t map;
+ int err;
+ int completed_segs, i;
int seg_cnt, seg = 0;
int frag_cnt = (int)skb_shinfo(skb)->nr_frags;
- if (unlikely(atomic_read(&qdev->tx_count) < 2)) {
- if (!netif_queue_stopped(ndev))
- netif_stop_queue(ndev);
- return NETDEV_TX_BUSY;
- }
- tx_cb = &qdev->tx_buf[qdev->req_producer_index] ;
- seg_cnt = tx_cb->seg_count = ql_get_seg_count((skb_shinfo(skb)->nr_frags));
+ seg_cnt = tx_cb->seg_count = ql_get_seg_count(qdev,
+ (skb_shinfo(skb)->nr_frags));
if(seg_cnt == -1) {
printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__);
- return NETDEV_TX_OK;
-
+ return NETDEV_TX_BUSY;
}
- mac_iocb_ptr = tx_cb->queue_entry;
- memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req));
- mac_iocb_ptr->opcode = qdev->mac_ob_opcode;
- mac_iocb_ptr->flags |= qdev->mb_bit_mask;
- mac_iocb_ptr->transaction_id = qdev->req_producer_index;
- mac_iocb_ptr->data_len = cpu_to_le16((u16) tot_len);
- tx_cb->skb = skb;
- if (skb->ip_summed == CHECKSUM_PARTIAL)
- ql_hw_csum_setup(skb, mac_iocb_ptr);
- len = skb_headlen(skb);
+ /*
+ * Map the skb buffer first.
+ */
map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE);
+
+ err = pci_dma_mapping_error(map);
+ if(err) {
+ printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
+ qdev->ndev->name, err);
+
+ return NETDEV_TX_BUSY;
+ }
+
oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low;
oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
@@ -2206,15 +2244,14 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
pci_unmap_len_set(&tx_cb->map[seg], maplen, len);
seg++;
- if (!skb_shinfo(skb)->nr_frags) {
+ if (seg_cnt == 1) {
/* Terminate the last segment. */
oal_entry->len =
cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY);
} else {
- int i;
oal = tx_cb->oal;
- for (i=0; i<frag_cnt; i++,seg++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ for (completed_segs=0; completed_segs<frag_cnt; completed_segs++,seg++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[completed_segs];
oal_entry++;
if ((seg == 2 && seg_cnt > 3) || /* Check for continuation */
(seg == 7 && seg_cnt > 8) || /* requirements. It's strange */
@@ -2224,6 +2261,15 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
map = pci_map_single(qdev->pdev, oal,
sizeof(struct oal),
PCI_DMA_TODEVICE);
+
+ err = pci_dma_mapping_error(map);
+ if(err) {
+
+ printk(KERN_ERR "%s: PCI mapping outbound address list with error: %d\n",
+ qdev->ndev->name, err);
+ goto map_error;
+ }
+
oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
oal_entry->len =
@@ -2242,6 +2288,14 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
pci_map_page(qdev->pdev, frag->page,
frag->page_offset, frag->size,
PCI_DMA_TODEVICE);
+
+ err = pci_dma_mapping_error(map);
+ if(err) {
+ printk(KERN_ERR "%s: PCI mapping frags failed with error: %d\n",
+ qdev->ndev->name, err);
+ goto map_error;
+ }
+
oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
oal_entry->len = cpu_to_le32(frag->size);
@@ -2253,6 +2307,94 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
oal_entry->len =
cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY);
}
+
+ return NETDEV_TX_OK;
+
+map_error:
+ /* A PCI mapping failed and now we will need to back out
+ * We need to traverse through the oal's and associated pages which
+ * have been mapped and now we must unmap them to clean up properly
+ */
+
+ seg = 1;
+ oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low;
+ oal = tx_cb->oal;
+ for (i=0; i<completed_segs; i++,seg++) {
+ oal_entry++;
+
+ if((seg == 2 && seg_cnt > 3) || /* Check for continuation */
+ (seg == 7 && seg_cnt > 8) || /* requirements. It's strange */
+ (seg == 12 && seg_cnt > 13) || /* but necessary. */
+ (seg == 17 && seg_cnt > 18)) {
+ pci_unmap_single(qdev->pdev,
+ pci_unmap_addr(&tx_cb->map[seg], mapaddr),
+ pci_unmap_len(&tx_cb->map[seg], maplen),
+ PCI_DMA_TODEVICE);
+ oal++;
+ seg++;
+ }
+
+ pci_unmap_page(qdev->pdev,
+ pci_unmap_addr(&tx_cb->map[seg], mapaddr),
+ pci_unmap_len(&tx_cb->map[seg], maplen),
+ PCI_DMA_TODEVICE);
+ }
+
+ pci_unmap_single(qdev->pdev,
+ pci_unmap_addr(&tx_cb->map[0], mapaddr),
+ pci_unmap_addr(&tx_cb->map[0], maplen),
+ PCI_DMA_TODEVICE);
+
+ return NETDEV_TX_BUSY;
+
+}
+
+/*
+ * The difference between 3022 and 3032 sends:
+ * 3022 only supports a simple single segment transmission.
+ * 3032 supports checksumming and scatter/gather lists (fragments).
+ * The 3032 supports sglists by using the 3 addr/len pairs (ALP)
+ * in the IOCB plus a chain of outbound address lists (OAL) that
+ * each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th)
+ * will used to point to an OAL when more ALP entries are required.
+ * The IOCB is always the top of the chain followed by one or more
+ * OALs (when necessary).
+ */
+static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql_tx_buf_cb *tx_cb;
+ u32 tot_len = skb->len;
+ struct ob_mac_iocb_req *mac_iocb_ptr;
+
+ if (unlikely(atomic_read(&qdev->tx_count) < 2)) {
+ return NETDEV_TX_BUSY;
+ }
+
+ tx_cb = &qdev->tx_buf[qdev->req_producer_index] ;
+ if((tx_cb->seg_count = ql_get_seg_count(qdev,
+ (skb_shinfo(skb)->nr_frags))) == -1) {
+ printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__);
+ return NETDEV_TX_OK;
+ }
+
+ mac_iocb_ptr = tx_cb->queue_entry;
+ mac_iocb_ptr->opcode = qdev->mac_ob_opcode;
+ mac_iocb_ptr->flags = OB_MAC_IOCB_REQ_X;
+ mac_iocb_ptr->flags |= qdev->mb_bit_mask;
+ mac_iocb_ptr->transaction_id = qdev->req_producer_index;
+ mac_iocb_ptr->data_len = cpu_to_le16((u16) tot_len);
+ tx_cb->skb = skb;
+ if (qdev->device_id == QL3032_DEVICE_ID &&
+ skb->ip_summed == CHECKSUM_PARTIAL)
+ ql_hw_csum_setup(skb, mac_iocb_ptr);
+
+ if(ql_send_map(qdev,mac_iocb_ptr,tx_cb,skb) != NETDEV_TX_OK) {
+ printk(KERN_ERR PFX"%s: Could not map the segments!\n",__func__);
+ return NETDEV_TX_BUSY;
+ }
+
wmb();
qdev->req_producer_index++;
if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES)
@@ -2338,12 +2480,19 @@ static int ql_alloc_buffer_queues(struct ql3_adapter *qdev)
{
/* Create Large Buffer Queue */
qdev->lrg_buf_q_size =
- NUM_LBUFQ_ENTRIES * sizeof(struct lrg_buf_q_entry);
+ qdev->num_lbufq_entries * sizeof(struct lrg_buf_q_entry);
if (qdev->lrg_buf_q_size < PAGE_SIZE)
qdev->lrg_buf_q_alloc_size = PAGE_SIZE;
else
qdev->lrg_buf_q_alloc_size = qdev->lrg_buf_q_size * 2;
+ qdev->lrg_buf = kmalloc(qdev->num_large_buffers * sizeof(struct ql_rcv_buf_cb),GFP_KERNEL);
+ if (qdev->lrg_buf == NULL) {
+ printk(KERN_ERR PFX
+ "%s: qdev->lrg_buf alloc failed.\n", qdev->ndev->name);
+ return -ENOMEM;
+ }
+
qdev->lrg_buf_q_alloc_virt_addr =
pci_alloc_consistent(qdev->pdev,
qdev->lrg_buf_q_alloc_size,
@@ -2393,7 +2542,7 @@ static void ql_free_buffer_queues(struct ql3_adapter *qdev)
"%s: Already done.\n", qdev->ndev->name);
return;
}
-
+ if(qdev->lrg_buf) kfree(qdev->lrg_buf);
pci_free_consistent(qdev->pdev,
qdev->lrg_buf_q_alloc_size,
qdev->lrg_buf_q_alloc_virt_addr,
@@ -2438,8 +2587,6 @@ static int ql_alloc_small_buffers(struct ql3_adapter *qdev)
small_buf_q_entry = qdev->small_buf_q_virt_addr;
- qdev->last_rsp_offset = qdev->small_buf_phy_addr_low;
-
/* Initialize the small buffer queue. */
for (i = 0; i < (QL_ADDR_ELE_PER_BUFQ_ENTRY * NUM_SBUFQ_ENTRIES); i++) {
small_buf_q_entry->addr_high =
@@ -2476,7 +2623,7 @@ static void ql_free_large_buffers(struct ql3_adapter *qdev)
int i = 0;
struct ql_rcv_buf_cb *lrg_buf_cb;
- for (i = 0; i < NUM_LARGE_BUFFERS; i++) {
+ for (i = 0; i < qdev->num_large_buffers; i++) {
lrg_buf_cb = &qdev->lrg_buf[i];
if (lrg_buf_cb->skb) {
dev_kfree_skb(lrg_buf_cb->skb);
@@ -2497,7 +2644,7 @@ static void ql_init_large_buffers(struct ql3_adapter *qdev)
struct ql_rcv_buf_cb *lrg_buf_cb;
struct bufq_addr_element *buf_addr_ele = qdev->lrg_buf_q_virt_addr;
- for (i = 0; i < NUM_LARGE_BUFFERS; i++) {
+ for (i = 0; i < qdev->num_large_buffers; i++) {
lrg_buf_cb = &qdev->lrg_buf[i];
buf_addr_ele->addr_high = lrg_buf_cb->buf_phy_addr_high;
buf_addr_ele->addr_low = lrg_buf_cb->buf_phy_addr_low;
@@ -2512,10 +2659,12 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
int i;
struct ql_rcv_buf_cb *lrg_buf_cb;
struct sk_buff *skb;
- u64 map;
+ dma_addr_t map;
+ int err;
- for (i = 0; i < NUM_LARGE_BUFFERS; i++) {
- skb = dev_alloc_skb(qdev->lrg_buffer_len);
+ for (i = 0; i < qdev->num_large_buffers; i++) {
+ skb = netdev_alloc_skb(qdev->ndev,
+ qdev->lrg_buffer_len);
if (unlikely(!skb)) {
/* Better luck next round */
printk(KERN_ERR PFX
@@ -2541,6 +2690,15 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
qdev->lrg_buffer_len -
QL_HEADER_SPACE,
PCI_DMA_FROMDEVICE);
+
+ err = pci_dma_mapping_error(map);
+ if(err) {
+ printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
+ qdev->ndev->name, err);
+ ql_free_large_buffers(qdev);
+ return -ENOMEM;
+ }
+
pci_unmap_addr_set(lrg_buf_cb, mapaddr, map);
pci_unmap_len_set(lrg_buf_cb, maplen,
qdev->lrg_buffer_len -
@@ -2592,9 +2750,15 @@ static int ql_create_send_free_list(struct ql3_adapter *qdev)
static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
{
- if (qdev->ndev->mtu == NORMAL_MTU_SIZE)
+ if (qdev->ndev->mtu == NORMAL_MTU_SIZE) {
+ qdev->num_lbufq_entries = NUM_LBUFQ_ENTRIES;
qdev->lrg_buffer_len = NORMAL_MTU_SIZE;
+ }
else if (qdev->ndev->mtu == JUMBO_MTU_SIZE) {
+ /*
+ * Bigger buffers, so less of them.
+ */
+ qdev->num_lbufq_entries = JUMBO_NUM_LBUFQ_ENTRIES;
qdev->lrg_buffer_len = JUMBO_MTU_SIZE;
} else {
printk(KERN_ERR PFX
@@ -2602,6 +2766,7 @@ static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
qdev->ndev->name);
return -ENOMEM;
}
+ qdev->num_large_buffers = qdev->num_lbufq_entries * QL_ADDR_ELE_PER_BUFQ_ENTRY;
qdev->lrg_buffer_len += VLAN_ETH_HLEN + VLAN_ID_LEN + QL_HEADER_SPACE;
qdev->max_frame_size =
(qdev->lrg_buffer_len - QL_HEADER_SPACE) + ETHERNET_CRC_SIZE;
@@ -2834,7 +2999,7 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
&hmem_regs->rxLargeQBaseAddrLow,
LS_64BITS(qdev->lrg_buf_q_phy_addr));
- ql_write_page1_reg(qdev, &hmem_regs->rxLargeQLength, NUM_LBUFQ_ENTRIES);
+ ql_write_page1_reg(qdev, &hmem_regs->rxLargeQLength, qdev->num_lbufq_entries);
ql_write_page1_reg(qdev,
&hmem_regs->rxLargeBufferLength,
@@ -2856,7 +3021,7 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
qdev->small_buf_q_producer_index = NUM_SBUFQ_ENTRIES - 1;
qdev->small_buf_release_cnt = 8;
- qdev->lrg_buf_q_producer_index = NUM_LBUFQ_ENTRIES - 1;
+ qdev->lrg_buf_q_producer_index = qdev->num_lbufq_entries - 1;
qdev->lrg_buf_release_cnt = 8;
qdev->lrg_buf_next_free =
(struct bufq_addr_element *)qdev->lrg_buf_q_virt_addr;
@@ -3292,6 +3457,7 @@ static int ql_adapter_up(struct ql3_adapter *qdev)
err_init:
ql_sem_unlock(qdev, QL_DRVR_SEM_MASK);
err_lock:
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
free_irq(qdev->pdev->irq, ndev);
err_irq:
if (qdev->msi && test_bit(QL_MSI_ENABLED,&qdev->flags)) {
@@ -3343,27 +3509,6 @@ static struct net_device_stats *ql3xxx_get_stats(struct net_device *dev)
return &qdev->stats;
}
-static int ql3xxx_change_mtu(struct net_device *ndev, int new_mtu)
-{
- struct ql3_adapter *qdev = netdev_priv(ndev);
- printk(KERN_ERR PFX "%s: new mtu size = %d.\n", ndev->name, new_mtu);
- if (new_mtu != NORMAL_MTU_SIZE && new_mtu != JUMBO_MTU_SIZE) {
- printk(KERN_ERR PFX
- "%s: mtu size of %d is not valid. Use exactly %d or "
- "%d.\n", ndev->name, new_mtu, NORMAL_MTU_SIZE,
- JUMBO_MTU_SIZE);
- return -EINVAL;
- }
-
- if (!netif_running(ndev)) {
- ndev->mtu = new_mtu;
- return 0;
- }
-
- ndev->mtu = new_mtu;
- return ql_cycle_adapter(qdev,QL_DO_RESET);
-}
-
static void ql3xxx_set_multicast_list(struct net_device *ndev)
{
/*
@@ -3609,8 +3754,12 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
}
ndev = alloc_etherdev(sizeof(struct ql3_adapter));
- if (!ndev)
+ if (!ndev) {
+ printk(KERN_ERR PFX "%s could not alloc etherdev\n",
+ pci_name(pdev));
+ err = -ENOMEM;
goto err_out_free_regions;
+ }
SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
@@ -3639,6 +3788,7 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
if (!qdev->mem_map_registers) {
printk(KERN_ERR PFX "%s: cannot map device registers\n",
pci_name(pdev));
+ err = -EIO;
goto err_out_free_ndev;
}
@@ -3650,7 +3800,6 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
ndev->hard_start_xmit = ql3xxx_send;
ndev->stop = ql3xxx_close;
ndev->get_stats = ql3xxx_get_stats;
- ndev->change_mtu = ql3xxx_change_mtu;
ndev->set_multicast_list = ql3xxx_set_multicast_list;
SET_ETHTOOL_OPS(ndev, &ql3xxx_ethtool_ops);
ndev->set_mac_address = ql3xxx_set_mac_address;
@@ -3667,6 +3816,7 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
printk(KERN_ALERT PFX
"ql3xxx_probe: Adapter #%d, Invalid NVRAM parameters.\n",
qdev->index);
+ err = -EIO;
goto err_out_iounmap;
}
@@ -3674,9 +3824,11 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
/* Validate and set parameters */
if (qdev->mac_index) {
+ ndev->mtu = qdev->nvram_data.macCfg_port1.etherMtu_mac ;
memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn2.macAddress,
ETH_ALEN);
} else {
+ ndev->mtu = qdev->nvram_data.macCfg_port0.etherMtu_mac ;
memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn0.macAddress,
ETH_ALEN);
}
diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h
index b2d76ea6882..34cd6580fd0 100755
--- a/drivers/net/qla3xxx.h
+++ b/drivers/net/qla3xxx.h
@@ -1014,13 +1014,15 @@ struct eeprom_data {
/* Transmit and Receive Buffers */
#define NUM_LBUFQ_ENTRIES 128
+#define JUMBO_NUM_LBUFQ_ENTRIES \
+(NUM_LBUFQ_ENTRIES/(JUMBO_MTU_SIZE/NORMAL_MTU_SIZE))
#define NUM_SBUFQ_ENTRIES 64
#define QL_SMALL_BUFFER_SIZE 32
#define QL_ADDR_ELE_PER_BUFQ_ENTRY \
(sizeof(struct lrg_buf_q_entry) / sizeof(struct bufq_addr_element))
/* Each send has at least control block. This is how many we keep. */
#define NUM_SMALL_BUFFERS NUM_SBUFQ_ENTRIES * QL_ADDR_ELE_PER_BUFQ_ENTRY
-#define NUM_LARGE_BUFFERS NUM_LBUFQ_ENTRIES * QL_ADDR_ELE_PER_BUFQ_ENTRY
+
#define QL_HEADER_SPACE 32 /* make header space at top of skb. */
/*
* Large & Small Buffers for Receives
@@ -1092,7 +1094,6 @@ struct oal_entry {
u32 len;
#define OAL_LAST_ENTRY 0x80000000 /* Last valid buffer in list. */
#define OAL_CONT_ENTRY 0x40000000 /* points to an OAL. (continuation) */
- u32 reserved;
};
struct oal {
@@ -1193,7 +1194,7 @@ struct ql3_adapter {
struct net_rsp_iocb *rsp_current;
u16 rsp_consumer_index;
u16 reserved_06;
- u32 *prsp_producer_index;
+ volatile u32 *prsp_producer_index;
u32 rsp_producer_index_phy_addr_high;
u32 rsp_producer_index_phy_addr_low;
@@ -1207,9 +1208,11 @@ struct ql3_adapter {
u32 lrg_buf_q_producer_index;
u32 lrg_buf_release_cnt;
struct bufq_addr_element *lrg_buf_next_free;
+ u32 num_large_buffers;
+ u32 num_lbufq_entries;
/* Large (Receive) Buffers */
- struct ql_rcv_buf_cb lrg_buf[NUM_LARGE_BUFFERS];
+ struct ql_rcv_buf_cb *lrg_buf;
struct ql_rcv_buf_cb *lrg_buf_free_head;
struct ql_rcv_buf_cb *lrg_buf_free_tail;
u32 lrg_buf_free_count;
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 13cf06ee97f..521b5f0618a 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -572,8 +572,8 @@ static void rtl8169_xmii_reset_enable(void __iomem *ioaddr)
{
unsigned int val;
- mdio_write(ioaddr, MII_BMCR, BMCR_RESET);
- val = mdio_read(ioaddr, MII_BMCR);
+ val = mdio_read(ioaddr, MII_BMCR) | BMCR_RESET;
+ mdio_write(ioaddr, MII_BMCR, val & 0xffff);
}
static void rtl8169_check_link_status(struct net_device *dev,
@@ -890,8 +890,7 @@ static void rtl8169_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
unsigned long flags;
spin_lock_irqsave(&tp->lock, flags);
- if (tp->vlgrp)
- tp->vlgrp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(tp->vlgrp, vid, NULL);
spin_unlock_irqrestore(&tp->lock, flags);
}
@@ -1369,11 +1368,7 @@ static inline void rtl8169_request_timer(struct net_device *dev)
(tp->phy_version >= RTL_GIGA_PHY_VER_H))
return;
- init_timer(timer);
- timer->expires = jiffies + RTL8169_PHY_TIMEOUT;
- timer->data = (unsigned long)(dev);
- timer->function = rtl8169_phy_timer;
- add_timer(timer);
+ mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT);
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1686,6 +1681,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->mmio_addr = ioaddr;
tp->align = rtl_cfg_info[ent->driver_data].align;
+ init_timer(&tp->timer);
+ tp->timer.data = (unsigned long) dev;
+ tp->timer.function = rtl8169_phy_timer;
+
spin_lock_init(&tp->lock);
rc = register_netdev(dev);
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index 0e345cbc2bf..33fb7f3b704 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -430,6 +430,7 @@ struct XENA_dev_config {
#define TX_PA_CFG_IGNORE_SNAP_OUI BIT(2)
#define TX_PA_CFG_IGNORE_LLC_CTRL BIT(3)
#define TX_PA_CFG_IGNORE_L2_ERR BIT(6)
+#define RX_PA_CFG_STRIP_VLAN_TAG BIT(15)
/* Recent add, used only debug purposes. */
u64 pcc_enable;
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index fd85648d98d..46ebf141ee5 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -42,6 +42,14 @@
* Possible values '1' for enable '0' for disable. Default is '0'
* lro_max_pkts: This parameter defines maximum number of packets can be
* aggregated as a single large packet
+ * napi: This parameter used to enable/disable NAPI (polling Rx)
+ * Possible values '1' for enable and '0' for disable. Default is '1'
+ * ufo: This parameter used to enable/disable UDP Fragmentation Offload(UFO)
+ * Possible values '1' for enable and '0' for disable. Default is '0'
+ * vlan_tag_strip: This can be used to enable or disable vlan stripping.
+ * Possible values '1' for enable , '0' for disable.
+ * Default is '2' - which means disable in promisc mode
+ * and enable in non-promiscuous mode.
************************************************************************/
#include <linux/module.h>
@@ -76,7 +84,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.16.1"
+#define DRV_VERSION "2.0.17.1"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -131,7 +139,7 @@ static char s2io_gstrings[][ETH_GSTRING_LEN] = {
"BIST Test\t(offline)"
};
-static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
+static char ethtool_xena_stats_keys[][ETH_GSTRING_LEN] = {
{"tmac_frms"},
{"tmac_data_octets"},
{"tmac_drop_frms"},
@@ -225,7 +233,10 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
{"rxd_rd_cnt"},
{"rxd_wr_cnt"},
{"txf_rd_cnt"},
- {"rxf_wr_cnt"},
+ {"rxf_wr_cnt"}
+};
+
+static char ethtool_enhanced_stats_keys[][ETH_GSTRING_LEN] = {
{"rmac_ttl_1519_4095_frms"},
{"rmac_ttl_4096_8191_frms"},
{"rmac_ttl_8192_max_frms"},
@@ -241,7 +252,10 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
{"rmac_red_discard"},
{"rmac_rts_discard"},
{"rmac_ingm_full_discard"},
- {"link_fault_cnt"},
+ {"link_fault_cnt"}
+};
+
+static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = {
{"\n DRIVER STATISTICS"},
{"single_bit_ecc_errs"},
{"double_bit_ecc_errs"},
@@ -269,8 +283,16 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
("lro_avg_aggr_pkts"),
};
-#define S2IO_STAT_LEN sizeof(ethtool_stats_keys)/ ETH_GSTRING_LEN
-#define S2IO_STAT_STRINGS_LEN S2IO_STAT_LEN * ETH_GSTRING_LEN
+#define S2IO_XENA_STAT_LEN sizeof(ethtool_xena_stats_keys)/ ETH_GSTRING_LEN
+#define S2IO_ENHANCED_STAT_LEN sizeof(ethtool_enhanced_stats_keys)/ \
+ ETH_GSTRING_LEN
+#define S2IO_DRIVER_STAT_LEN sizeof(ethtool_driver_stats_keys)/ ETH_GSTRING_LEN
+
+#define XFRAME_I_STAT_LEN (S2IO_XENA_STAT_LEN + S2IO_DRIVER_STAT_LEN )
+#define XFRAME_II_STAT_LEN (XFRAME_I_STAT_LEN + S2IO_ENHANCED_STAT_LEN )
+
+#define XFRAME_I_STAT_STRINGS_LEN ( XFRAME_I_STAT_LEN * ETH_GSTRING_LEN )
+#define XFRAME_II_STAT_STRINGS_LEN ( XFRAME_II_STAT_LEN * ETH_GSTRING_LEN )
#define S2IO_TEST_LEN sizeof(s2io_gstrings) / ETH_GSTRING_LEN
#define S2IO_STRINGS_LEN S2IO_TEST_LEN * ETH_GSTRING_LEN
@@ -293,6 +315,9 @@ static void s2io_vlan_rx_register(struct net_device *dev,
spin_unlock_irqrestore(&nic->tx_lock, flags);
}
+/* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */
+int vlan_strip_flag;
+
/* Unregister the vlan */
static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
{
@@ -300,8 +325,7 @@ static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
unsigned long flags;
spin_lock_irqsave(&nic->tx_lock, flags);
- if (nic->vlgrp)
- nic->vlgrp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(nic->vlgrp, vid, NULL);
spin_unlock_irqrestore(&nic->tx_lock, flags);
}
@@ -404,6 +428,7 @@ S2IO_PARM_INT(indicate_max_pkts, 0);
S2IO_PARM_INT(napi, 1);
S2IO_PARM_INT(ufo, 0);
+S2IO_PARM_INT(vlan_tag_strip, NO_STRIP_IN_PROMISC);
static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
{DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN};
@@ -1371,6 +1396,16 @@ static int init_nic(struct s2io_nic *nic)
&bar0->rts_frm_len_n[i]);
}
}
+
+ /* Disable differentiated services steering logic */
+ for (i = 0; i < 64; i++) {
+ if (rts_ds_steer(nic, i, 0) == FAILURE) {
+ DBG_PRINT(ERR_DBG, "%s: failed rts ds steering",
+ dev->name);
+ DBG_PRINT(ERR_DBG, "set on codepoint %d\n", i);
+ return FAILURE;
+ }
+ }
/* Program statistics memory */
writeq(mac_control->stats_mem_phy, &bar0->stat_addr);
@@ -1943,6 +1978,13 @@ static int start_nic(struct s2io_nic *nic)
writeq(val64, &bar0->rx_pa_cfg);
}
+ if (vlan_tag_strip == 0) {
+ val64 = readq(&bar0->rx_pa_cfg);
+ val64 &= ~RX_PA_CFG_STRIP_VLAN_TAG;
+ writeq(val64, &bar0->rx_pa_cfg);
+ vlan_strip_flag = 0;
+ }
+
/*
* Enabling MC-RLDRAM. After enabling the device, we timeout
* for around 100ms, which is approximately the time required
@@ -3195,26 +3237,37 @@ static void alarm_intr_handler(struct s2io_nic *nic)
* SUCCESS on success and FAILURE on failure.
*/
-static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit)
+static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit,
+ int bit_state)
{
- int ret = FAILURE, cnt = 0;
+ int ret = FAILURE, cnt = 0, delay = 1;
u64 val64;
- while (TRUE) {
+ if ((bit_state != S2IO_BIT_RESET) && (bit_state != S2IO_BIT_SET))
+ return FAILURE;
+
+ do {
val64 = readq(addr);
- if (!(val64 & busy_bit)) {
- ret = SUCCESS;
- break;
+ if (bit_state == S2IO_BIT_RESET) {
+ if (!(val64 & busy_bit)) {
+ ret = SUCCESS;
+ break;
+ }
+ } else {
+ if (!(val64 & busy_bit)) {
+ ret = SUCCESS;
+ break;
+ }
}
if(in_interrupt())
- mdelay(50);
+ mdelay(delay);
else
- msleep(50);
+ msleep(delay);
- if (cnt++ > 10)
- break;
- }
+ if (++cnt >= 10)
+ delay = 50;
+ } while (cnt < 20);
return ret;
}
/*
@@ -3340,6 +3393,9 @@ new_way:
writeq(val64, &bar0->pcc_err_reg);
}
+ /* restore the previously assigned mac address */
+ s2io_set_mac_addr(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr);
+
sp->device_enabled_once = FALSE;
}
@@ -4087,6 +4143,11 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp)
val64 &= ~GPIO_INT_MASK_LINK_UP;
val64 |= GPIO_INT_MASK_LINK_DOWN;
writeq(val64, &bar0->gpio_int_mask);
+
+ /* turn off LED */
+ val64 = readq(&bar0->adapter_control);
+ val64 = val64 &(~ADAPTER_LED_ON);
+ writeq(val64, &bar0->adapter_control);
}
}
val64 = readq(&bar0->gpio_int_mask);
@@ -4296,7 +4357,8 @@ static void s2io_set_multicast(struct net_device *dev)
writeq(val64, &bar0->rmac_addr_cmd_mem);
/* Wait till command completes */
wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
- RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
+ RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
+ S2IO_BIT_RESET);
sp->m_cast_flg = 1;
sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET;
@@ -4312,7 +4374,8 @@ static void s2io_set_multicast(struct net_device *dev)
writeq(val64, &bar0->rmac_addr_cmd_mem);
/* Wait till command completes */
wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
- RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
+ RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
+ S2IO_BIT_RESET);
sp->m_cast_flg = 0;
sp->all_multi_pos = 0;
@@ -4329,6 +4392,13 @@ static void s2io_set_multicast(struct net_device *dev)
writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
writel((u32) (val64 >> 32), (add + 4));
+ if (vlan_tag_strip != 1) {
+ val64 = readq(&bar0->rx_pa_cfg);
+ val64 &= ~RX_PA_CFG_STRIP_VLAN_TAG;
+ writeq(val64, &bar0->rx_pa_cfg);
+ vlan_strip_flag = 0;
+ }
+
val64 = readq(&bar0->mac_cfg);
sp->promisc_flg = 1;
DBG_PRINT(INFO_DBG, "%s: entered promiscuous mode\n",
@@ -4344,6 +4414,13 @@ static void s2io_set_multicast(struct net_device *dev)
writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
writel((u32) (val64 >> 32), (add + 4));
+ if (vlan_tag_strip != 0) {
+ val64 = readq(&bar0->rx_pa_cfg);
+ val64 |= RX_PA_CFG_STRIP_VLAN_TAG;
+ writeq(val64, &bar0->rx_pa_cfg);
+ vlan_strip_flag = 1;
+ }
+
val64 = readq(&bar0->mac_cfg);
sp->promisc_flg = 0;
DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n",
@@ -4378,7 +4455,8 @@ static void s2io_set_multicast(struct net_device *dev)
/* Wait for command completes */
if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
- RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
+ RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
+ S2IO_BIT_RESET)) {
DBG_PRINT(ERR_DBG, "%s: Adding ",
dev->name);
DBG_PRINT(ERR_DBG, "Multicasts failed\n");
@@ -4409,7 +4487,8 @@ static void s2io_set_multicast(struct net_device *dev)
/* Wait for command completes */
if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
- RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
+ RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
+ S2IO_BIT_RESET)) {
DBG_PRINT(ERR_DBG, "%s: Adding ",
dev->name);
DBG_PRINT(ERR_DBG, "Multicasts failed\n");
@@ -4435,6 +4514,7 @@ static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
struct XENA_dev_config __iomem *bar0 = sp->bar0;
register u64 val64, mac_addr = 0;
int i;
+ u64 old_mac_addr = 0;
/*
* Set the new MAC address as the new unicast filter and reflect this
@@ -4444,6 +4524,22 @@ static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
for (i = 0; i < ETH_ALEN; i++) {
mac_addr <<= 8;
mac_addr |= addr[i];
+ old_mac_addr <<= 8;
+ old_mac_addr |= sp->def_mac_addr[0].mac_addr[i];
+ }
+
+ if(0 == mac_addr)
+ return SUCCESS;
+
+ /* Update the internal structure with this new mac address */
+ if(mac_addr != old_mac_addr) {
+ memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN));
+ sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_addr);
+ sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_addr >> 8);
+ sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_addr >> 16);
+ sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_addr >> 24);
+ sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_addr >> 32);
+ sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_addr >> 40);
}
writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
@@ -4455,7 +4551,7 @@ static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
writeq(val64, &bar0->rmac_addr_cmd_mem);
/* Wait till command completes */
if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
- RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) {
+ RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET)) {
DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name);
return FAILURE;
}
@@ -4546,7 +4642,11 @@ static void s2io_ethtool_gdrvinfo(struct net_device *dev,
info->regdump_len = XENA_REG_SPACE;
info->eedump_len = XENA_EEPROM_SPACE;
info->testinfo_len = S2IO_TEST_LEN;
- info->n_stats = S2IO_STAT_LEN;
+
+ if (sp->device_type == XFRAME_I_DEVICE)
+ info->n_stats = XFRAME_I_STAT_LEN;
+ else
+ info->n_stats = XFRAME_II_STAT_LEN;
}
/**
@@ -5568,22 +5668,30 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
tmp_stats[i++] = le32_to_cpu(stat_info->rxd_wr_cnt);
tmp_stats[i++] = le32_to_cpu(stat_info->txf_rd_cnt);
tmp_stats[i++] = le32_to_cpu(stat_info->rxf_wr_cnt);
- tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms);
- tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms);
- tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_8192_max_frms);
- tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_gt_max_frms);
- tmp_stats[i++] = le64_to_cpu(stat_info->rmac_osized_alt_frms);
- tmp_stats[i++] = le64_to_cpu(stat_info->rmac_jabber_alt_frms);
- tmp_stats[i++] = le64_to_cpu(stat_info->rmac_gt_max_alt_frms);
- tmp_stats[i++] = le64_to_cpu(stat_info->rmac_vlan_frms);
- tmp_stats[i++] = le32_to_cpu(stat_info->rmac_len_discard);
- tmp_stats[i++] = le32_to_cpu(stat_info->rmac_fcs_discard);
- tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pf_discard);
- tmp_stats[i++] = le32_to_cpu(stat_info->rmac_da_discard);
- tmp_stats[i++] = le32_to_cpu(stat_info->rmac_red_discard);
- tmp_stats[i++] = le32_to_cpu(stat_info->rmac_rts_discard);
- tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ingm_full_discard);
- tmp_stats[i++] = le32_to_cpu(stat_info->link_fault_cnt);
+
+ /* Enhanced statistics exist only for Hercules */
+ if(sp->device_type == XFRAME_II_DEVICE) {
+ tmp_stats[i++] =
+ le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms);
+ tmp_stats[i++] =
+ le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms);
+ tmp_stats[i++] =
+ le64_to_cpu(stat_info->rmac_ttl_8192_max_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_gt_max_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_osized_alt_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_jabber_alt_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_gt_max_alt_frms);
+ tmp_stats[i++] = le64_to_cpu(stat_info->rmac_vlan_frms);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rmac_len_discard);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rmac_fcs_discard);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pf_discard);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rmac_da_discard);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rmac_red_discard);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rmac_rts_discard);
+ tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ingm_full_discard);
+ tmp_stats[i++] = le32_to_cpu(stat_info->link_fault_cnt);
+ }
+
tmp_stats[i++] = 0;
tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs;
tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs;
@@ -5663,18 +5771,42 @@ static int s2io_ethtool_self_test_count(struct net_device *dev)
static void s2io_ethtool_get_strings(struct net_device *dev,
u32 stringset, u8 * data)
{
+ int stat_size = 0;
+ struct s2io_nic *sp = dev->priv;
+
switch (stringset) {
case ETH_SS_TEST:
memcpy(data, s2io_gstrings, S2IO_STRINGS_LEN);
break;
case ETH_SS_STATS:
- memcpy(data, &ethtool_stats_keys,
- sizeof(ethtool_stats_keys));
+ stat_size = sizeof(ethtool_xena_stats_keys);
+ memcpy(data, &ethtool_xena_stats_keys,stat_size);
+ if(sp->device_type == XFRAME_II_DEVICE) {
+ memcpy(data + stat_size,
+ &ethtool_enhanced_stats_keys,
+ sizeof(ethtool_enhanced_stats_keys));
+ stat_size += sizeof(ethtool_enhanced_stats_keys);
+ }
+
+ memcpy(data + stat_size, &ethtool_driver_stats_keys,
+ sizeof(ethtool_driver_stats_keys));
}
}
static int s2io_ethtool_get_stats_count(struct net_device *dev)
{
- return (S2IO_STAT_LEN);
+ struct s2io_nic *sp = dev->priv;
+ int stat_count = 0;
+ switch(sp->device_type) {
+ case XFRAME_I_DEVICE:
+ stat_count = XFRAME_I_STAT_LEN;
+ break;
+
+ case XFRAME_II_DEVICE:
+ stat_count = XFRAME_II_STAT_LEN;
+ break;
+ }
+
+ return stat_count;
}
static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
@@ -5909,7 +6041,7 @@ static void s2io_set_link(struct work_struct *work)
clear_bit(0, &(nic->link_state));
out_unlock:
- rtnl_lock();
+ rtnl_unlock();
}
static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
@@ -6066,10 +6198,13 @@ static int rxd_owner_bit_reset(struct s2io_nic *sp)
rx_blocks[j].rxds[k].virt_addr;
if(sp->rxd_mode >= RXD_MODE_3A)
ba = &mac_control->rings[i].ba[j][k];
- set_rxd_buffer_pointer(sp, rxdp, ba,
+ if (set_rxd_buffer_pointer(sp, rxdp, ba,
&skb,(u64 *)&temp0_64,
(u64 *)&temp1_64,
- (u64 *)&temp2_64, size);
+ (u64 *)&temp2_64,
+ size) == ENOMEM) {
+ return 0;
+ }
set_rxd_buffer_size(sp, rxdp, size);
wmb();
@@ -6112,7 +6247,7 @@ static int s2io_add_isr(struct s2io_nic * sp)
}
}
if (sp->intr_type == MSI_X) {
- int i;
+ 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) {
@@ -6121,16 +6256,36 @@ static int s2io_add_isr(struct s2io_nic * sp)
err = request_irq(sp->entries[i].vector,
s2io_msix_fifo_handle, 0, sp->desc[i],
sp->s2io_entries[i].arg);
- DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc[i],
- (unsigned long long)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%lx\n",sp->desc[i],
+ (unsigned long long)
+ sp->msix_info[i].addr,
+ (unsigned long)
+ ntohl(sp->msix_info[i].data));
+ } else {
+ msix_tx_cnt++;
+ }
} 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);
- DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc[i],
- (unsigned long long)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%lx\n",sp->desc[i],
+ (unsigned long long)
+ sp->msix_info[i].addr,
+ (unsigned long)
+ ntohl(sp->msix_info[i].data));
+ } else {
+ msix_rx_cnt++;
+ }
}
if (err) {
DBG_PRINT(ERR_DBG,"%s:MSI-X-%d registration "
@@ -6140,6 +6295,8 @@ static int s2io_add_isr(struct s2io_nic * sp)
}
sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
}
+ printk("MSI-X-TX %d entries enabled\n",msix_tx_cnt);
+ printk("MSI-X-RX %d entries enabled\n",msix_rx_cnt);
}
if (sp->intr_type == INTA) {
err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
@@ -6567,7 +6724,8 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
if (!sp->lro) {
skb->protocol = eth_type_trans(skb, dev);
- if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
+ if ((sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2) &&
+ vlan_strip_flag)) {
/* Queueing the vlan frame to the upper layer */
if (napi)
vlan_hwaccel_receive_skb(skb, sp->vlgrp,
@@ -6704,8 +6862,7 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
"Defaulting to INTA\n");
*dev_intr_type = INTA;
}
- if ( (rx_ring_num > 1) && (*dev_intr_type != INTA) )
- napi = 0;
+
if (rx_ring_mode > 3) {
DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n");
DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n");
@@ -6715,6 +6872,37 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
}
/**
+ * rts_ds_steer - Receive traffic steering based on IPv4 or IPv6 TOS
+ * or Traffic class respectively.
+ * @nic: device peivate variable
+ * Description: The function configures the receive steering to
+ * desired receive ring.
+ * Return Value: SUCCESS on success and
+ * '-1' on failure (endian settings incorrect).
+ */
+static int rts_ds_steer(struct s2io_nic *nic, u8 ds_codepoint, u8 ring)
+{
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
+ register u64 val64 = 0;
+
+ if (ds_codepoint > 63)
+ return FAILURE;
+
+ val64 = RTS_DS_MEM_DATA(ring);
+ writeq(val64, &bar0->rts_ds_mem_data);
+
+ val64 = RTS_DS_MEM_CTRL_WE |
+ RTS_DS_MEM_CTRL_STROBE_NEW_CMD |
+ RTS_DS_MEM_CTRL_OFFSET(ds_codepoint);
+
+ writeq(val64, &bar0->rts_ds_mem_ctrl);
+
+ return wait_for_cmd_complete(&bar0->rts_ds_mem_ctrl,
+ RTS_DS_MEM_CTRL_STROBE_CMD_BEING_EXECUTED,
+ S2IO_BIT_RESET);
+}
+
+/**
* s2io_init_nic - Initialization of the adapter .
* @pdev : structure containing the PCI related information of the device.
* @pre: List of PCI devices supported by the driver listed in s2io_tbl.
@@ -7008,13 +7196,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET);
writeq(val64, &bar0->rmac_addr_cmd_mem);
wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
- RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING);
+ RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET);
tmp64 = readq(&bar0->rmac_addr_data0_mem);
mac_down = (u32) tmp64;
mac_up = (u32) (tmp64 >> 32);
- memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN));
-
sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_up);
sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_up >> 8);
sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_up >> 16);
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 0de0c65f945..803137ca4b6 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -32,7 +32,8 @@
#define FAILURE -1
#define S2IO_MINUS_ONE 0xFFFFFFFFFFFFFFFFULL
#define S2IO_MAX_PCI_CONFIG_SPACE_REINIT 100
-
+#define S2IO_BIT_RESET 1
+#define S2IO_BIT_SET 2
#define CHECKBIT(value, nbit) (value & (1 << nbit))
/* Maximum time to flicker LED when asked to identify NIC using ethtool */
@@ -296,6 +297,9 @@ struct stat_block {
struct xpakStat xpak_stat;
};
+/* Default value for 'vlan_strip_tag' configuration parameter */
+#define NO_STRIP_IN_PROMISC 2
+
/*
* Structures representing different init time configuration
* parameters of the NIC.
@@ -1005,7 +1009,8 @@ static int s2io_set_swapper(struct s2io_nic * sp);
static void s2io_card_down(struct s2io_nic *nic);
static int s2io_card_up(struct s2io_nic *nic);
static int get_xena_rev_id(struct pci_dev *pdev);
-static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit);
+static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit,
+ int bit_state);
static int s2io_add_isr(struct s2io_nic * sp);
static void s2io_rem_isr(struct s2io_nic * sp);
@@ -1019,6 +1024,7 @@ static void queue_rx_frame(struct sk_buff *skb);
static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro);
static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
struct sk_buff *skb, u32 tcp_len);
+static int rts_ds_steer(struct s2io_nic *nic, u8 ds_codepoint, u8 ring);
#define s2io_tcp_mss(skb) skb_shinfo(skb)->gso_size
#define s2io_udp_mss(skb) skb_shinfo(skb)->gso_size
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index a833e7f9757..52ed522a234 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -12,26 +12,15 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/route.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-#include <linux/bitops.h>
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
#include <asm/sgi/hpc3.h>
#include <asm/sgi/ip22.h>
-#include <asm/sgialib.h>
#include "sgiseeq.h"
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index fb2b5305163..b3750f28427 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -968,10 +968,10 @@ static void mdio_write(struct net_device *net_dev, int phy_id, int location,
static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr)
{
- int i = 0;
+ int i;
u16 status;
- while (i++ < 2)
+ for (i = 0; i < 2; i++)
status = mdio_read(net_dev, phy_addr, MII_STATUS);
mdio_write( net_dev, phy_addr, MII_CONTROL, MII_CNTL_RESET );
@@ -1430,7 +1430,7 @@ static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr)
int i = 0;
u32 status;
- while (i++ < 2)
+ for (i = 0; i < 2; i++)
status = mdio_read(net_dev, phy_addr, MII_STATUS);
if (!(status & MII_STAT_LINK)){
@@ -1466,9 +1466,9 @@ static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex
int phy_addr = sis_priv->cur_phy;
u32 status;
u16 autoadv, autorec;
- int i = 0;
+ int i;
- while (i++ < 2)
+ for (i = 0; i < 2; i++)
status = mdio_read(net_dev, phy_addr, MII_STATUS);
if (!(status & MII_STAT_LINK))
diff --git a/drivers/net/skfp/cfm.c b/drivers/net/skfp/cfm.c
index 4c8aaa76233..5310d39b573 100644
--- a/drivers/net/skfp/cfm.c
+++ b/drivers/net/skfp/cfm.c
@@ -73,7 +73,7 @@ static const char * const cfm_events[] = {
/*
* map from state to downstream port type
*/
-static const u_char cf_to_ptype[] = {
+static const unsigned char cf_to_ptype[] = {
TNONE,TNONE,TNONE,TNONE,TNONE,
TNONE,TB,TB,TS,
TA,TB,TS,TB
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index c3d2e0a2c4e..eea75a401b0 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -77,13 +77,13 @@ static const struct pci_device_id skge_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B) },
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) },
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU) },
- { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T), },
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T) },
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b01) }, /* DGE-530T */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */
{ PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) },
{ PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064) },
- { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015, },
+ { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, skge_id_table);
@@ -2767,6 +2767,17 @@ static int skge_change_mtu(struct net_device *dev, int new_mtu)
return err;
}
+static const u8 pause_mc_addr[ETH_ALEN] = { 0x1, 0x80, 0xc2, 0x0, 0x0, 0x1 };
+
+static void genesis_add_filter(u8 filter[8], const u8 *addr)
+{
+ u32 crc, bit;
+
+ crc = ether_crc_le(ETH_ALEN, addr);
+ bit = ~crc & 0x3f;
+ filter[bit/8] |= 1 << (bit%8);
+}
+
static void genesis_set_multicast(struct net_device *dev)
{
struct skge_port *skge = netdev_priv(dev);
@@ -2788,24 +2799,33 @@ static void genesis_set_multicast(struct net_device *dev)
memset(filter, 0xff, sizeof(filter));
else {
memset(filter, 0, sizeof(filter));
- for (i = 0; list && i < count; i++, list = list->next) {
- u32 crc, bit;
- crc = ether_crc_le(ETH_ALEN, list->dmi_addr);
- bit = ~crc & 0x3f;
- filter[bit/8] |= 1 << (bit%8);
- }
+
+ if (skge->flow_status == FLOW_STAT_REM_SEND
+ || skge->flow_status == FLOW_STAT_SYMMETRIC)
+ genesis_add_filter(filter, pause_mc_addr);
+
+ for (i = 0; list && i < count; i++, list = list->next)
+ genesis_add_filter(filter, list->dmi_addr);
}
xm_write32(hw, port, XM_MODE, mode);
xm_outhash(hw, port, XM_HSM, filter);
}
+static void yukon_add_filter(u8 filter[8], const u8 *addr)
+{
+ u32 bit = ether_crc(ETH_ALEN, addr) & 0x3f;
+ filter[bit/8] |= 1 << (bit%8);
+}
+
static void yukon_set_multicast(struct net_device *dev)
{
struct skge_port *skge = netdev_priv(dev);
struct skge_hw *hw = skge->hw;
int port = skge->port;
struct dev_mc_list *list = dev->mc_list;
+ int rx_pause = (skge->flow_status == FLOW_STAT_REM_SEND
+ || skge->flow_status == FLOW_STAT_SYMMETRIC);
u16 reg;
u8 filter[8];
@@ -2818,16 +2838,17 @@ static void yukon_set_multicast(struct net_device *dev)
reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
else if (dev->flags & IFF_ALLMULTI) /* all multicast */
memset(filter, 0xff, sizeof(filter));
- else if (dev->mc_count == 0) /* no multicast */
+ else if (dev->mc_count == 0 && !rx_pause)/* no multicast */
reg &= ~GM_RXCR_MCF_ENA;
else {
int i;
reg |= GM_RXCR_MCF_ENA;
- for (i = 0; list && i < dev->mc_count; i++, list = list->next) {
- u32 bit = ether_crc(ETH_ALEN, list->dmi_addr) & 0x3f;
- filter[bit/8] |= 1 << (bit%8);
- }
+ if (rx_pause)
+ yukon_add_filter(filter, pause_mc_addr);
+
+ for (i = 0; list && i < dev->mc_count; i++, list = list->next)
+ yukon_add_filter(filter, list->dmi_addr);
}
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index 17b1b479dff..e9354dfa7e9 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -1849,8 +1849,7 @@ enum {
GMR_FS_JABBER,
/* Rx GMAC FIFO Flush Mask (default) */
RX_FF_FL_DEF_MSK = GMR_FS_CRC_ERR | GMR_FS_RX_FF_OV |GMR_FS_MII_ERR |
- GMR_FS_BAD_FC | GMR_FS_GOOD_FC | GMR_FS_UN_SIZE |
- GMR_FS_JABBER,
+ GMR_FS_BAD_FC | GMR_FS_UN_SIZE | GMR_FS_JABBER,
};
/* RX_GMF_CTRL_T 32 bit Rx GMAC FIFO Control/Test */
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 52edbd7ac17..ab0ab92583f 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -1053,8 +1053,7 @@ static void sky2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_OFF);
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_OFF);
- if (sky2->vlgrp)
- sky2->vlgrp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(sky2->vlgrp, vid, NULL);
netif_tx_unlock_bh(dev);
}
@@ -2166,9 +2165,27 @@ force_update:
/* fall through */
#endif
case OP_RXCHKS:
- skb = sky2->rx_ring[sky2->rx_next].skb;
- skb->ip_summed = CHECKSUM_COMPLETE;
- skb->csum = status & 0xffff;
+ if (!sky2->rx_csum)
+ break;
+
+ /* Both checksum counters are programmed to start at
+ * the same offset, so unless there is a problem they
+ * should match. This failure is an early indication that
+ * hardware receive checksumming won't work.
+ */
+ if (likely(status >> 16 == (status & 0xffff))) {
+ skb = sky2->rx_ring[sky2->rx_next].skb;
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ skb->csum = status & 0xffff;
+ } else {
+ printk(KERN_NOTICE PFX "%s: hardware receive "
+ "checksum problem (status = %#x)\n",
+ dev->name, status);
+ sky2->rx_csum = 0;
+ sky2_write32(sky2->hw,
+ Q_ADDR(rxqaddr[le->link], Q_CSR),
+ BMU_DIS_RX_CHKSUM);
+ }
break;
case OP_TXINDEXLE:
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 64ed8ff5b03..3b91af89e4c 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -1,7 +1,8 @@
/*
- * Network device driver for Cell Processor-Based Blade
+ * Network device driver for Cell Processor-Based Blade and Celleb platform
*
* (C) Copyright IBM Corp. 2005
+ * (C) Copyright 2006 TOSHIBA CORPORATION
*
* Authors : Utz Bacher <utz.bacher@de.ibm.com>
* Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
@@ -166,6 +167,41 @@ spider_net_read_phy(struct net_device *netdev, int mii_id, int reg)
}
/**
+ * spider_net_setup_aneg - initial auto-negotiation setup
+ * @card: device structure
+ **/
+static void
+spider_net_setup_aneg(struct spider_net_card *card)
+{
+ struct mii_phy *phy = &card->phy;
+ u32 advertise = 0;
+ u16 bmcr, bmsr, stat1000, estat;
+
+ bmcr = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMCR);
+ bmsr = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR);
+ stat1000 = spider_net_read_phy(card->netdev, phy->mii_id, MII_STAT1000);
+ estat = spider_net_read_phy(card->netdev, phy->mii_id, MII_ESTATUS);
+
+ if (bmsr & BMSR_10HALF)
+ advertise |= ADVERTISED_10baseT_Half;
+ if (bmsr & BMSR_10FULL)
+ advertise |= ADVERTISED_10baseT_Full;
+ if (bmsr & BMSR_100HALF)
+ advertise |= ADVERTISED_100baseT_Half;
+ if (bmsr & BMSR_100FULL)
+ advertise |= ADVERTISED_100baseT_Full;
+
+ if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_TFULL))
+ advertise |= SUPPORTED_1000baseT_Full;
+ if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_THALF))
+ advertise |= SUPPORTED_1000baseT_Half;
+
+ mii_phy_probe(phy, phy->mii_id);
+ phy->def->ops->setup_aneg(phy, advertise);
+
+}
+
+/**
* spider_net_rx_irq_off - switch off rx irq on this spider card
* @card: device structure
*
@@ -263,9 +299,9 @@ spider_net_get_mac_address(struct net_device *netdev)
* returns the status as in the dmac_cmd_status field of the descriptor
*/
static inline int
-spider_net_get_descr_status(struct spider_net_descr *descr)
+spider_net_get_descr_status(struct spider_net_hw_descr *hwdescr)
{
- return descr->dmac_cmd_status & SPIDER_NET_DESCR_IND_PROC_MASK;
+ return hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_IND_PROC_MASK;
}
/**
@@ -283,12 +319,12 @@ spider_net_free_chain(struct spider_net_card *card,
descr = chain->ring;
do {
descr->bus_addr = 0;
- descr->next_descr_addr = 0;
+ descr->hwdescr->next_descr_addr = 0;
descr = descr->next;
} while (descr != chain->ring);
dma_free_coherent(&card->pdev->dev, chain->num_desc,
- chain->ring, chain->dma_addr);
+ chain->hwring, chain->dma_addr);
}
/**
@@ -307,31 +343,34 @@ spider_net_init_chain(struct spider_net_card *card,
{
int i;
struct spider_net_descr *descr;
+ struct spider_net_hw_descr *hwdescr;
dma_addr_t buf;
size_t alloc_size;
- alloc_size = chain->num_desc * sizeof (struct spider_net_descr);
+ alloc_size = chain->num_desc * sizeof(struct spider_net_hw_descr);
- chain->ring = dma_alloc_coherent(&card->pdev->dev, alloc_size,
+ chain->hwring = dma_alloc_coherent(&card->pdev->dev, alloc_size,
&chain->dma_addr, GFP_KERNEL);
- if (!chain->ring)
+ if (!chain->hwring)
return -ENOMEM;
- descr = chain->ring;
- memset(descr, 0, alloc_size);
+ memset(chain->ring, 0, chain->num_desc * sizeof(struct spider_net_descr));
/* Set up the hardware pointers in each descriptor */
+ descr = chain->ring;
+ hwdescr = chain->hwring;
buf = chain->dma_addr;
- for (i=0; i < chain->num_desc; i++, descr++) {
- descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+ for (i=0; i < chain->num_desc; i++, descr++, hwdescr++) {
+ hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+ hwdescr->next_descr_addr = 0;
+ descr->hwdescr = hwdescr;
descr->bus_addr = buf;
- descr->next_descr_addr = 0;
descr->next = descr + 1;
descr->prev = descr - 1;
- buf += sizeof(struct spider_net_descr);
+ buf += sizeof(struct spider_net_hw_descr);
}
/* do actual circular list */
(descr-1)->next = chain->ring;
@@ -357,10 +396,11 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card)
descr = card->rx_chain.head;
do {
if (descr->skb) {
- dev_kfree_skb(descr->skb);
- pci_unmap_single(card->pdev, descr->buf_addr,
+ pci_unmap_single(card->pdev, descr->hwdescr->buf_addr,
SPIDER_NET_MAX_FRAME,
PCI_DMA_BIDIRECTIONAL);
+ dev_kfree_skb(descr->skb);
+ descr->skb = NULL;
}
descr = descr->next;
} while (descr != card->rx_chain.head);
@@ -380,6 +420,7 @@ static int
spider_net_prepare_rx_descr(struct spider_net_card *card,
struct spider_net_descr *descr)
{
+ struct spider_net_hw_descr *hwdescr = descr->hwdescr;
dma_addr_t buf;
int offset;
int bufsize;
@@ -398,11 +439,11 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
card->spider_stats.alloc_rx_skb_error++;
return -ENOMEM;
}
- descr->buf_size = bufsize;
- descr->result_size = 0;
- descr->valid_size = 0;
- descr->data_status = 0;
- descr->data_error = 0;
+ hwdescr->buf_size = bufsize;
+ hwdescr->result_size = 0;
+ hwdescr->valid_size = 0;
+ hwdescr->data_status = 0;
+ hwdescr->data_error = 0;
offset = ((unsigned long)descr->skb->data) &
(SPIDER_NET_RXBUF_ALIGN - 1);
@@ -411,21 +452,22 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
/* iommu-map the skb */
buf = pci_map_single(card->pdev, descr->skb->data,
SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
- descr->buf_addr = buf;
if (pci_dma_mapping_error(buf)) {
dev_kfree_skb_any(descr->skb);
+ descr->skb = NULL;
if (netif_msg_rx_err(card) && net_ratelimit())
pr_err("Could not iommu-map rx buffer\n");
card->spider_stats.rx_iommu_map_error++;
- descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+ hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
} else {
- descr->next_descr_addr = 0;
+ hwdescr->buf_addr = buf;
+ hwdescr->next_descr_addr = 0;
wmb();
- descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |
+ hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |
SPIDER_NET_DMAC_NOINTR_COMPLETE;
wmb();
- descr->prev->next_descr_addr = descr->bus_addr;
+ descr->prev->hwdescr->next_descr_addr = descr->bus_addr;
}
return 0;
@@ -481,7 +523,7 @@ spider_net_refill_rx_chain(struct spider_net_card *card)
if (!spin_trylock_irqsave(&chain->lock, flags))
return;
- while (spider_net_get_descr_status(chain->head) ==
+ while (spider_net_get_descr_status(chain->head->hwdescr) ==
SPIDER_NET_DESCR_NOT_IN_USE) {
if (spider_net_prepare_rx_descr(card, chain->head))
break;
@@ -642,7 +684,9 @@ static int
spider_net_prepare_tx_descr(struct spider_net_card *card,
struct sk_buff *skb)
{
+ struct spider_net_descr_chain *chain = &card->tx_chain;
struct spider_net_descr *descr;
+ struct spider_net_hw_descr *hwdescr;
dma_addr_t buf;
unsigned long flags;
@@ -655,32 +699,39 @@ spider_net_prepare_tx_descr(struct spider_net_card *card,
return -ENOMEM;
}
- spin_lock_irqsave(&card->tx_chain.lock, flags);
+ spin_lock_irqsave(&chain->lock, flags);
descr = card->tx_chain.head;
- card->tx_chain.head = descr->next;
+ if (descr->next == chain->tail->prev) {
+ spin_unlock_irqrestore(&chain->lock, flags);
+ pci_unmap_single(card->pdev, buf, skb->len, PCI_DMA_TODEVICE);
+ return -ENOMEM;
+ }
+ hwdescr = descr->hwdescr;
+ chain->head = descr->next;
- descr->buf_addr = buf;
- descr->buf_size = skb->len;
- descr->next_descr_addr = 0;
descr->skb = skb;
- descr->data_status = 0;
+ hwdescr->buf_addr = buf;
+ hwdescr->buf_size = skb->len;
+ hwdescr->next_descr_addr = 0;
+ hwdescr->data_status = 0;
- descr->dmac_cmd_status =
+ hwdescr->dmac_cmd_status =
SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS;
- spin_unlock_irqrestore(&card->tx_chain.lock, flags);
+ spin_unlock_irqrestore(&chain->lock, flags);
if (skb->protocol == htons(ETH_P_IP))
switch (skb->nh.iph->protocol) {
case IPPROTO_TCP:
- descr->dmac_cmd_status |= SPIDER_NET_DMAC_TCP;
+ hwdescr->dmac_cmd_status |= SPIDER_NET_DMAC_TCP;
break;
case IPPROTO_UDP:
- descr->dmac_cmd_status |= SPIDER_NET_DMAC_UDP;
+ hwdescr->dmac_cmd_status |= SPIDER_NET_DMAC_UDP;
break;
}
/* Chain the bus address, so that the DMA engine finds this descr. */
- descr->prev->next_descr_addr = descr->bus_addr;
+ wmb();
+ descr->prev->hwdescr->next_descr_addr = descr->bus_addr;
card->netdev->trans_start = jiffies; /* set netdev watchdog timer */
return 0;
@@ -689,16 +740,17 @@ spider_net_prepare_tx_descr(struct spider_net_card *card,
static int
spider_net_set_low_watermark(struct spider_net_card *card)
{
+ struct spider_net_descr *descr = card->tx_chain.tail;
+ struct spider_net_hw_descr *hwdescr;
unsigned long flags;
int status;
int cnt=0;
int i;
- struct spider_net_descr *descr = card->tx_chain.tail;
/* Measure the length of the queue. Measurement does not
* need to be precise -- does not need a lock. */
while (descr != card->tx_chain.head) {
- status = descr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE;
+ status = descr->hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE;
if (status == SPIDER_NET_DESCR_NOT_IN_USE)
break;
descr = descr->next;
@@ -717,10 +769,12 @@ spider_net_set_low_watermark(struct spider_net_card *card)
/* Set the new watermark, clear the old watermark */
spin_lock_irqsave(&card->tx_chain.lock, flags);
- descr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG;
- if (card->low_watermark && card->low_watermark != descr)
- card->low_watermark->dmac_cmd_status =
- card->low_watermark->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG;
+ descr->hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG;
+ if (card->low_watermark && card->low_watermark != descr) {
+ hwdescr = card->low_watermark->hwdescr;
+ hwdescr->dmac_cmd_status =
+ hwdescr->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG;
+ }
card->low_watermark = descr;
spin_unlock_irqrestore(&card->tx_chain.lock, flags);
return cnt;
@@ -743,16 +797,22 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
{
struct spider_net_descr_chain *chain = &card->tx_chain;
struct spider_net_descr *descr;
+ struct spider_net_hw_descr *hwdescr;
struct sk_buff *skb;
u32 buf_addr;
unsigned long flags;
int status;
- while (chain->tail != chain->head) {
+ while (1) {
spin_lock_irqsave(&chain->lock, flags);
+ if (chain->tail == chain->head) {
+ spin_unlock_irqrestore(&chain->lock, flags);
+ return 0;
+ }
descr = chain->tail;
+ hwdescr = descr->hwdescr;
- status = spider_net_get_descr_status(descr);
+ status = spider_net_get_descr_status(hwdescr);
switch (status) {
case SPIDER_NET_DESCR_COMPLETE:
card->netdev_stats.tx_packets++;
@@ -788,9 +848,10 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
}
chain->tail = descr->next;
- descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
+ hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
skb = descr->skb;
- buf_addr = descr->buf_addr;
+ descr->skb = NULL;
+ buf_addr = hwdescr->buf_addr;
spin_unlock_irqrestore(&chain->lock, flags);
/* unmap the skb */
@@ -826,7 +887,7 @@ spider_net_kick_tx_dma(struct spider_net_card *card)
descr = card->tx_chain.tail;
for (;;) {
- if (spider_net_get_descr_status(descr) ==
+ if (spider_net_get_descr_status(descr->hwdescr) ==
SPIDER_NET_DESCR_CARDOWNED) {
spider_net_write_reg(card, SPIDER_NET_GDTDCHA,
descr->bus_addr);
@@ -855,13 +916,10 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev)
{
int cnt;
struct spider_net_card *card = netdev_priv(netdev);
- struct spider_net_descr_chain *chain = &card->tx_chain;
spider_net_release_tx_chain(card, 0);
- if ((chain->head->next == chain->tail->prev) ||
- (spider_net_prepare_tx_descr(card, skb) != 0)) {
-
+ if (spider_net_prepare_tx_descr(card, skb) != 0) {
card->netdev_stats.tx_dropped++;
netif_stop_queue(netdev);
return NETDEV_TX_BUSY;
@@ -922,17 +980,18 @@ static void
spider_net_pass_skb_up(struct spider_net_descr *descr,
struct spider_net_card *card)
{
+ struct spider_net_hw_descr *hwdescr= descr->hwdescr;
struct sk_buff *skb;
struct net_device *netdev;
u32 data_status, data_error;
- data_status = descr->data_status;
- data_error = descr->data_error;
+ data_status = hwdescr->data_status;
+ data_error = hwdescr->data_error;
netdev = card->netdev;
skb = descr->skb;
skb->dev = netdev;
- skb_put(skb, descr->valid_size);
+ skb_put(skb, hwdescr->valid_size);
/* the card seems to add 2 bytes of junk in front
* of the ethernet frame */
@@ -994,23 +1053,25 @@ static void show_rx_chain(struct spider_net_card *card)
#endif
/**
- * spider_net_decode_one_descr - processes an rx descriptor
+ * spider_net_decode_one_descr - processes an RX descriptor
* @card: card structure
*
- * Returns 1 if a packet has been sent to the stack, otherwise 0
+ * Returns 1 if a packet has been sent to the stack, otherwise 0.
*
- * Processes an rx descriptor by iommu-unmapping the data buffer and passing
- * the packet up to the stack. This function is called in softirq
- * context, e.g. either bottom half from interrupt or NAPI polling context
+ * Processes an RX descriptor by iommu-unmapping the data buffer
+ * and passing the packet up to the stack. This function is called
+ * in softirq context, e.g. either bottom half from interrupt or
+ * NAPI polling context.
*/
static int
spider_net_decode_one_descr(struct spider_net_card *card)
{
struct spider_net_descr_chain *chain = &card->rx_chain;
struct spider_net_descr *descr = chain->tail;
+ struct spider_net_hw_descr *hwdescr = descr->hwdescr;
int status;
- status = spider_net_get_descr_status(descr);
+ status = spider_net_get_descr_status(hwdescr);
/* Nothing in the descriptor, or ring must be empty */
if ((status == SPIDER_NET_DESCR_CARDOWNED) ||
@@ -1021,7 +1082,7 @@ spider_net_decode_one_descr(struct spider_net_card *card)
chain->tail = descr->next;
/* unmap descriptor */
- pci_unmap_single(card->pdev, descr->buf_addr,
+ pci_unmap_single(card->pdev, hwdescr->buf_addr,
SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) ||
@@ -1037,34 +1098,33 @@ spider_net_decode_one_descr(struct spider_net_card *card)
if ( (status != SPIDER_NET_DESCR_COMPLETE) &&
(status != SPIDER_NET_DESCR_FRAME_END) ) {
if (netif_msg_rx_err(card))
- pr_err("%s: RX descriptor with unkown state %d\n",
+ pr_err("%s: RX descriptor with unknown state %d\n",
card->netdev->name, status);
card->spider_stats.rx_desc_unk_state++;
goto bad_desc;
}
/* The cases we'll throw away the packet immediately */
- if (descr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
+ if (hwdescr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
if (netif_msg_rx_err(card))
pr_err("%s: error in received descriptor found, "
"data_status=x%08x, data_error=x%08x\n",
card->netdev->name,
- descr->data_status, descr->data_error);
+ hwdescr->data_status, hwdescr->data_error);
goto bad_desc;
}
- if (descr->dmac_cmd_status & 0xfefe) {
+ if (hwdescr->dmac_cmd_status & 0xfefe) {
pr_err("%s: bad status, cmd_status=x%08x\n",
card->netdev->name,
- descr->dmac_cmd_status);
- pr_err("buf_addr=x%08x\n", descr->buf_addr);
- pr_err("buf_size=x%08x\n", descr->buf_size);
- pr_err("next_descr_addr=x%08x\n", descr->next_descr_addr);
- pr_err("result_size=x%08x\n", descr->result_size);
- pr_err("valid_size=x%08x\n", descr->valid_size);
- pr_err("data_status=x%08x\n", descr->data_status);
- pr_err("data_error=x%08x\n", descr->data_error);
- pr_err("bus_addr=x%08x\n", descr->bus_addr);
+ hwdescr->dmac_cmd_status);
+ pr_err("buf_addr=x%08x\n", hwdescr->buf_addr);
+ pr_err("buf_size=x%08x\n", hwdescr->buf_size);
+ pr_err("next_descr_addr=x%08x\n", hwdescr->next_descr_addr);
+ pr_err("result_size=x%08x\n", hwdescr->result_size);
+ pr_err("valid_size=x%08x\n", hwdescr->valid_size);
+ pr_err("data_status=x%08x\n", hwdescr->data_status);
+ pr_err("data_error=x%08x\n", hwdescr->data_error);
pr_err("which=%ld\n", descr - card->rx_chain.ring);
card->spider_stats.rx_desc_error++;
@@ -1073,12 +1133,13 @@ spider_net_decode_one_descr(struct spider_net_card *card)
/* Ok, we've got a packet in descr */
spider_net_pass_skb_up(descr, card);
- descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+ hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
return 1;
bad_desc:
dev_kfree_skb_irq(descr->skb);
- descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+ descr->skb = NULL;
+ hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
return 0;
}
@@ -1248,6 +1309,33 @@ spider_net_set_mac(struct net_device *netdev, void *p)
}
/**
+ * spider_net_link_reset
+ * @netdev: net device structure
+ *
+ * This is called when the PHY_LINK signal is asserted. For the blade this is
+ * not connected so we should never get here.
+ *
+ */
+static void
+spider_net_link_reset(struct net_device *netdev)
+{
+
+ struct spider_net_card *card = netdev_priv(netdev);
+
+ del_timer_sync(&card->aneg_timer);
+
+ /* clear interrupt, block further interrupts */
+ spider_net_write_reg(card, SPIDER_NET_GMACST,
+ spider_net_read_reg(card, SPIDER_NET_GMACST));
+ spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0);
+
+ /* reset phy and setup aneg */
+ spider_net_setup_aneg(card);
+ mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
+
+}
+
+/**
* spider_net_handle_error_irq - handles errors raised by an interrupt
* @card: card structure
* @status_reg: interrupt status register 0 (GHIINT0STS)
@@ -1359,8 +1447,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
switch (i)
{
case SPIDER_NET_GTMFLLINT:
- if (netif_msg_intr(card) && net_ratelimit())
- pr_err("Spider TX RAM full\n");
+ /* TX RAM full may happen on a usual case.
+ * Logging is not needed. */
show_error = 0;
break;
case SPIDER_NET_GRFDFLLINT: /* fallthrough */
@@ -1500,6 +1588,9 @@ spider_net_interrupt(int irq, void *ptr)
if (status_reg & SPIDER_NET_TXINT)
netif_rx_schedule(netdev);
+ if (status_reg & SPIDER_NET_LINKINT)
+ spider_net_link_reset(netdev);
+
if (status_reg & SPIDER_NET_ERRINT )
spider_net_handle_error_irq(card, status_reg);
@@ -1540,6 +1631,11 @@ spider_net_init_card(struct spider_net_card *card)
spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
SPIDER_NET_CKRCTRL_RUN_VALUE);
+
+ /* trigger ETOMOD signal */
+ spider_net_write_reg(card, SPIDER_NET_GMACOPEMD,
+ spider_net_read_reg(card, SPIDER_NET_GMACOPEMD) | 0x4);
+
}
/**
@@ -1624,8 +1720,6 @@ spider_net_enable_card(struct spider_net_card *card)
spider_net_write_reg(card, SPIDER_NET_GMACLENLMT,
SPIDER_NET_LENLMT_VALUE);
- spider_net_write_reg(card, SPIDER_NET_GMACMODE,
- SPIDER_NET_MACMODE_VALUE);
spider_net_write_reg(card, SPIDER_NET_GMACOPEMD,
SPIDER_NET_OPMODE_VALUE);
@@ -1642,98 +1736,6 @@ spider_net_enable_card(struct spider_net_card *card)
}
/**
- * spider_net_open - called upon ifonfig up
- * @netdev: interface device structure
- *
- * returns 0 on success, <0 on failure
- *
- * spider_net_open allocates all the descriptors and memory needed for
- * operation, sets up multicast list and enables interrupts
- */
-int
-spider_net_open(struct net_device *netdev)
-{
- struct spider_net_card *card = netdev_priv(netdev);
- int result;
-
- result = spider_net_init_chain(card, &card->tx_chain);
- if (result)
- goto alloc_tx_failed;
- card->low_watermark = NULL;
-
- result = spider_net_init_chain(card, &card->rx_chain);
- if (result)
- goto alloc_rx_failed;
-
- /* Allocate rx skbs */
- if (spider_net_alloc_rx_skbs(card))
- goto alloc_skbs_failed;
-
- spider_net_set_multi(netdev);
-
- /* further enhancement: setup hw vlan, if needed */
-
- result = -EBUSY;
- if (request_irq(netdev->irq, spider_net_interrupt,
- IRQF_SHARED, netdev->name, netdev))
- goto register_int_failed;
-
- spider_net_enable_card(card);
-
- netif_start_queue(netdev);
- netif_carrier_on(netdev);
- netif_poll_enable(netdev);
-
- return 0;
-
-register_int_failed:
- spider_net_free_rx_chain_contents(card);
-alloc_skbs_failed:
- spider_net_free_chain(card, &card->rx_chain);
-alloc_rx_failed:
- spider_net_free_chain(card, &card->tx_chain);
-alloc_tx_failed:
- return result;
-}
-
-/**
- * spider_net_setup_phy - setup PHY
- * @card: card structure
- *
- * returns 0 on success, <0 on failure
- *
- * spider_net_setup_phy is used as part of spider_net_probe. Sets
- * the PHY to 1000 Mbps
- **/
-static int
-spider_net_setup_phy(struct spider_net_card *card)
-{
- struct mii_phy *phy = &card->phy;
-
- spider_net_write_reg(card, SPIDER_NET_GDTDMASEL,
- SPIDER_NET_DMASEL_VALUE);
- spider_net_write_reg(card, SPIDER_NET_GPCCTRL,
- SPIDER_NET_PHY_CTRL_VALUE);
- phy->mii_id = 1;
- phy->dev = card->netdev;
- phy->mdio_read = spider_net_read_phy;
- phy->mdio_write = spider_net_write_phy;
-
- mii_phy_probe(phy, phy->mii_id);
-
- if (phy->def->ops->setup_forced)
- phy->def->ops->setup_forced(phy, SPEED_1000, DUPLEX_FULL);
-
- phy->def->ops->enable_fiber(phy);
-
- phy->def->ops->read_link(phy);
- pr_info("Found %s with %i Mbps, %s-duplex.\n", phy->def->name,
- phy->speed, phy->duplex==1 ? "Full" : "Half");
-
- return 0;
-}
-
-/**
* spider_net_download_firmware - loads firmware into the adapter
* @card: card structure
* @firmware_ptr: pointer to firmware data
@@ -1852,6 +1854,179 @@ out_err:
}
/**
+ * spider_net_open - called upon ifonfig up
+ * @netdev: interface device structure
+ *
+ * returns 0 on success, <0 on failure
+ *
+ * spider_net_open allocates all the descriptors and memory needed for
+ * operation, sets up multicast list and enables interrupts
+ */
+int
+spider_net_open(struct net_device *netdev)
+{
+ struct spider_net_card *card = netdev_priv(netdev);
+ int result;
+
+ result = spider_net_init_firmware(card);
+ if (result)
+ goto init_firmware_failed;
+
+ /* start probing with copper */
+ spider_net_setup_aneg(card);
+ if (card->phy.def->phy_id)
+ mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
+
+ result = spider_net_init_chain(card, &card->tx_chain);
+ if (result)
+ goto alloc_tx_failed;
+ card->low_watermark = NULL;
+
+ result = spider_net_init_chain(card, &card->rx_chain);
+ if (result)
+ goto alloc_rx_failed;
+
+ /* Allocate rx skbs */
+ if (spider_net_alloc_rx_skbs(card))
+ goto alloc_skbs_failed;
+
+ spider_net_set_multi(netdev);
+
+ /* further enhancement: setup hw vlan, if needed */
+
+ result = -EBUSY;
+ if (request_irq(netdev->irq, spider_net_interrupt,
+ IRQF_SHARED, netdev->name, netdev))
+ goto register_int_failed;
+
+ spider_net_enable_card(card);
+
+ netif_start_queue(netdev);
+ netif_carrier_on(netdev);
+ netif_poll_enable(netdev);
+
+ return 0;
+
+register_int_failed:
+ spider_net_free_rx_chain_contents(card);
+alloc_skbs_failed:
+ spider_net_free_chain(card, &card->rx_chain);
+alloc_rx_failed:
+ spider_net_free_chain(card, &card->tx_chain);
+alloc_tx_failed:
+ del_timer_sync(&card->aneg_timer);
+init_firmware_failed:
+ return result;
+}
+
+/**
+ * spider_net_link_phy
+ * @data: used for pointer to card structure
+ *
+ */
+static void spider_net_link_phy(unsigned long data)
+{
+ struct spider_net_card *card = (struct spider_net_card *)data;
+ struct mii_phy *phy = &card->phy;
+
+ /* if link didn't come up after SPIDER_NET_ANEG_TIMEOUT tries, setup phy again */
+ if (card->aneg_count > SPIDER_NET_ANEG_TIMEOUT) {
+
+ pr_info("%s: link is down trying to bring it up\n", card->netdev->name);
+
+ switch (card->medium) {
+ case BCM54XX_COPPER:
+ /* enable fiber with autonegotiation first */
+ if (phy->def->ops->enable_fiber)
+ phy->def->ops->enable_fiber(phy, 1);
+ card->medium = BCM54XX_FIBER;
+ break;
+
+ case BCM54XX_FIBER:
+ /* fiber didn't come up, try to disable fiber autoneg */
+ if (phy->def->ops->enable_fiber)
+ phy->def->ops->enable_fiber(phy, 0);
+ card->medium = BCM54XX_UNKNOWN;
+ break;
+
+ case BCM54XX_UNKNOWN:
+ /* copper, fiber with and without failed,
+ * retry from beginning */
+ spider_net_setup_aneg(card);
+ card->medium = BCM54XX_COPPER;
+ break;
+ }
+
+ card->aneg_count = 0;
+ mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
+ return;
+ }
+
+ /* link still not up, try again later */
+ if (!(phy->def->ops->poll_link(phy))) {
+ card->aneg_count++;
+ mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
+ return;
+ }
+
+ /* link came up, get abilities */
+ phy->def->ops->read_link(phy);
+
+ spider_net_write_reg(card, SPIDER_NET_GMACST,
+ spider_net_read_reg(card, SPIDER_NET_GMACST));
+ spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0x4);
+
+ if (phy->speed == 1000)
+ spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0x00000001);
+ else
+ spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0);
+
+ card->aneg_count = 0;
+
+ pr_debug("Found %s with %i Mbps, %s-duplex %sautoneg.\n",
+ phy->def->name, phy->speed, phy->duplex==1 ? "Full" : "Half",
+ phy->autoneg==1 ? "" : "no ");
+
+ return;
+}
+
+/**
+ * spider_net_setup_phy - setup PHY
+ * @card: card structure
+ *
+ * returns 0 on success, <0 on failure
+ *
+ * spider_net_setup_phy is used as part of spider_net_probe.
+ **/
+static int
+spider_net_setup_phy(struct spider_net_card *card)
+{
+ struct mii_phy *phy = &card->phy;
+
+ spider_net_write_reg(card, SPIDER_NET_GDTDMASEL,
+ SPIDER_NET_DMASEL_VALUE);
+ spider_net_write_reg(card, SPIDER_NET_GPCCTRL,
+ SPIDER_NET_PHY_CTRL_VALUE);
+
+ phy->dev = card->netdev;
+ phy->mdio_read = spider_net_read_phy;
+ phy->mdio_write = spider_net_write_phy;
+
+ for (phy->mii_id = 1; phy->mii_id <= 31; phy->mii_id++) {
+ unsigned short id;
+ id = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR);
+ if (id != 0x0000 && id != 0xffff) {
+ if (!mii_phy_probe(phy, phy->mii_id)) {
+ pr_info("Found %s.\n", phy->def->name);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
* spider_net_workaround_rxramfull - work around firmware bug
* @card: card structure
*
@@ -1900,14 +2075,15 @@ spider_net_stop(struct net_device *netdev)
netif_carrier_off(netdev);
netif_stop_queue(netdev);
del_timer_sync(&card->tx_timer);
+ del_timer_sync(&card->aneg_timer);
/* disable/mask all interrupts */
spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0);
spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0);
spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0);
+ spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0);
- /* free_irq(netdev->irq, netdev);*/
- free_irq(to_pci_dev(netdev->dev.parent)->irq, netdev);
+ free_irq(netdev->irq, netdev);
spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
SPIDER_NET_DMA_TX_FEND_VALUE);
@@ -1919,8 +2095,6 @@ spider_net_stop(struct net_device *netdev)
spider_net_release_tx_chain(card, 1);
spider_net_free_rx_chain_contents(card);
- spider_net_free_rx_chain_contents(card);
-
spider_net_free_chain(card, &card->tx_chain);
spider_net_free_chain(card, &card->rx_chain);
@@ -1952,8 +2126,6 @@ spider_net_tx_timeout_task(struct work_struct *work)
if (spider_net_setup_phy(card))
goto out;
- if (spider_net_init_firmware(card))
- goto out;
spider_net_open(netdev);
spider_net_kick_tx_dma(card);
@@ -2046,10 +2218,12 @@ spider_net_setup_netdev(struct spider_net_card *card)
card->tx_timer.data = (unsigned long) card;
netdev->irq = card->pdev->irq;
- card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;
+ card->aneg_count = 0;
+ init_timer(&card->aneg_timer);
+ card->aneg_timer.function = spider_net_link_phy;
+ card->aneg_timer.data = (unsigned long) card;
- card->tx_chain.num_desc = tx_descriptors;
- card->rx_chain.num_desc = rx_descriptors;
+ card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;
spider_net_setup_netdev_ops(netdev);
@@ -2098,8 +2272,11 @@ spider_net_alloc_card(void)
{
struct net_device *netdev;
struct spider_net_card *card;
+ size_t alloc_size;
- netdev = alloc_etherdev(sizeof(struct spider_net_card));
+ alloc_size = sizeof(struct spider_net_card) +
+ (tx_descriptors + rx_descriptors) * sizeof(struct spider_net_descr);
+ netdev = alloc_etherdev(alloc_size);
if (!netdev)
return NULL;
@@ -2110,6 +2287,11 @@ spider_net_alloc_card(void)
init_waitqueue_head(&card->waitq);
atomic_set(&card->tx_timeout_task_counter, 0);
+ card->rx_chain.num_desc = rx_descriptors;
+ card->rx_chain.ring = card->darray;
+ card->tx_chain.num_desc = tx_descriptors;
+ card->tx_chain.ring = card->darray + rx_descriptors;
+
return card;
}
@@ -2220,10 +2402,6 @@ spider_net_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto out_undo_pci;
- err = spider_net_init_firmware(card);
- if (err)
- goto out_undo_pci;
-
err = spider_net_setup_netdev(card);
if (err)
goto out_undo_pci;
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
index 2fec5cf7692..4a1e0d28a50 100644
--- a/drivers/net/spider_net.h
+++ b/drivers/net/spider_net.h
@@ -1,7 +1,8 @@
/*
- * Network device driver for Cell Processor-Based Blade
+ * Network device driver for Cell Processor-Based Blade and Celleb platform
*
* (C) Copyright IBM Corp. 2005
+ * (C) Copyright 2006 TOSHIBA CORPORATION
*
* Authors : Utz Bacher <utz.bacher@de.ibm.com>
* Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
@@ -24,7 +25,7 @@
#ifndef _SPIDER_NET_H
#define _SPIDER_NET_H
-#define VERSION "1.6 B"
+#define VERSION "2.0 A"
#include "sungem_phy.h"
@@ -50,6 +51,8 @@ extern char spider_net_driver_name[];
#define SPIDER_NET_TX_DESCRIPTORS_MAX 512
#define SPIDER_NET_TX_TIMER (HZ/5)
+#define SPIDER_NET_ANEG_TIMER (HZ)
+#define SPIDER_NET_ANEG_TIMEOUT 2
#define SPIDER_NET_RX_CSUM_DEFAULT 1
@@ -104,6 +107,7 @@ extern char spider_net_driver_name[];
#define SPIDER_NET_GMACOPEMD 0x00000100
#define SPIDER_NET_GMACLENLMT 0x00000108
+#define SPIDER_NET_GMACST 0x00000110
#define SPIDER_NET_GMACINTEN 0x00000118
#define SPIDER_NET_GMACPHYCTRL 0x00000120
@@ -181,7 +185,8 @@ extern char spider_net_driver_name[];
/* pause frames: automatic, no upper retransmission count */
/* outside loopback mode: ETOMOD signal dont matter, not connected */
-#define SPIDER_NET_OPMODE_VALUE 0x00000063
+/* ETOMOD signal is brought to PHY reset. bit 2 must be 1 in Celleb */
+#define SPIDER_NET_OPMODE_VALUE 0x00000067
/*#define SPIDER_NET_OPMODE_VALUE 0x001b0062*/
#define SPIDER_NET_LENLMT_VALUE 0x00000908
@@ -333,9 +338,12 @@ enum spider_net_int2_status {
/* We rely on flagged descriptor interrupts */
#define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) )
+#define SPIDER_NET_LINKINT ( 1 << SPIDER_NET_GMAC2INT )
+
#define SPIDER_NET_ERRINT ( 0xffffffff & \
(~SPIDER_NET_TXINT) & \
- (~SPIDER_NET_RXINT) )
+ (~SPIDER_NET_RXINT) & \
+ (~SPIDER_NET_LINKINT) )
#define SPIDER_NET_GPREXEC 0x80000000
#define SPIDER_NET_GPRDAT_MASK 0x0000ffff
@@ -356,8 +364,8 @@ enum spider_net_int2_status {
#define SPIDER_NET_DESCR_NOT_IN_USE 0xF0000000
#define SPIDER_NET_DESCR_TXDESFLG 0x00800000
-struct spider_net_descr {
- /* as defined by the hardware */
+/* Descriptor, as defined by the hardware */
+struct spider_net_hw_descr {
u32 buf_addr;
u32 buf_size;
u32 next_descr_addr;
@@ -366,13 +374,15 @@ struct spider_net_descr {
u32 valid_size; /* all zeroes for tx */
u32 data_status;
u32 data_error; /* all zeroes for tx */
+} __attribute__((aligned(32)));
- /* used in the driver */
+struct spider_net_descr {
+ struct spider_net_hw_descr *hwdescr;
struct sk_buff *skb;
u32 bus_addr;
struct spider_net_descr *next;
struct spider_net_descr *prev;
-} __attribute__((aligned(32)));
+};
struct spider_net_descr_chain {
spinlock_t lock;
@@ -380,6 +390,7 @@ struct spider_net_descr_chain {
struct spider_net_descr *tail;
struct spider_net_descr *ring;
int num_desc;
+ struct spider_net_hw_descr *hwring;
dma_addr_t dma_addr;
};
@@ -436,12 +447,16 @@ struct spider_net_card {
struct pci_dev *pdev;
struct mii_phy phy;
+ int medium;
+
void __iomem *regs;
struct spider_net_descr_chain tx_chain;
struct spider_net_descr_chain rx_chain;
struct spider_net_descr *low_watermark;
+ int aneg_count;
+ struct timer_list aneg_timer;
struct timer_list tx_timer;
struct work_struct tx_timeout_task;
atomic_t tx_timeout_task_counter;
@@ -452,6 +467,9 @@ struct spider_net_card {
struct net_device_stats netdev_stats;
struct spider_net_extra_stats spider_stats;
struct spider_net_options options;
+
+ /* Must be last item in struct */
+ struct spider_net_descr darray[0];
};
#define pr_err(fmt,arg...) \
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index bf873ea2579..8bba2e3da7e 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -677,8 +677,7 @@ static void netdev_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
spin_lock(&np->lock);
if (debug > 1)
printk("%s: removing vlanid %d from vlan filter\n", dev->name, vid);
- if (np->vlgrp)
- np->vlgrp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(np->vlgrp, vid, NULL);
set_rx_mode(dev);
spin_unlock(&np->lock);
}
@@ -1738,7 +1737,7 @@ static void set_rx_mode(struct net_device *dev)
int vlan_count = 0;
void __iomem *filter_addr = ioaddr + HashTable + 8;
for (i = 0; i < VLAN_VID_MASK; i++) {
- if (np->vlgrp->vlan_devices[i]) {
+ if (vlan_group_get_device(np->vlgrp, i)) {
if (vlan_count >= 32)
break;
writew(cpu_to_be16(i), filter_addr);
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
index a3220a96524..4757aa647c7 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/sun3_82586.c
@@ -28,8 +28,6 @@ static int automatic_resume = 0; /* experimental .. better should be zero */
static int rfdadd = 0; /* rfdadd=1 may be better for 8K MEM cards */
static int fifo=0x8; /* don't change */
-/* #define REALLY_SLOW_IO */
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
index 701ba4f3b69..56a110ca5e6 100644
--- a/drivers/net/sungem_phy.c
+++ b/drivers/net/sungem_phy.c
@@ -310,6 +310,107 @@ static int bcm5411_init(struct mii_phy* phy)
return 0;
}
+static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
+{
+ u16 ctl, adv;
+
+ phy->autoneg = 1;
+ phy->speed = SPEED_10;
+ phy->duplex = DUPLEX_HALF;
+ phy->pause = 0;
+ phy->advertising = advertise;
+
+ /* Setup standard advertise */
+ adv = phy_read(phy, MII_ADVERTISE);
+ adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+ if (advertise & ADVERTISED_10baseT_Half)
+ adv |= ADVERTISE_10HALF;
+ if (advertise & ADVERTISED_10baseT_Full)
+ adv |= ADVERTISE_10FULL;
+ if (advertise & ADVERTISED_100baseT_Half)
+ adv |= ADVERTISE_100HALF;
+ if (advertise & ADVERTISED_100baseT_Full)
+ adv |= ADVERTISE_100FULL;
+ phy_write(phy, MII_ADVERTISE, adv);
+
+ /* Start/Restart aneg */
+ ctl = phy_read(phy, MII_BMCR);
+ ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ phy_write(phy, MII_BMCR, ctl);
+
+ return 0;
+}
+
+static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
+{
+ u16 ctl;
+
+ phy->autoneg = 0;
+ phy->speed = speed;
+ phy->duplex = fd;
+ phy->pause = 0;
+
+ ctl = phy_read(phy, MII_BMCR);
+ ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
+
+ /* First reset the PHY */
+ phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
+
+ /* Select speed & duplex */
+ switch(speed) {
+ case SPEED_10:
+ break;
+ case SPEED_100:
+ ctl |= BMCR_SPEED100;
+ break;
+ case SPEED_1000:
+ default:
+ return -EINVAL;
+ }
+ if (fd == DUPLEX_FULL)
+ ctl |= BMCR_FULLDPLX;
+ phy_write(phy, MII_BMCR, ctl);
+
+ return 0;
+}
+
+static int genmii_poll_link(struct mii_phy *phy)
+{
+ u16 status;
+
+ (void)phy_read(phy, MII_BMSR);
+ status = phy_read(phy, MII_BMSR);
+ if ((status & BMSR_LSTATUS) == 0)
+ return 0;
+ if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
+ return 0;
+ return 1;
+}
+
+static int genmii_read_link(struct mii_phy *phy)
+{
+ u16 lpa;
+
+ if (phy->autoneg) {
+ lpa = phy_read(phy, MII_LPA);
+
+ if (lpa & (LPA_10FULL | LPA_100FULL))
+ phy->duplex = DUPLEX_FULL;
+ else
+ phy->duplex = DUPLEX_HALF;
+ if (lpa & (LPA_100FULL | LPA_100HALF))
+ phy->speed = SPEED_100;
+ else
+ phy->speed = SPEED_10;
+ phy->pause = 0;
+ }
+ /* On non-aneg, we assume what we put in BMCR is the speed,
+ * though magic-aneg shouldn't prevent this case from occurring
+ */
+
+ return 0;
+}
+
static int generic_suspend(struct mii_phy* phy)
{
phy_write(phy, MII_BMCR, BMCR_PDOWN);
@@ -364,30 +465,6 @@ static int bcm5421_init(struct mii_phy* phy)
return 0;
}
-static int bcm5421_enable_fiber(struct mii_phy* phy)
-{
- /* enable fiber mode */
- phy_write(phy, MII_NCONFIG, 0x9020);
- /* LEDs active in both modes, autosense prio = fiber */
- phy_write(phy, MII_NCONFIG, 0x945f);
-
- /* switch off fibre autoneg */
- phy_write(phy, MII_NCONFIG, 0xfc01);
- phy_write(phy, 0x0b, 0x0004);
-
- return 0;
-}
-
-static int bcm5461_enable_fiber(struct mii_phy* phy)
-{
- phy_write(phy, MII_NCONFIG, 0xfc0c);
- phy_write(phy, MII_BMCR, 0x4140);
- phy_write(phy, MII_NCONFIG, 0xfc0b);
- phy_write(phy, MII_BMCR, 0x0140);
-
- return 0;
-}
-
static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
{
u16 ctl, adv;
@@ -515,6 +592,155 @@ static int marvell88e1111_init(struct mii_phy* phy)
return 0;
}
+#define BCM5421_MODE_MASK (1 << 5)
+
+static int bcm5421_poll_link(struct mii_phy* phy)
+{
+ u32 phy_reg;
+ int mode;
+
+ /* find out in what mode we are */
+ phy_write(phy, MII_NCONFIG, 0x1000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ mode = (phy_reg & BCM5421_MODE_MASK) >> 5;
+
+ if ( mode == BCM54XX_COPPER)
+ return genmii_poll_link(phy);
+
+ /* try to find out wether we have a link */
+ phy_write(phy, MII_NCONFIG, 0x2000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ if (phy_reg & 0x0020)
+ return 0;
+ else
+ return 1;
+}
+
+static int bcm5421_read_link(struct mii_phy* phy)
+{
+ u32 phy_reg;
+ int mode;
+
+ /* find out in what mode we are */
+ phy_write(phy, MII_NCONFIG, 0x1000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ mode = (phy_reg & BCM5421_MODE_MASK ) >> 5;
+
+ if ( mode == BCM54XX_COPPER)
+ return bcm54xx_read_link(phy);
+
+ phy->speed = SPEED_1000;
+
+ /* find out wether we are running half- or full duplex */
+ phy_write(phy, MII_NCONFIG, 0x2000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ if ( (phy_reg & 0x0080) >> 7)
+ phy->duplex |= DUPLEX_HALF;
+ else
+ phy->duplex |= DUPLEX_FULL;
+
+ return 0;
+}
+
+static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg)
+{
+ /* enable fiber mode */
+ phy_write(phy, MII_NCONFIG, 0x9020);
+ /* LEDs active in both modes, autosense prio = fiber */
+ phy_write(phy, MII_NCONFIG, 0x945f);
+
+ if (!autoneg) {
+ /* switch off fibre autoneg */
+ phy_write(phy, MII_NCONFIG, 0xfc01);
+ phy_write(phy, 0x0b, 0x0004);
+ }
+
+ phy->autoneg = autoneg;
+
+ return 0;
+}
+
+#define BCM5461_FIBER_LINK (1 << 2)
+#define BCM5461_MODE_MASK (3 << 1)
+
+static int bcm5461_poll_link(struct mii_phy* phy)
+{
+ u32 phy_reg;
+ int mode;
+
+ /* find out in what mode we are */
+ phy_write(phy, MII_NCONFIG, 0x7c00);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
+
+ if ( mode == BCM54XX_COPPER)
+ return genmii_poll_link(phy);
+
+ /* find out wether we have a link */
+ phy_write(phy, MII_NCONFIG, 0x7000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ if (phy_reg & BCM5461_FIBER_LINK)
+ return 1;
+ else
+ return 0;
+}
+
+#define BCM5461_FIBER_DUPLEX (1 << 3)
+
+static int bcm5461_read_link(struct mii_phy* phy)
+{
+ u32 phy_reg;
+ int mode;
+
+ /* find out in what mode we are */
+ phy_write(phy, MII_NCONFIG, 0x7c00);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
+
+ if ( mode == BCM54XX_COPPER) {
+ return bcm54xx_read_link(phy);
+ }
+
+ phy->speed = SPEED_1000;
+
+ /* find out wether we are running half- or full duplex */
+ phy_write(phy, MII_NCONFIG, 0x7000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ if (phy_reg & BCM5461_FIBER_DUPLEX)
+ phy->duplex |= DUPLEX_FULL;
+ else
+ phy->duplex |= DUPLEX_HALF;
+
+ return 0;
+}
+
+static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg)
+{
+ /* select fiber mode, enable 1000 base-X registers */
+ phy_write(phy, MII_NCONFIG, 0xfc0b);
+
+ if (autoneg) {
+ /* enable fiber with no autonegotiation */
+ phy_write(phy, MII_ADVERTISE, 0x01e0);
+ phy_write(phy, MII_BMCR, 0x1140);
+ } else {
+ /* enable fiber with autonegotiation */
+ phy_write(phy, MII_BMCR, 0x0140);
+ }
+
+ phy->autoneg = autoneg;
+
+ return 0;
+}
+
static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
{
u16 ctl, adv;
@@ -645,113 +871,6 @@ static int marvell_read_link(struct mii_phy *phy)
return 0;
}
-static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
-{
- u16 ctl, adv;
-
- phy->autoneg = 1;
- phy->speed = SPEED_10;
- phy->duplex = DUPLEX_HALF;
- phy->pause = 0;
- phy->advertising = advertise;
-
- /* Setup standard advertise */
- adv = phy_read(phy, MII_ADVERTISE);
- adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
- if (advertise & ADVERTISED_10baseT_Half)
- adv |= ADVERTISE_10HALF;
- if (advertise & ADVERTISED_10baseT_Full)
- adv |= ADVERTISE_10FULL;
- if (advertise & ADVERTISED_100baseT_Half)
- adv |= ADVERTISE_100HALF;
- if (advertise & ADVERTISED_100baseT_Full)
- adv |= ADVERTISE_100FULL;
- if (advertise & ADVERTISED_Pause)
- adv |= ADVERTISE_PAUSE_CAP;
- if (advertise & ADVERTISED_Asym_Pause)
- adv |= ADVERTISE_PAUSE_ASYM;
- phy_write(phy, MII_ADVERTISE, adv);
-
- /* Start/Restart aneg */
- ctl = phy_read(phy, MII_BMCR);
- ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
- phy_write(phy, MII_BMCR, ctl);
-
- return 0;
-}
-
-static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
-{
- u16 ctl;
-
- phy->autoneg = 0;
- phy->speed = speed;
- phy->duplex = fd;
- phy->pause = 0;
-
- ctl = phy_read(phy, MII_BMCR);
- ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
-
- /* First reset the PHY */
- phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
-
- /* Select speed & duplex */
- switch(speed) {
- case SPEED_10:
- break;
- case SPEED_100:
- ctl |= BMCR_SPEED100;
- break;
- case SPEED_1000:
- default:
- return -EINVAL;
- }
- if (fd == DUPLEX_FULL)
- ctl |= BMCR_FULLDPLX;
- phy_write(phy, MII_BMCR, ctl);
-
- return 0;
-}
-
-static int genmii_poll_link(struct mii_phy *phy)
-{
- u16 status;
-
- (void)phy_read(phy, MII_BMSR);
- status = phy_read(phy, MII_BMSR);
- if ((status & BMSR_LSTATUS) == 0)
- return 0;
- if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
- return 0;
- return 1;
-}
-
-static int genmii_read_link(struct mii_phy *phy)
-{
- u16 lpa;
-
- if (phy->autoneg) {
- lpa = phy_read(phy, MII_LPA);
-
- if (lpa & (LPA_10FULL | LPA_100FULL))
- phy->duplex = DUPLEX_FULL;
- else
- phy->duplex = DUPLEX_HALF;
- if (lpa & (LPA_100FULL | LPA_100HALF))
- phy->speed = SPEED_100;
- else
- phy->speed = SPEED_10;
- phy->pause = (phy->duplex == DUPLEX_FULL) &&
- ((lpa & LPA_PAUSE) != 0);
- }
- /* On non-aneg, we assume what we put in BMCR is the speed,
- * though magic-aneg shouldn't prevent this case from occurring
- */
-
- return 0;
-}
-
-
#define MII_BASIC_FEATURES \
(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
@@ -885,8 +1004,8 @@ static struct mii_phy_ops bcm5421_phy_ops = {
.suspend = generic_suspend,
.setup_aneg = bcm54xx_setup_aneg,
.setup_forced = bcm54xx_setup_forced,
- .poll_link = genmii_poll_link,
- .read_link = bcm54xx_read_link,
+ .poll_link = bcm5421_poll_link,
+ .read_link = bcm5421_read_link,
.enable_fiber = bcm5421_enable_fiber,
};
@@ -923,8 +1042,8 @@ static struct mii_phy_ops bcm5461_phy_ops = {
.suspend = generic_suspend,
.setup_aneg = bcm54xx_setup_aneg,
.setup_forced = bcm54xx_setup_forced,
- .poll_link = genmii_poll_link,
- .read_link = bcm54xx_read_link,
+ .poll_link = bcm5461_poll_link,
+ .read_link = bcm5461_read_link,
.enable_fiber = bcm5461_enable_fiber,
};
diff --git a/drivers/net/sungem_phy.h b/drivers/net/sungem_phy.h
index 1d70ba6f9f1..af02f9479cb 100644
--- a/drivers/net/sungem_phy.h
+++ b/drivers/net/sungem_phy.h
@@ -12,7 +12,7 @@ struct mii_phy_ops
int (*setup_forced)(struct mii_phy *phy, int speed, int fd);
int (*poll_link)(struct mii_phy *phy);
int (*read_link)(struct mii_phy *phy);
- int (*enable_fiber)(struct mii_phy *phy);
+ int (*enable_fiber)(struct mii_phy *phy, int autoneg);
};
/* Structure used to statically define an mii/gii based PHY */
@@ -26,6 +26,14 @@ struct mii_phy_def
const struct mii_phy_ops* ops;
};
+enum {
+ BCM54XX_COPPER,
+ BCM54XX_FIBER,
+ BCM54XX_GBIC,
+ BCM54XX_SGMII,
+ BCM54XX_UNKNOWN,
+};
+
/* An instance of a PHY, partially borrowed from mii_if_info */
struct mii_phy
{
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index 81ed82f0b52..e3a7e3ceab7 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -657,7 +657,7 @@ tc35815_init_queues(struct net_device *dev)
dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
#endif
} else {
- clear_page(lp->fd_buf);
+ memset(lp->fd_buf, 0, PAGE_SIZE * FD_PAGE_NUM);
#ifdef __mips__
dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
#endif
@@ -1703,19 +1703,6 @@ static void tc35815_chip_init(struct net_device *dev)
spin_unlock_irqrestore(&lp->lock, flags);
}
-/* XXX */
-void
-tc35815_killall(void)
-{
- struct net_device *dev;
-
- for (dev = root_tc35815_dev; dev; dev = ((struct tc35815_local *)dev->priv)->next_module) {
- if (dev->flags&IFF_UP){
- dev->stop(dev);
- }
- }
-}
-
static struct pci_driver tc35815_driver = {
.name = TC35815_MODULE_NAME,
.probe = tc35815_probe,
@@ -1732,6 +1719,11 @@ static void __exit tc35815_cleanup_module(void)
{
struct net_device *next_dev;
+ /*
+ * TODO: implement a tc35815_driver.remove hook, and
+ * move this code into that function. Then, delete
+ * all root_tc35815_dev list handling code.
+ */
while (root_tc35815_dev) {
struct net_device *dev = root_tc35815_dev;
next_dev = ((struct tc35815_local *)dev->priv)->next_module;
@@ -1740,6 +1732,9 @@ static void __exit tc35815_cleanup_module(void)
free_netdev(dev);
root_tc35815_dev = next_dev;
}
+
+ pci_unregister_driver(&tc35815_driver);
}
+
module_init(tc35815_init_module);
module_exit(tc35815_cleanup_module);
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 81a1c2e1a3f..8c8f9f4d47a 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.73"
-#define DRV_MODULE_RELDATE "February 12, 2007"
+#define DRV_MODULE_VERSION "3.74"
+#define DRV_MODULE_RELDATE "February 20, 2007"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -3993,7 +3993,10 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb)
/* Estimate the number of fragments in the worst case */
if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3))) {
netif_stop_queue(tp->dev);
- return NETDEV_TX_BUSY;
+ if (tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3))
+ return NETDEV_TX_BUSY;
+
+ netif_wake_queue(tp->dev);
}
segs = skb_gso_segment(skb, tp->dev->features & ~NETIF_F_TSO);
@@ -4061,7 +4064,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
hdr_len = ip_tcp_len + tcp_opt_len;
if (unlikely((ETH_HLEN + hdr_len) > 80) &&
- (tp->tg3_flags2 & TG3_FLG2_HW_TSO_1_BUG))
+ (tp->tg3_flags2 & TG3_FLG2_TSO_BUG))
return (tg3_tso_bug(tp, skb));
base_flags |= (TXD_FLAG_CPU_PRE_DMA |
@@ -8137,7 +8140,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
(ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
(ering->tx_pending > TG3_TX_RING_SIZE - 1) ||
(ering->tx_pending <= MAX_SKB_FRAGS) ||
- ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1_BUG) &&
+ ((tp->tg3_flags2 & TG3_FLG2_TSO_BUG) &&
(ering->tx_pending <= (MAX_SKB_FRAGS * 3))))
return -EINVAL;
@@ -9111,8 +9114,7 @@ static void tg3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
tg3_netif_stop(tp);
tg3_full_lock(tp, 0);
- if (tp->vlgrp)
- tp->vlgrp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(tp->vlgrp, vid, NULL);
tg3_full_unlock(tp);
if (netif_running(dev))
@@ -10557,12 +10559,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
} else {
- tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1 |
- TG3_FLG2_HW_TSO_1_BUG;
+ tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1 | TG3_FLG2_TSO_BUG;
if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
ASIC_REV_5750 &&
tp->pci_chip_rev_id >= CHIPREV_ID_5750_C2)
- tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_1_BUG;
+ tp->tg3_flags2 &= ~TG3_FLG2_TSO_BUG;
}
}
@@ -11867,7 +11868,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0) {
tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE;
} else {
- tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
+ tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE | TG3_FLG2_TSO_BUG;
}
/* TSO is on by default on chips that support hardware TSO.
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 45d477e8f37..086892d8c1f 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2227,7 +2227,7 @@ struct tg3 {
#define TG3_FLAG_INIT_COMPLETE 0x80000000
u32 tg3_flags2;
#define TG3_FLG2_RESTART_TIMER 0x00000001
-#define TG3_FLG2_HW_TSO_1_BUG 0x00000002
+#define TG3_FLG2_TSO_BUG 0x00000002
#define TG3_FLG2_NO_ETH_WIRE_SPEED 0x00000004
#define TG3_FLG2_IS_5788 0x00000008
#define TG3_FLG2_MAX_RXPEND_64 0x00000010
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 0d97e10ccac..36202e94ee9 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -186,7 +186,6 @@ static char __devinit *adapter_def(char type)
#define TRC_INITV 0x02 /* verbose init trace points */
static unsigned char ibmtr_debug_trace = 0;
-static int ibmtr_probe(struct net_device *dev);
static int ibmtr_probe1(struct net_device *dev, int ioaddr);
static unsigned char get_sram_size(struct tok_info *adapt_info);
static int trdev_init(struct net_device *dev);
@@ -335,17 +334,6 @@ static void ibmtr_cleanup_card(struct net_device *dev)
#endif
}
-int ibmtr_probe_card(struct net_device *dev)
-{
- int err = ibmtr_probe(dev);
- if (!err) {
- err = register_netdev(dev);
- if (err)
- ibmtr_cleanup_card(dev);
- }
- return err;
-}
-
/****************************************************************************
* ibmtr_probe(): Routine specified in the network device structure
* to probe for an IBM Token Ring Adapter. Routine outline:
@@ -358,7 +346,7 @@ int ibmtr_probe_card(struct net_device *dev)
* which references it.
****************************************************************************/
-static int ibmtr_probe(struct net_device *dev)
+static int __init ibmtr_probe(struct net_device *dev)
{
int i;
int base_addr = dev->base_addr;
@@ -378,6 +366,17 @@ static int ibmtr_probe(struct net_device *dev)
return -ENODEV;
}
+int __init ibmtr_probe_card(struct net_device *dev)
+{
+ int err = ibmtr_probe(dev);
+ if (!err) {
+ err = register_netdev(dev);
+ if (err)
+ ibmtr_cleanup_card(dev);
+ }
+ return err;
+}
+
/*****************************************************************************/
static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index 9d67f11422e..c82befa209a 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -63,7 +63,7 @@ MODULE_PARM_DESC (debug, "de2104x bitmapped message enable number");
/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \
- || defined(__sparc_) || defined(__ia64__) \
+ || defined(__sparc__) || defined(__ia64__) \
|| defined(__sh__) || defined(__mips__)
static int rx_copybreak = 1518;
#else
@@ -1685,7 +1685,7 @@ static const struct ethtool_ops de_ethtool_ops = {
.get_regs = de_get_regs,
};
-static void __init de21040_get_mac_address (struct de_private *de)
+static void __devinit de21040_get_mac_address (struct de_private *de)
{
unsigned i;
@@ -1703,7 +1703,7 @@ static void __init de21040_get_mac_address (struct de_private *de)
}
}
-static void __init de21040_get_media_info(struct de_private *de)
+static void __devinit de21040_get_media_info(struct de_private *de)
{
unsigned int i;
@@ -1765,7 +1765,7 @@ static unsigned __devinit tulip_read_eeprom(void __iomem *regs, int location, in
return retval;
}
-static void __init de21041_get_srom_info (struct de_private *de)
+static void __devinit de21041_get_srom_info (struct de_private *de)
{
unsigned i, sa_offset = 0, ofs;
u8 ee_data[DE_EEPROM_SIZE + 6] = {};
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index 7f59a3d4fda..24a29c99ba9 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -143,9 +143,16 @@
#define DMFE_TX_TIMEOUT ((3*HZ)/2) /* tx packet time-out time 1.5 s" */
#define DMFE_TX_KICK (HZ/2) /* tx packet Kick-out time 0.5 s" */
-#define DMFE_DBUG(dbug_now, msg, value) if (dmfe_debug || (dbug_now)) printk(KERN_ERR DRV_NAME ": %s %lx\n", (msg), (long) (value))
+#define DMFE_DBUG(dbug_now, msg, value) \
+ do { \
+ if (dmfe_debug || (dbug_now)) \
+ printk(KERN_ERR DRV_NAME ": %s %lx\n",\
+ (msg), (long) (value)); \
+ } while (0)
-#define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR DRV_NAME ": Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half");
+#define SHOW_MEDIA_TYPE(mode) \
+ printk (KERN_INFO DRV_NAME ": Change Speed to %sMhz %s duplex\n" , \
+ (mode & 1) ? "100":"10", (mode & 4) ? "full":"half");
/* CR9 definition: SROM/MII */
@@ -163,10 +170,20 @@
#define SROM_V41_CODE 0x14
-#define SROM_CLK_WRITE(data, ioaddr) outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5);
+#define SROM_CLK_WRITE(data, ioaddr) \
+ outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr); \
+ udelay(5); \
+ outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr); \
+ udelay(5); \
+ outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr); \
+ udelay(5);
+
+#define __CHK_IO_SIZE(pci_id, dev_rev) \
+ (( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? \
+ DM9102A_IO_SIZE: DM9102_IO_SIZE)
-#define __CHK_IO_SIZE(pci_id, dev_rev) ( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE
-#define CHK_IO_SIZE(pci_dev, dev_rev) __CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev)
+#define CHK_IO_SIZE(pci_dev, dev_rev) \
+ (__CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev))
/* Sten Check */
#define DEVICE net_device
@@ -187,7 +204,7 @@ struct rx_desc {
struct dmfe_board_info {
u32 chip_id; /* Chip vendor/Device ID */
u32 chip_revision; /* Chip revision */
- struct DEVICE *dev; /* net device */
+ struct DEVICE *next_dev; /* next device */
struct pci_dev *pdev; /* PCI device */
spinlock_t lock;
@@ -231,7 +248,6 @@ struct dmfe_board_info {
u8 media_mode; /* user specify media mode */
u8 op_mode; /* real work media mode */
u8 phy_addr;
- u8 link_failed; /* Ever link failed */
u8 wait_reset; /* Hardware failed, need to reset */
u8 dm910x_chk_mode; /* Operating mode check */
u8 first_in_callback; /* Flag to record state */
@@ -329,7 +345,7 @@ static void dmfe_program_DM9802(struct dmfe_board_info *);
static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * );
static void dmfe_set_phyxcer(struct dmfe_board_info *);
-/* DM910X network baord routine ---------------------------- */
+/* DM910X network board routine ---------------------------- */
/*
* Search DM910X board ,allocate space and register it
@@ -356,7 +372,8 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
- printk(KERN_WARNING DRV_NAME ": 32-bit PCI DMA not available.\n");
+ printk(KERN_WARNING DRV_NAME
+ ": 32-bit PCI DMA not available.\n");
err = -ENODEV;
goto err_out_free;
}
@@ -399,11 +416,12 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
/* Init system & device */
db = netdev_priv(dev);
- db->dev = dev;
-
/* Allocate Tx/Rx descriptor memory */
- db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr);
- db->buf_pool_ptr = pci_alloc_consistent(pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4, &db->buf_pool_dma_ptr);
+ db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) *
+ DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr);
+
+ db->buf_pool_ptr = pci_alloc_consistent(pdev, TX_BUF_ALLOC *
+ TX_DESC_CNT + 4, &db->buf_pool_dma_ptr);
db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr;
db->first_tx_desc_dma = db->desc_pool_dma_ptr;
@@ -428,7 +446,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
dev->poll_controller = &poll_dmfe;
#endif
dev->ethtool_ops = &netdev_ethtool_ops;
- netif_carrier_off(db->dev);
+ netif_carrier_off(dev);
spin_lock_init(&db->lock);
pci_read_config_dword(pdev, 0x50, &pci_pmr);
@@ -440,7 +458,8 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
/* read 64 word srom data */
for (i = 0; i < 64; i++)
- ((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i));
+ ((u16 *) db->srom)[i] =
+ cpu_to_le16(read_srom_word(db->ioaddr, i));
/* Set Node address */
for (i = 0; i < 6; i++)
@@ -482,14 +501,17 @@ static void __devexit dmfe_remove_one (struct pci_dev *pdev)
DMFE_DBUG(0, "dmfe_remove_one()", 0);
if (dev) {
+
+ unregister_netdev(dev);
+
pci_free_consistent(db->pdev, sizeof(struct tx_desc) *
DESC_ALL_CNT + 0x20, db->desc_pool_ptr,
db->desc_pool_dma_ptr);
pci_free_consistent(db->pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4,
db->buf_pool_ptr, db->buf_pool_dma_ptr);
- unregister_netdev(dev);
pci_release_regions(pdev);
free_netdev(dev); /* free board information */
+
pci_set_drvdata(pdev, NULL);
}
@@ -509,7 +531,8 @@ static int dmfe_open(struct DEVICE *dev)
DMFE_DBUG(0, "dmfe_open", 0);
- ret = request_irq(dev->irq, &dmfe_interrupt, IRQF_SHARED, dev->name, dev);
+ ret = request_irq(dev->irq, &dmfe_interrupt,
+ IRQF_SHARED, dev->name, dev);
if (ret)
return ret;
@@ -518,7 +541,6 @@ static int dmfe_open(struct DEVICE *dev)
db->tx_packet_cnt = 0;
db->tx_queue_cnt = 0;
db->rx_avail_cnt = 0;
- db->link_failed = 1;
db->wait_reset = 0;
db->first_in_callback = 0;
@@ -650,7 +672,8 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev)
/* No Tx resource check, it never happen nromally */
if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) {
spin_unlock_irqrestore(&db->lock, flags);
- printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_queue_cnt);
+ printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n",
+ db->tx_queue_cnt);
return 1;
}
@@ -722,7 +745,8 @@ static int dmfe_stop(struct DEVICE *dev)
#if 0
/* show statistic counter */
- printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",
+ printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx"
+ " LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",
db->tx_fifo_underrun, db->tx_excessive_collision,
db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier,
db->tx_jabber_timeout, db->reset_count, db->reset_cr8,
@@ -905,7 +929,7 @@ static inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
{
struct rx_desc *rxptr;
- struct sk_buff *skb;
+ struct sk_buff *skb, *newskb;
int rxlen;
u32 rdes0;
@@ -919,7 +943,9 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
db->rx_avail_cnt--;
db->interval_rx_cnt++;
- pci_unmap_single(db->pdev, le32_to_cpu(rxptr->rdes2), RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE);
+ pci_unmap_single(db->pdev, le32_to_cpu(rxptr->rdes2),
+ RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE);
+
if ( (rdes0 & 0x300) != 0x300) {
/* A packet without First/Last flag */
/* reuse this SKB */
@@ -956,9 +982,11 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
} else {
/* Good packet, send to upper layer */
/* Shorst packet used new SKB */
- if ( (rxlen < RX_COPY_SIZE) &&
- ( (skb = dev_alloc_skb(rxlen + 2) )
- != NULL) ) {
+ if ((rxlen < RX_COPY_SIZE) &&
+ ((newskb = dev_alloc_skb(rxlen + 2))
+ != NULL)) {
+
+ skb = newskb;
/* size less than COPY_SIZE, allocate a rxlen SKB */
skb->dev = dev;
skb_reserve(skb, 2); /* 16byte align */
@@ -1069,6 +1097,8 @@ static void dmfe_timer(unsigned long data)
struct dmfe_board_info *db = netdev_priv(dev);
unsigned long flags;
+ int link_ok, link_ok_phy;
+
DMFE_DBUG(0, "dmfe_timer()", 0);
spin_lock_irqsave(&db->lock, flags);
@@ -1078,7 +1108,8 @@ static void dmfe_timer(unsigned long data)
if (db->chip_type && (db->chip_id==PCI_DM9102_ID)) {
db->cr6_data &= ~0x40000;
update_cr6(db->cr6_data, db->ioaddr);
- phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
+ phy_write(db->ioaddr,
+ db->phy_addr, 0, 0x1000, db->chip_id);
db->cr6_data |= 0x40000;
update_cr6(db->cr6_data, db->ioaddr);
db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
@@ -1139,21 +1170,41 @@ static void dmfe_timer(unsigned long data)
(db->chip_revision == 0x02000010)) ) {
/* DM9102A Chip */
if (tmp_cr12 & 2)
- tmp_cr12 = 0x0; /* Link failed */
+ link_ok = 0;
else
- tmp_cr12 = 0x3; /* Link OK */
+ link_ok = 1;
}
+ else
+ /*0x43 is used instead of 0x3 because bit 6 should represent
+ link status of external PHY */
+ link_ok = (tmp_cr12 & 0x43) ? 1 : 0;
+
+
+ /* If chip reports that link is failed it could be because external
+ PHY link status pin is not conected correctly to chip
+ To be sure ask PHY too.
+ */
+
+ /* need a dummy read because of PHY's register latch*/
+ phy_read (db->ioaddr, db->phy_addr, 1, db->chip_id);
+ link_ok_phy = (phy_read (db->ioaddr,
+ db->phy_addr, 1, db->chip_id) & 0x4) ? 1 : 0;
- if ( !(tmp_cr12 & 0x3) && !db->link_failed ) {
+ if (link_ok_phy != link_ok) {
+ DMFE_DBUG (0, "PHY and chip report different link status", 0);
+ link_ok = link_ok | link_ok_phy;
+ }
+
+ if ( !link_ok && netif_carrier_ok(dev)) {
/* Link Failed */
DMFE_DBUG(0, "Link Failed", tmp_cr12);
- db->link_failed = 1;
- netif_carrier_off(db->dev);
+ netif_carrier_off(dev);
/* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */
/* AUTO or force 1M Homerun/Longrun don't need */
if ( !(db->media_mode & 0x38) )
- phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
+ phy_write(db->ioaddr, db->phy_addr,
+ 0, 0x1000, db->chip_id);
/* AUTO mode, if INT phyxcer link failed, select EXT device */
if (db->media_mode & DMFE_AUTO) {
@@ -1162,21 +1213,19 @@ static void dmfe_timer(unsigned long data)
db->cr6_data&=~0x00000200; /* bit9=0, HD mode */
update_cr6(db->cr6_data, db->ioaddr);
}
- } else
- if ((tmp_cr12 & 0x3) && db->link_failed) {
- DMFE_DBUG(0, "Link link OK", tmp_cr12);
- db->link_failed = 0;
-
- /* Auto Sense Speed */
- if ( (db->media_mode & DMFE_AUTO) &&
- dmfe_sense_speed(db) )
- db->link_failed = 1;
- else
- netif_carrier_on(db->dev);
- dmfe_process_mode(db);
- /* SHOW_MEDIA_TYPE(db->op_mode); */
+ } else if (!netif_carrier_ok(dev)) {
+
+ DMFE_DBUG(0, "Link link OK", tmp_cr12);
+
+ /* Auto Sense Speed */
+ if ( !(db->media_mode & DMFE_AUTO) || !dmfe_sense_speed(db)) {
+ netif_carrier_on(dev);
+ SHOW_MEDIA_TYPE(db->op_mode);
}
+ dmfe_process_mode(db);
+ }
+
/* HPNA remote command check */
if (db->HPNA_command & 0xf00) {
db->HPNA_timer--;
@@ -1221,7 +1270,7 @@ static void dmfe_dynamic_reset(struct DEVICE *dev)
db->tx_packet_cnt = 0;
db->tx_queue_cnt = 0;
db->rx_avail_cnt = 0;
- db->link_failed = 1;
+ netif_carrier_off(dev);
db->wait_reset = 0;
/* Re-initilize DM910X board */
@@ -1259,7 +1308,8 @@ static void dmfe_reuse_skb(struct dmfe_board_info *db, struct sk_buff * skb)
if (!(rxptr->rdes0 & cpu_to_le32(0x80000000))) {
rxptr->rx_skb_ptr = skb;
- rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->data, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
+ rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev,
+ skb->data, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
wmb();
rxptr->rdes0 = cpu_to_le32(0x80000000);
db->rx_avail_cnt++;
@@ -1291,8 +1341,11 @@ static void dmfe_descriptor_init(struct dmfe_board_info *db, unsigned long ioadd
outl(db->first_tx_desc_dma, ioaddr + DCR4); /* TX DESC address */
/* rx descriptor start pointer */
- db->first_rx_desc = (void *)db->first_tx_desc + sizeof(struct tx_desc) * TX_DESC_CNT;
- db->first_rx_desc_dma = db->first_tx_desc_dma + sizeof(struct tx_desc) * TX_DESC_CNT;
+ db->first_rx_desc = (void *)db->first_tx_desc +
+ sizeof(struct tx_desc) * TX_DESC_CNT;
+
+ db->first_rx_desc_dma = db->first_tx_desc_dma +
+ sizeof(struct tx_desc) * TX_DESC_CNT;
db->rx_insert_ptr = db->first_rx_desc;
db->rx_ready_ptr = db->first_rx_desc;
outl(db->first_rx_desc_dma, ioaddr + DCR3); /* RX DESC address */
@@ -1470,7 +1523,8 @@ static void allocate_rx_buffer(struct dmfe_board_info *db)
if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL )
break;
rxptr->rx_skb_ptr = skb; /* FIXME (?) */
- rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->data, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
+ rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->data,
+ RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
wmb();
rxptr->rdes0 = cpu_to_le32(0x80000000);
rxptr = rxptr->next_rx_desc;
@@ -1510,7 +1564,8 @@ static u16 read_srom_word(long ioaddr, int offset)
for (i = 16; i > 0; i--) {
outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr);
udelay(5);
- srom_data = (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1 : 0);
+ srom_data = (srom_data << 1) |
+ ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1 : 0);
outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
udelay(5);
}
@@ -1537,9 +1592,11 @@ static u8 dmfe_sense_speed(struct dmfe_board_info * db)
if ( (phy_mode & 0x24) == 0x24 ) {
if (db->chip_id == PCI_DM9132_ID) /* DM9132 */
- phy_mode = phy_read(db->ioaddr, db->phy_addr, 7, db->chip_id) & 0xf000;
+ phy_mode = phy_read(db->ioaddr,
+ db->phy_addr, 7, db->chip_id) & 0xf000;
else /* DM9102/DM9102A */
- phy_mode = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0xf000;
+ phy_mode = phy_read(db->ioaddr,
+ db->phy_addr, 17, db->chip_id) & 0xf000;
/* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */
switch (phy_mode) {
case 0x1000: db->op_mode = DMFE_10MHF; break;
@@ -1576,8 +1633,11 @@ static void dmfe_set_phyxcer(struct dmfe_board_info *db)
/* DM9009 Chip: Phyxcer reg18 bit12=0 */
if (db->chip_id == PCI_DM9009_ID) {
- phy_reg = phy_read(db->ioaddr, db->phy_addr, 18, db->chip_id) & ~0x1000;
- phy_write(db->ioaddr, db->phy_addr, 18, phy_reg, db->chip_id);
+ phy_reg = phy_read(db->ioaddr,
+ db->phy_addr, 18, db->chip_id) & ~0x1000;
+
+ phy_write(db->ioaddr,
+ db->phy_addr, 18, phy_reg, db->chip_id);
}
/* Phyxcer capability setting */
@@ -1650,10 +1710,12 @@ static void dmfe_process_mode(struct dmfe_board_info *db)
case DMFE_100MHF: phy_reg = 0x2000; break;
case DMFE_100MFD: phy_reg = 0x2100; break;
}
- phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
+ phy_write(db->ioaddr,
+ db->phy_addr, 0, phy_reg, db->chip_id);
if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
mdelay(20);
- phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
+ phy_write(db->ioaddr,
+ db->phy_addr, 0, phy_reg, db->chip_id);
}
}
}
@@ -1663,7 +1725,8 @@ static void dmfe_process_mode(struct dmfe_board_info *db)
* Write a word to Phy register
*/
-static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id)
+static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset,
+ u16 phy_data, u32 chip_id)
{
u16 i;
unsigned long ioaddr;
@@ -1689,11 +1752,13 @@ static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data
/* Send Phy address */
for (i = 0x10; i > 0; i = i >> 1)
- phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
+ phy_write_1bit(ioaddr,
+ phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
/* Send register address */
for (i = 0x10; i > 0; i = i >> 1)
- phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0);
+ phy_write_1bit(ioaddr,
+ offset & i ? PHY_DATA_1 : PHY_DATA_0);
/* written trasnition */
phy_write_1bit(ioaddr, PHY_DATA_1);
@@ -1701,7 +1766,8 @@ static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data
/* Write a word data to PHY controller */
for ( i = 0x8000; i > 0; i >>= 1)
- phy_write_1bit(ioaddr, phy_data & i ? PHY_DATA_1 : PHY_DATA_0);
+ phy_write_1bit(ioaddr,
+ phy_data & i ? PHY_DATA_1 : PHY_DATA_0);
}
}
@@ -1738,11 +1804,13 @@ static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset, u32 chip_id)
/* Send Phy address */
for (i = 0x10; i > 0; i = i >> 1)
- phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
+ phy_write_1bit(ioaddr,
+ phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
/* Send register address */
for (i = 0x10; i > 0; i = i >> 1)
- phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0);
+ phy_write_1bit(ioaddr,
+ offset & i ? PHY_DATA_1 : PHY_DATA_0);
/* Skip transition state */
phy_read_1bit(ioaddr);
@@ -1963,7 +2031,8 @@ static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db)
/* Check remote device status match our setting ot not */
if ( phy_reg != (db->HPNA_command & 0x0f00) ) {
- phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
+ phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command,
+ db->chip_id);
db->HPNA_timer=8;
} else
db->HPNA_timer=600; /* Match, every 10 minutes, check */
@@ -2003,8 +2072,11 @@ module_param(HPNA_tx_cmd, byte, 0);
module_param(HPNA_NoiseFloor, byte, 0);
module_param(SF_mode, byte, 0);
MODULE_PARM_DESC(debug, "Davicom DM9xxx enable debugging (0-1)");
-MODULE_PARM_DESC(mode, "Davicom DM9xxx: Bit 0: 10/100Mbps, bit 2: duplex, bit 8: HomePNA");
-MODULE_PARM_DESC(SF_mode, "Davicom DM9xxx special function (bit 0: VLAN, bit 1 Flow Control, bit 2: TX pause packet)");
+MODULE_PARM_DESC(mode, "Davicom DM9xxx: "
+ "Bit 0: 10/100Mbps, bit 2: duplex, bit 8: HomePNA");
+
+MODULE_PARM_DESC(SF_mode, "Davicom DM9xxx special function "
+ "(bit 0: VLAN, bit 1 Flow Control, bit 2: TX pause packet)");
/* Description:
* when user used insmod to add module, system invoked init_module()
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 5a35354aa52..e3774a52237 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -67,7 +67,7 @@ const char * const medianame[32] = {
/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \
- || defined(__sparc_) || defined(__ia64__) \
+ || defined(__sparc__) || defined(__ia64__) \
|| defined(__sh__) || defined(__mips__)
static int rx_copybreak = 1518;
#else
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 9781b16bb8b..0d91d094edd 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -746,8 +746,7 @@ typhoon_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
{
struct typhoon *tp = netdev_priv(dev);
spin_lock_bh(&tp->state_lock);
- if(tp->vlgrp)
- tp->vlgrp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(tp->vlgrp, vid, NULL);
spin_unlock_bh(&tp->state_lock);
}
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index a2fc2bbcf97..dab88b958d6 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -3598,17 +3598,20 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Move to next BD in the ring */
if (!(bd_status & T_W))
- ugeth->txBd[txQ] = bd + sizeof(struct qe_bd);
+ bd += sizeof(struct qe_bd);
else
- ugeth->txBd[txQ] = ugeth->p_tx_bd_ring[txQ];
+ bd = ugeth->p_tx_bd_ring[txQ];
/* If the next BD still needs to be cleaned up, then the bds
are full. We need to tell the kernel to stop sending us stuff. */
if (bd == ugeth->confBd[txQ]) {
if (!netif_queue_stopped(dev))
netif_stop_queue(dev);
+ return NETDEV_TX_BUSY;
}
+ ugeth->txBd[txQ] = bd;
+
if (ugeth->p_scheduler) {
ugeth->cpucount[txQ]++;
/* Indicate to QE that there are more Tx bds ready for
@@ -3620,7 +3623,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irq(&ugeth->lock);
- return 0;
+ return NETDEV_TX_OK;
}
static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit)
@@ -3722,7 +3725,7 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
/* Handle the transmitted buffer and release */
/* the BD to be used with the current frame */
- if ((bd = ugeth->txBd[txQ]) && (netif_queue_stopped(dev) == 0))
+ if ((bd == ugeth->txBd[txQ]) && (netif_queue_stopped(dev) == 0))
break;
ugeth->stats.tx_packets++;
@@ -3741,10 +3744,12 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
/* Advance the confirmation BD pointer */
if (!(bd_status & T_W))
- ugeth->confBd[txQ] += sizeof(struct qe_bd);
+ bd += sizeof(struct qe_bd);
else
- ugeth->confBd[txQ] = ugeth->p_tx_bd_ring[txQ];
+ bd = ugeth->p_tx_bd_ring[txQ];
+ bd_status = in_be32((u32 *)bd);
}
+ ugeth->confBd[txQ] = bd;
return 0;
}
@@ -4199,9 +4204,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
ugeth->ug_info = ug_info;
ugeth->dev = dev;
- mac_addr = get_property(np, "mac-address", NULL);
- if (mac_addr == NULL)
- mac_addr = get_property(np, "local-mac-address", NULL);
+ mac_addr = of_get_mac_address(np);
if (mac_addr)
memcpy(dev->dev_addr, mac_addr, 6);
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index ebbda1d8f54..f3a972e74e9 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -30,8 +30,8 @@
*/
#define DRV_NAME "via-rhine"
-#define DRV_VERSION "1.4.2"
-#define DRV_RELDATE "Sept-11-2006"
+#define DRV_VERSION "1.4.3"
+#define DRV_RELDATE "2007-03-06"
/* A few user-configurable values.
@@ -105,6 +105,7 @@ static const int multicast_filter_limit = 32;
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
+#include <linux/dmi.h>
/* These identify the driver base version and may not be removed. */
static char version[] __devinitdata =
@@ -1995,6 +1996,23 @@ static struct pci_driver rhine_driver = {
.shutdown = rhine_shutdown,
};
+static struct dmi_system_id __initdata rhine_dmi_table[] = {
+ {
+ .ident = "EPIA-M",
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "Award Software International, Inc."),
+ DMI_MATCH(DMI_BIOS_VERSION, "6.00 PG"),
+ },
+ },
+ {
+ .ident = "KV7",
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"),
+ DMI_MATCH(DMI_BIOS_VERSION, "6.00 PG"),
+ },
+ },
+ { NULL }
+};
static int __init rhine_init(void)
{
@@ -2002,6 +2020,16 @@ static int __init rhine_init(void)
#ifdef MODULE
printk(version);
#endif
+ if (dmi_check_system(rhine_dmi_table)) {
+ /* these BIOSes fail at PXE boot if chip is in D3 */
+ avoid_D3 = 1;
+ printk(KERN_WARNING "%s: Broken BIOS detected, avoid_D3 "
+ "enabled.\n",
+ DRV_NAME);
+ }
+ else if (avoid_D3)
+ printk(KERN_INFO "%s: avoid_D3 set.\n", DRV_NAME);
+
return pci_register_driver(&rhine_driver);
}
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index e91b5a84a20..5b82e4fd0d7 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -94,7 +94,6 @@
#include <linux/device.h>
#undef COSA_SLOW_IO /* for testing purposes only */
-#undef REALLY_SLOW_IO
#include <asm/io.h>
#include <asm/dma.h>
diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
index 9040d7cf651..65ad2e24caf 100644
--- a/drivers/net/wan/hdlc.c
+++ b/drivers/net/wan/hdlc.c
@@ -38,7 +38,7 @@
#include <linux/hdlc.h>
-static const char* version = "HDLC support module revision 1.20";
+static const char* version = "HDLC support module revision 1.21";
#undef DEBUG_LINK
@@ -222,19 +222,31 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -EINVAL;
}
+static void hdlc_setup_dev(struct net_device *dev)
+{
+ /* Re-init all variables changed by HDLC protocol drivers,
+ * including ether_setup() called from hdlc_raw_eth.c.
+ */
+ dev->get_stats = hdlc_get_stats;
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+ dev->mtu = HDLC_MAX_MTU;
+ dev->type = ARPHRD_RAWHDLC;
+ dev->hard_header_len = 16;
+ dev->addr_len = 0;
+ dev->hard_header = NULL;
+ dev->rebuild_header = NULL;
+ dev->set_mac_address = NULL;
+ dev->hard_header_cache = NULL;
+ dev->header_cache_update = NULL;
+ dev->change_mtu = hdlc_change_mtu;
+ dev->hard_header_parse = NULL;
+}
+
static void hdlc_setup(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- dev->get_stats = hdlc_get_stats;
- dev->change_mtu = hdlc_change_mtu;
- dev->mtu = HDLC_MAX_MTU;
-
- dev->type = ARPHRD_RAWHDLC;
- dev->hard_header_len = 16;
-
- dev->flags = IFF_POINTOPOINT | IFF_NOARP;
-
+ hdlc_setup_dev(dev);
hdlc->carrier = 1;
hdlc->open = 0;
spin_lock_init(&hdlc->state_lock);
@@ -294,6 +306,7 @@ void detach_hdlc_protocol(struct net_device *dev)
}
kfree(hdlc->state);
hdlc->state = NULL;
+ hdlc_setup_dev(dev);
}
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index b0bc5ddcf1b..c9664fd8a91 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -365,10 +365,7 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
memcpy(&state(hdlc)->settings, &new_settings, size);
dev->hard_start_xmit = hdlc->xmit;
dev->hard_header = cisco_hard_header;
- dev->hard_header_cache = NULL;
dev->type = ARPHRD_CISCO;
- dev->flags = IFF_POINTOPOINT | IFF_NOARP;
- dev->addr_len = 0;
netif_dormant_on(dev);
return 0;
}
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index b45ab680d2d..c6c3c757d6f 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -1289,10 +1289,7 @@ static int fr_ioctl(struct net_device *dev, struct ifreq *ifr)
memcpy(&state(hdlc)->settings, &new_settings, size);
dev->hard_start_xmit = hdlc->xmit;
- dev->hard_header = NULL;
dev->type = ARPHRD_FRAD;
- dev->flags = IFF_POINTOPOINT | IFF_NOARP;
- dev->addr_len = 0;
return 0;
case IF_PROTO_FR_ADD_PVC:
diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
index e9f717070fd..4591437dd2f 100644
--- a/drivers/net/wan/hdlc_ppp.c
+++ b/drivers/net/wan/hdlc_ppp.c
@@ -127,9 +127,7 @@ static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
if (result)
return result;
dev->hard_start_xmit = hdlc->xmit;
- dev->hard_header = NULL;
dev->type = ARPHRD_PPP;
- dev->addr_len = 0;
netif_dormant_off(dev);
return 0;
}
diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c
index fe3cae5c6b9..e23bc665626 100644
--- a/drivers/net/wan/hdlc_raw.c
+++ b/drivers/net/wan/hdlc_raw.c
@@ -88,10 +88,7 @@ static int raw_ioctl(struct net_device *dev, struct ifreq *ifr)
return result;
memcpy(hdlc->state, &new_settings, size);
dev->hard_start_xmit = hdlc->xmit;
- dev->hard_header = NULL;
dev->type = ARPHRD_RAWHDLC;
- dev->flags = IFF_POINTOPOINT | IFF_NOARP;
- dev->addr_len = 0;
netif_dormant_off(dev);
return 0;
}
diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c
index e4bb9f8ad43..cd7b22f50ed 100644
--- a/drivers/net/wan/hdlc_x25.c
+++ b/drivers/net/wan/hdlc_x25.c
@@ -215,9 +215,7 @@ static int x25_ioctl(struct net_device *dev, struct ifreq *ifr)
x25_rx, 0)) != 0)
return result;
dev->hard_start_xmit = x25_xmit;
- dev->hard_header = NULL;
dev->type = ARPHRD_X25;
- dev->addr_len = 0;
netif_dormant_off(dev);
return 0;
}
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index 8dbcf83bb5f..8b4540bfc1b 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -407,7 +407,7 @@ static void z8530_tx(struct z8530_channel *c)
while(c->txcount) {
/* FIFO full ? */
if(!(read_zsreg(c, R0)&4))
- break;
+ return;
c->txcount--;
/*
* Shovel out the byte
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 73c831a3b74..80cb88eb98c 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -1858,9 +1858,6 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id)
spin_lock(&bcm->irq_lock);
- assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
- assert(bcm->current_core->id == BCM43xx_COREID_80211);
-
reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
if (reason == 0xffffffff) {
/* irq not for us (shared irq) */
@@ -1871,6 +1868,9 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id)
if (!reason)
goto out;
+ assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
+ assert(bcm->current_core->id == BCM43xx_COREID_80211);
+
bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA0_REASON)
& 0x0001DC00;
bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
@@ -2733,8 +2733,9 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
* dangling pins on the second core. Be careful
* and ignore these cores here.
*/
- if (bcm->pci_dev->device != 0x4324) {
- dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n");
+ if (1 /*bcm->pci_dev->device != 0x4324*/ ) {
+ /* TODO: A PHY */
+ dprintk(KERN_INFO PFX "Ignoring additional 802.11a core.\n");
continue;
}
}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index 3a5c9c2b215..cae89258a64 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -859,6 +859,11 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm)
bcm43xx_radio_write16(bcm, 0x005D, 0x0088);
bcm43xx_radio_write16(bcm, 0x005E, 0x0088);
bcm43xx_radio_write16(bcm, 0x007D, 0x0088);
+ bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
+ BCM43xx_UCODEFLAGS_OFFSET,
+ (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED,
+ BCM43xx_UCODEFLAGS_OFFSET)
+ | 0x00000200));
}
if (radio->revision == 8) {
bcm43xx_radio_write16(bcm, 0x0051, 0x0000);
@@ -941,7 +946,8 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0038, 0x0668);
bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
if (radio->revision <= 5)
- bcm43xx_phy_write(bcm, 0x005D, bcm43xx_phy_read(bcm, 0x005D) | 0x0003);
+ bcm43xx_phy_write(bcm, 0x005D, (bcm43xx_phy_read(bcm, 0x005D)
+ & 0xFF80) | 0x0003);
if (radio->revision <= 2)
bcm43xx_radio_write16(bcm, 0x005D, 0x000D);
@@ -958,7 +964,7 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0016, 0x0410);
bcm43xx_phy_write(bcm, 0x0017, 0x0820);
bcm43xx_phy_write(bcm, 0x0062, 0x0007);
- (void) bcm43xx_radio_calibrationvalue(bcm);
+ bcm43xx_radio_init2050(bcm);
bcm43xx_phy_lo_g_measure(bcm);
if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
bcm43xx_calc_nrssi_slope(bcm);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index 7b665e2386a..d6d9413d7f2 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -105,18 +105,24 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;
u8 channel;
+ s8 expon;
int freq;
int err = -EINVAL;
mutex_lock(&bcm->mutex);
spin_lock_irqsave(&bcm->irq_lock, flags);
- if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
+ if ((data->freq.e == 0) &&
+ (data->freq.m >= 0) && (data->freq.m <= 1000)) {
channel = data->freq.m;
freq = bcm43xx_channel_to_freq(bcm, channel);
} else {
- channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
freq = data->freq.m;
+ expon = 6 - data->freq.e;
+ while (--expon >= 0) /* scale down the frequency to MHz */
+ freq /= 10;
+ assert(freq > 1000);
+ channel = bcm43xx_freq_to_channel(bcm, freq);
}
if (!ieee80211_is_valid_channel(bcm->ieee, channel))
goto out_unlock;
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index c250f08c8dd..ce9230b2f63 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -26,7 +26,6 @@
* Tested with Planet AP in 2.5.73-bk, 216 Kbytes/s in Infrastructure mode
* with a SMP machine (dual pentium 100), using pktgen, 432 pps (pkt_size = 60)
*/
-#undef REALLY_SLOW_IO /* most systems can safely undef this */
#include <linux/delay.h>
#include <linux/types.h>
diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c
index 07dc2b6d4e9..9bb4db552f3 100644
--- a/drivers/parisc/hppb.c
+++ b/drivers/parisc/hppb.c
@@ -10,10 +10,6 @@
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
-** This Driver currently only supports the console (port 0) on the MUX.
-** Additional work will be needed on this driver to enable the full
-** functionality of the MUX.
-**
*/
#include <linux/types.h>
@@ -67,7 +63,7 @@ static int hppb_probe(struct parisc_device *dev)
}
card = card->next;
}
- printk(KERN_INFO "Found GeckoBoa at 0x%lx\n", dev->hpa.start);
+ printk(KERN_INFO "Found GeckoBoa at 0x%x\n", dev->hpa.start);
card->hpa = dev->hpa.start;
card->mmio_region.name = "HP-PB Bus";
@@ -78,16 +74,18 @@ static int hppb_probe(struct parisc_device *dev)
status = ccio_request_resource(dev, &card->mmio_region);
if(status < 0) {
- printk(KERN_ERR "%s: failed to claim HP-PB bus space (%08lx, %08lx)\n",
+ printk(KERN_ERR "%s: failed to claim HP-PB bus space (%08x, %08x)\n",
__FILE__, card->mmio_region.start, card->mmio_region.end);
}
return 0;
}
-
static struct parisc_device_id hppb_tbl[] = {
- { HPHW_BCPORT, HVERSION_REV_ANY_ID, 0x500, 0xc },
+ { HPHW_BCPORT, HVERSION_REV_ANY_ID, 0x500, 0xc }, /* E25 and K */
+ { HPHW_BCPORT, 0x0, 0x501, 0xc }, /* E35 */
+ { HPHW_BCPORT, 0x0, 0x502, 0xc }, /* E45 */
+ { HPHW_BCPORT, 0x0, 0x503, 0xc }, /* E55 */
{ 0, }
};
diff --git a/drivers/parisc/iosapic_private.h b/drivers/parisc/iosapic_private.h
index 41e7ec2a44a..6e05e30a245 100644
--- a/drivers/parisc/iosapic_private.h
+++ b/drivers/parisc/iosapic_private.h
@@ -132,7 +132,7 @@ struct iosapic_irt {
struct vector_info {
struct iosapic_info *iosapic; /* I/O SAPIC this vector is on */
struct irt_entry *irte; /* IRT entry */
- u32 *eoi_addr; /* precalculate EOI reg address */
+ u32 __iomem *eoi_addr; /* precalculate EOI reg address */
u32 eoi_data; /* IA64: ? PA: swapped txn_data */
int txn_irq; /* virtual IRQ number for processor */
ulong txn_addr; /* IA64: id_eid PA: partial HPA */
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index ba6769934c7..21c4c299b3d 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -168,7 +168,8 @@ lba_dump_res(struct resource *r, int d)
printk(KERN_DEBUG "(%p)", r->parent);
for (i = d; i ; --i) printk(" ");
- printk(KERN_DEBUG "%p [%lx,%lx]/%lx\n", r, r->start, r->end, r->flags);
+ printk(KERN_DEBUG "%p [%lx,%lx]/%lx\n", r,
+ (long)r->start, (long)r->end, r->flags);
lba_dump_res(r->child, d+2);
lba_dump_res(r->sibling, d);
}
@@ -647,7 +648,7 @@ truncate_pat_collision(struct resource *root, struct resource *new)
printk(KERN_WARNING "LBA: Truncating lmmio_space [%lx/%lx] "
"to [%lx,%lx]\n",
start, end,
- new->start, new->end );
+ (long)new->start, (long)new->end );
return 0; /* truncation successful */
}
@@ -715,8 +716,8 @@ lba_fixup_bus(struct pci_bus *bus)
printk("FAILED: lba_fixup_bus() request for "
"elmmio_space [%lx/%lx]\n",
- ldev->hba.elmmio_space.start,
- ldev->hba.elmmio_space.end);
+ (long)ldev->hba.elmmio_space.start,
+ (long)ldev->hba.elmmio_space.end);
/* lba_dump_res(&iomem_resource, 2); */
/* BUG(); */
@@ -738,15 +739,15 @@ lba_fixup_bus(struct pci_bus *bus)
&(ldev->hba.lmmio_space))) {
printk(KERN_WARNING "LBA: lmmio_space [%lx/%lx] duplicate!\n",
- ldev->hba.lmmio_space.start,
- ldev->hba.lmmio_space.end);
+ (long)ldev->hba.lmmio_space.start,
+ (long)ldev->hba.lmmio_space.end);
} else {
err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space));
if (err < 0) {
printk(KERN_ERR "FAILED: lba_fixup_bus() request for "
"lmmio_space [%lx/%lx]\n",
- ldev->hba.lmmio_space.start,
- ldev->hba.lmmio_space.end);
+ (long)ldev->hba.lmmio_space.start,
+ (long)ldev->hba.lmmio_space.end);
} else
bus->resource[i++] = &(ldev->hba.lmmio_space);
}
@@ -758,8 +759,8 @@ lba_fixup_bus(struct pci_bus *bus)
if (err < 0) {
printk("FAILED: lba_fixup_bus() request for "
"gmmio_space [%lx/%lx]\n",
- ldev->hba.gmmio_space.start,
- ldev->hba.gmmio_space.end);
+ (long)ldev->hba.gmmio_space.start,
+ (long)ldev->hba.gmmio_space.end);
lba_dump_res(&iomem_resource, 2);
BUG();
}
@@ -980,7 +981,7 @@ LBA_PORT_IN(32, 0)
#define LBA_PORT_OUT(size, mask) \
static void lba_pat_out##size (struct pci_hba_data *l, u16 addr, u##size val) \
{ \
- void *where = (void *) PIOP_TO_GMMIO(LBA_DEV(l), addr); \
+ void __iomem *where = PIOP_TO_GMMIO(LBA_DEV(l), addr); \
DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, l, addr, val); \
WRITE_REG##size(val, where); \
/* flush the I/O down to the elroy at least */ \
@@ -1063,16 +1064,16 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
/* used to fix up pre-initialized MEM BARs */
if (!lba_dev->hba.lmmio_space.start) {
sprintf(lba_dev->hba.lmmio_name,
- "PCI%02lx LMMIO",
- lba_dev->hba.bus_num.start);
+ "PCI%02x LMMIO",
+ (int)lba_dev->hba.bus_num.start);
lba_dev->hba.lmmio_space_offset = p->start -
io->start;
r = &lba_dev->hba.lmmio_space;
r->name = lba_dev->hba.lmmio_name;
} else if (!lba_dev->hba.elmmio_space.start) {
sprintf(lba_dev->hba.elmmio_name,
- "PCI%02lx ELMMIO",
- lba_dev->hba.bus_num.start);
+ "PCI%02x ELMMIO",
+ (int)lba_dev->hba.bus_num.start);
r = &lba_dev->hba.elmmio_space;
r->name = lba_dev->hba.elmmio_name;
} else {
@@ -1089,8 +1090,8 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
case PAT_GMMIO:
/* MMIO space > 4GB phys addr; for 64-bit BAR */
- sprintf(lba_dev->hba.gmmio_name, "PCI%02lx GMMIO",
- lba_dev->hba.bus_num.start);
+ sprintf(lba_dev->hba.gmmio_name, "PCI%02x GMMIO",
+ (int)lba_dev->hba.bus_num.start);
r = &lba_dev->hba.gmmio_space;
r->name = lba_dev->hba.gmmio_name;
r->start = p->start;
@@ -1112,8 +1113,8 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
*/
lba_dev->iop_base = ioremap_nocache(p->start, 64 * 1024 * 1024);
- sprintf(lba_dev->hba.io_name, "PCI%02lx Ports",
- lba_dev->hba.bus_num.start);
+ sprintf(lba_dev->hba.io_name, "PCI%02x Ports",
+ (int)lba_dev->hba.bus_num.start);
r = &lba_dev->hba.io_space;
r->name = lba_dev->hba.io_name;
r->start = HBA_PORT_BASE(lba_dev->hba.hba_num);
@@ -1166,8 +1167,8 @@ lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
** Legacy boxes but it's nice to see in /proc/iomem.
*/
r = &(lba_dev->hba.lmmio_space);
- sprintf(lba_dev->hba.lmmio_name, "PCI%02lx LMMIO",
- lba_dev->hba.bus_num.start);
+ sprintf(lba_dev->hba.lmmio_name, "PCI%02x LMMIO",
+ (int)lba_dev->hba.bus_num.start);
r->name = lba_dev->hba.lmmio_name;
#if 1
@@ -1275,8 +1276,8 @@ lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
** an existing (but unused portion of) distributed range.
*/
r = &(lba_dev->hba.elmmio_space);
- sprintf(lba_dev->hba.elmmio_name, "PCI%02lx ELMMIO",
- lba_dev->hba.bus_num.start);
+ sprintf(lba_dev->hba.elmmio_name, "PCI%02x ELMMIO",
+ (int)lba_dev->hba.bus_num.start);
r->name = lba_dev->hba.elmmio_name;
#if 1
@@ -1297,8 +1298,8 @@ lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
#endif
r = &(lba_dev->hba.io_space);
- sprintf(lba_dev->hba.io_name, "PCI%02lx Ports",
- lba_dev->hba.bus_num.start);
+ sprintf(lba_dev->hba.io_name, "PCI%02x Ports",
+ (int)lba_dev->hba.bus_num.start);
r->name = lba_dev->hba.io_name;
r->flags = IORESOURCE_IO;
r->start = READ_REG32(lba_dev->hba.base_addr + LBA_IOS_BASE) & ~1L;
@@ -1406,13 +1407,20 @@ lba_hw_init(struct lba_device *d)
return 0;
}
-
+/*
+ * Unfortunately, when firmware numbers busses, it doesn't take into account
+ * Cardbus bridges. So we have to renumber the busses to suit ourselves.
+ * Elroy/Mercury don't actually know what bus number they're attached to;
+ * we use bus 0 to indicate the directly attached bus and any other bus
+ * number will be taken care of by the PCI-PCI bridge.
+ */
+static unsigned int lba_next_bus = 0;
/*
-** Determine if lba should claim this chip (return 0) or not (return 1).
-** If so, initialize the chip and tell other partners in crime they
-** have work to do.
-*/
+ * Determine if lba should claim this chip (return 0) or not (return 1).
+ * If so, initialize the chip and tell other partners in crime they
+ * have work to do.
+ */
static int __init
lba_driver_probe(struct parisc_device *dev)
{
@@ -1440,7 +1448,7 @@ lba_driver_probe(struct parisc_device *dev)
}
printk(KERN_INFO "Elroy version %s (0x%x) found at 0x%lx\n",
- version, func_class & 0xf, dev->hpa.start);
+ version, func_class & 0xf, (long)dev->hpa.start);
if (func_class < 2) {
printk(KERN_WARNING "Can't support LBA older than "
@@ -1470,17 +1478,16 @@ lba_driver_probe(struct parisc_device *dev)
*/
printk(KERN_INFO "%s version TR%d.%d (0x%x) found at 0x%lx\n",
IS_MERCURY(dev) ? "Mercury" : "Quicksilver", major,
- minor, func_class, dev->hpa.start);
+ minor, func_class, (long)dev->hpa.start);
cfg_ops = &mercury_cfg_ops;
} else {
- printk(KERN_ERR "Unknown LBA found at 0x%lx\n", dev->hpa.start);
+ printk(KERN_ERR "Unknown LBA found at 0x%lx\n",
+ (long)dev->hpa.start);
return -ENODEV;
}
- /*
- ** Tell I/O SAPIC driver we have a IRQ handler/region.
- */
+ /* Tell I/O SAPIC driver we have a IRQ handler/region. */
tmp_obj = iosapic_register(dev->hpa.start + LBA_IOSAPIC_BASE);
/* NOTE: PCI devices (e.g. 103c:1005 graphics card) which don't
@@ -1529,16 +1536,17 @@ lba_driver_probe(struct parisc_device *dev)
lba_legacy_resources(dev, lba_dev);
}
- /*
- ** Tell PCI support another PCI bus was found.
- ** Walks PCI bus for us too.
- */
+ if (lba_dev->hba.bus_num.start < lba_next_bus)
+ lba_dev->hba.bus_num.start = lba_next_bus;
+
dev->dev.platform_data = lba_dev;
lba_bus = lba_dev->hba.hba_bus =
pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start,
cfg_ops, NULL);
- if (lba_bus)
+ if (lba_bus) {
+ lba_next_bus = lba_bus->subordinate + 1;
pci_bus_add_devices(lba_bus);
+ }
/* This is in lieu of calling pci_assign_unassigned_resources() */
if (is_pdc_pat()) {
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index 9a731c101d1..d190c05d87e 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -66,8 +66,8 @@ static char lcd_text_default[32] __read_mostly;
static struct workqueue_struct *led_wq;
-static void led_work_func(void *);
-static DECLARE_WORK(led_task, led_work_func, NULL);
+static void led_work_func(struct work_struct *);
+static DECLARE_DELAYED_WORK(led_task, led_work_func);
#if 0
#define DPRINTK(x) printk x
@@ -136,7 +136,7 @@ static int start_task(void)
/* Create the work queue and queue the LED task */
led_wq = create_singlethread_workqueue("led_wq");
- queue_work(led_wq, &led_task);
+ queue_delayed_work(led_wq, &led_task, 0);
return 0;
}
@@ -441,7 +441,7 @@ static __inline__ int led_get_diskio_activity(void)
#define LED_UPDATE_INTERVAL (1 + (HZ*19/1000))
-static void led_work_func (void *unused)
+static void led_work_func (struct work_struct *unused)
{
static unsigned long last_jiffies;
static unsigned long count_HZ; /* counter in range 0..HZ */
@@ -588,7 +588,7 @@ int __init register_led_driver(int model, unsigned long cmd_reg, unsigned long d
/* Ensure the work is queued */
if (led_wq) {
- queue_work(led_wq, &led_task);
+ queue_delayed_work(led_wq, &led_task, 0);
}
return 0;
@@ -629,7 +629,7 @@ void __init register_led_regions(void)
** avoid a race condition while writing the CMD/DATA register pair.
**
*/
-int lcd_print( char *str )
+int lcd_print( const char *str )
{
int i;
@@ -658,7 +658,7 @@ int lcd_print( char *str )
/* re-queue the work */
if (led_wq) {
- queue_work(led_wq, &led_task);
+ queue_delayed_work(led_wq, &led_task, 0);
}
return lcd_info.lcd_width;
diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c
index 97e9dc066f9..6dedbdef710 100644
--- a/drivers/parisc/power.c
+++ b/drivers/parisc/power.c
@@ -2,7 +2,7 @@
* linux/drivers/parisc/power.c
* HP PARISC soft power switch support driver
*
- * Copyright (c) 2001-2005 Helge Deller <deller@gmx.de>
+ * Copyright (c) 2001-2007 Helge Deller <deller@gmx.de>
* All rights reserved.
*
*
@@ -29,7 +29,6 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
*
*
- *
* HINT:
* Support of the soft power switch button may be enabled or disabled at
* runtime through the "/proc/sys/kernel/power" procfs entry.
@@ -38,34 +37,28 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/string.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
+#include <linux/kthread.h>
#include <asm/pdc.h>
#include <asm/io.h>
#include <asm/led.h>
-#include <asm/uaccess.h>
+#define DRIVER_NAME "powersw"
+#define KTHREAD_NAME "kpowerswd"
-#ifdef DEBUG
-# define DPRINTK(x...) printk(x)
-#else
-# define DPRINTK(x...)
-#endif
-
-
-/* filename in /proc which can be used to enable/disable the power switch */
-#define SYSCTL_FILENAME "sys/kernel/power"
+/* how often should the power button be polled ? */
+#define POWERSWITCH_POLL_PER_SEC 2
+/* how long does the power button needs to be down until we react ? */
+#define POWERSWITCH_DOWN_SEC 2
+/* assembly code to access special registers */
+/* taken from PCXL ERS page 82 */
#define DIAG_CODE(code) (0x14000000 + ((code)<<5))
-/* this will go to processor.h or any other place... */
-/* taken from PCXL ERS page 82 */
#define MFCPU_X(rDiagReg, t_ch, t_th, code) \
(DIAG_CODE(code) + ((rDiagReg)<<21) + ((t_ch)<<16) + ((t_th)<<0) )
@@ -76,111 +69,95 @@
#define __getDIAG(dr) ( { \
register unsigned long __res asm("r28");\
__asm__ __volatile__ ( \
- ".word %1\n nop\n" : "=&r" (__res) : "i" (MFCPU_T(dr,28)) \
+ ".word %1" : "=&r" (__res) : "i" (MFCPU_T(dr,28) ) \
); \
__res; \
} )
-
-static void deferred_poweroff(void *dummy)
-{
- if (kill_cad_pid(SIGINT, 1)) {
- /* just in case killing init process failed */
- machine_power_off();
- }
-}
-
-/*
- * This function gets called from interrupt context.
- * As it's called within an interrupt, it wouldn't sync if we don't
- * use schedule_work().
- */
-
-static DECLARE_WORK(poweroff_work, deferred_poweroff, NULL);
-
-static void poweroff(void)
-{
- static int powering_off __read_mostly;
-
- if (powering_off)
- return;
-
- powering_off++;
- schedule_work(&poweroff_work);
-}
-
-
-/* local time-counter for shutdown */
+/* local shutdown counter */
static int shutdown_timer __read_mostly;
/* check, give feedback and start shutdown after one second */
static void process_shutdown(void)
{
if (shutdown_timer == 0)
- DPRINTK(KERN_INFO "Shutdown requested...\n");
+ printk(KERN_ALERT KTHREAD_NAME ": Shutdown requested...\n");
shutdown_timer++;
/* wait until the button was pressed for 1 second */
- if (shutdown_timer == HZ) {
-#if defined (DEBUG) || defined(CONFIG_CHASSIS_LCD_LED)
- static char msg[] = "Shutting down...";
-#endif
- DPRINTK(KERN_INFO "%s\n", msg);
+ if (shutdown_timer == (POWERSWITCH_DOWN_SEC*POWERSWITCH_POLL_PER_SEC)) {
+ static const char msg[] = "Shutting down...";
+ printk(KERN_INFO KTHREAD_NAME ": %s\n", msg);
lcd_print(msg);
- poweroff();
+
+ /* send kill signal */
+ if (kill_cad_pid(SIGINT, 1)) {
+ /* just in case killing init process failed */
+ if (pm_power_off)
+ pm_power_off();
+ }
}
}
-/* main power switch tasklet struct (scheduled from time.c) */
-DECLARE_TASKLET_DISABLED(power_tasklet, NULL, 0);
+/* main power switch task struct */
+static struct task_struct *power_task;
+
+/* filename in /proc which can be used to enable/disable the power switch */
+#define SYSCTL_FILENAME "sys/kernel/power"
/* soft power switch enabled/disabled */
int pwrsw_enabled __read_mostly = 1;
-/*
- * On gecko style machines (e.g. 712/xx and 715/xx)
- * the power switch status is stored in Bit 0 ("the highest bit")
- * of CPU diagnose register 25.
- *
- */
-static void gecko_tasklet_func(unsigned long unused)
+/* main kernel thread worker. It polls the button state */
+static int kpowerswd(void *param)
{
- if (unlikely(!pwrsw_enabled))
- return;
-
- if (__getDIAG(25) & 0x80000000) {
- /* power switch button not pressed or released again */
- /* Warning: Some machines do never reset this DIAG flag! */
- shutdown_timer = 0;
- } else {
- process_shutdown();
- }
-}
-
+ __set_current_state(TASK_RUNNING);
+
+ do {
+ int button_not_pressed;
+ unsigned long soft_power_reg = (unsigned long) param;
+
+ schedule_timeout_interruptible(pwrsw_enabled ? HZ : HZ/POWERSWITCH_POLL_PER_SEC);
+ __set_current_state(TASK_RUNNING);
+
+ if (unlikely(!pwrsw_enabled))
+ continue;
+
+ if (soft_power_reg) {
+ /*
+ * Non-Gecko-style machines:
+ * Check the power switch status which is read from the
+ * real I/O location at soft_power_reg.
+ * Bit 31 ("the lowest bit) is the status of the power switch.
+ * This bit is "1" if the button is NOT pressed.
+ */
+ button_not_pressed = (gsc_readl(soft_power_reg) & 0x1);
+ } else {
+ /*
+ * On gecko style machines (e.g. 712/xx and 715/xx)
+ * the power switch status is stored in Bit 0 ("the highest bit")
+ * of CPU diagnose register 25.
+ * Warning: Some machines never reset the DIAG flag, even if
+ * the button has been released again.
+ */
+ button_not_pressed = (__getDIAG(25) & 0x80000000);
+ }
+
+ if (likely(button_not_pressed)) {
+ if (unlikely(shutdown_timer && /* avoid writing if not necessary */
+ shutdown_timer < (POWERSWITCH_DOWN_SEC*POWERSWITCH_POLL_PER_SEC))) {
+ shutdown_timer = 0;
+ printk(KERN_INFO KTHREAD_NAME ": Shutdown request aborted.\n");
+ }
+ } else
+ process_shutdown();
+
+
+ } while (!kthread_should_stop());
-
-/*
- * Check the power switch status which is read from the
- * real I/O location at soft_power_reg.
- * Bit 31 ("the lowest bit) is the status of the power switch.
- */
-
-static void polling_tasklet_func(unsigned long soft_power_reg)
-{
- unsigned long current_status;
-
- if (unlikely(!pwrsw_enabled))
- return;
-
- current_status = gsc_readl(soft_power_reg);
- if (current_status & 0x1) {
- /* power switch button not pressed */
- shutdown_timer = 0;
- } else {
- process_shutdown();
- }
+ return 0;
}
@@ -220,7 +197,7 @@ static struct notifier_block parisc_panic_block = {
static int __init power_init(void)
{
unsigned long ret;
- unsigned long soft_power_reg = 0;
+ unsigned long soft_power_reg;
#if 0
request_irq( IRQ_FROM_REGION(CPU_IRQ_REGION)+2, &powerfail_interrupt,
@@ -235,44 +212,44 @@ static int __init power_init(void)
soft_power_reg = -1UL;
switch (soft_power_reg) {
- case 0: printk(KERN_INFO "Gecko-style soft power switch enabled.\n");
- power_tasklet.func = gecko_tasklet_func;
+ case 0: printk(KERN_INFO DRIVER_NAME ": Gecko-style soft power switch enabled.\n");
break;
- case -1UL: printk(KERN_INFO "Soft power switch support not available.\n");
+ case -1UL: printk(KERN_INFO DRIVER_NAME ": Soft power switch support not available.\n");
return -ENODEV;
- default: printk(KERN_INFO "Soft power switch enabled, polling @ 0x%08lx.\n",
+ default: printk(KERN_INFO DRIVER_NAME ": Soft power switch at 0x%08lx enabled.\n",
soft_power_reg);
- power_tasklet.data = soft_power_reg;
- power_tasklet.func = polling_tasklet_func;
+ }
+
+ power_task = kthread_run(kpowerswd, (void*)soft_power_reg, KTHREAD_NAME);
+ if (IS_ERR(power_task)) {
+ printk(KERN_ERR DRIVER_NAME ": thread creation failed. Driver not loaded.\n");
+ pdc_soft_power_button(0);
+ return -EIO;
}
/* Register a call for panic conditions. */
atomic_notifier_chain_register(&panic_notifier_list,
&parisc_panic_block);
- tasklet_enable(&power_tasklet);
-
return 0;
}
static void __exit power_exit(void)
{
- if (!power_tasklet.func)
- return;
+ kthread_stop(power_task);
- tasklet_disable(&power_tasklet);
atomic_notifier_chain_unregister(&panic_notifier_list,
&parisc_panic_block);
- power_tasklet.func = NULL;
+
pdc_soft_power_button(0);
}
-module_init(power_init);
+arch_initcall(power_init);
module_exit(power_exit);
-MODULE_AUTHOR("Helge Deller");
+MODULE_AUTHOR("Helge Deller <deller@gmx.de>");
MODULE_DESCRIPTION("Soft power switch driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index 76a29dadd51..322957ac2ad 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -109,7 +109,7 @@ static unsigned long piranha_bad_128k = 0;
#ifdef SBA_AGP_SUPPORT
static int sba_reserve_agpgart = 1;
-module_param(sba_reserve_agpgart, int, 1);
+module_param(sba_reserve_agpgart, int, 0444);
MODULE_PARM_DESC(sba_reserve_agpgart, "Reserve half of IO pdir as AGPGART");
#endif
@@ -846,7 +846,7 @@ static void *sba_alloc_consistent(struct device *hwdev, size_t size,
if (!hwdev) {
/* only support PCI */
*dma_handle = 0;
- return 0;
+ return NULL;
}
ret = (void *) __get_free_pages(gfp, get_order(size));
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 68555c11f55..01869b1782e 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -38,6 +38,36 @@ static int msi_cache_init(void)
return 0;
}
+static void msi_set_enable(struct pci_dev *dev, int enable)
+{
+ int pos;
+ u16 control;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+ if (pos) {
+ pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
+ control &= ~PCI_MSI_FLAGS_ENABLE;
+ if (enable)
+ control |= PCI_MSI_FLAGS_ENABLE;
+ pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
+ }
+}
+
+static void msix_set_enable(struct pci_dev *dev, int enable)
+{
+ int pos;
+ u16 control;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+ if (pos) {
+ pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
+ control &= ~PCI_MSIX_FLAGS_ENABLE;
+ if (enable)
+ control |= PCI_MSIX_FLAGS_ENABLE;
+ pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
+ }
+}
+
static void msi_set_mask_bit(unsigned int irq, int flag)
{
struct msi_desc *entry;
@@ -55,6 +85,8 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
mask_bits &= ~(1);
mask_bits |= flag;
pci_write_config_dword(entry->dev, pos, mask_bits);
+ } else {
+ msi_set_enable(entry->dev, !flag);
}
break;
case PCI_CAP_ID_MSIX:
@@ -192,44 +224,6 @@ static struct msi_desc* alloc_msi_entry(void)
return entry;
}
-static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
-{
- u16 control;
-
- pci_read_config_word(dev, msi_control_reg(pos), &control);
- if (type == PCI_CAP_ID_MSI) {
- /* Set enabled bits to single MSI & enable MSI_enable bit */
- msi_enable(control, 1);
- pci_write_config_word(dev, msi_control_reg(pos), control);
- dev->msi_enabled = 1;
- } else {
- msix_enable(control);
- pci_write_config_word(dev, msi_control_reg(pos), control);
- dev->msix_enabled = 1;
- }
-
- pci_intx(dev, 0); /* disable intx */
-}
-
-void disable_msi_mode(struct pci_dev *dev, int pos, int type)
-{
- u16 control;
-
- pci_read_config_word(dev, msi_control_reg(pos), &control);
- if (type == PCI_CAP_ID_MSI) {
- /* Set enabled bits to single MSI & enable MSI_enable bit */
- msi_disable(control);
- pci_write_config_word(dev, msi_control_reg(pos), control);
- dev->msi_enabled = 0;
- } else {
- msix_disable(control);
- pci_write_config_word(dev, msi_control_reg(pos), control);
- dev->msix_enabled = 0;
- }
-
- pci_intx(dev, 1); /* enable intx */
-}
-
#ifdef CONFIG_PM
static int __pci_save_msi_state(struct pci_dev *dev)
{
@@ -238,12 +232,11 @@ static int __pci_save_msi_state(struct pci_dev *dev)
struct pci_cap_saved_state *save_state;
u32 *cap;
- pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- if (pos <= 0 || dev->no_msi)
+ if (!dev->msi_enabled)
return 0;
- pci_read_config_word(dev, msi_control_reg(pos), &control);
- if (!(control & PCI_MSI_FLAGS_ENABLE))
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+ if (pos <= 0)
return 0;
save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u32) * 5,
@@ -276,13 +269,18 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
struct pci_cap_saved_state *save_state;
u32 *cap;
+ if (!dev->msi_enabled)
+ return;
+
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSI);
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
if (!save_state || pos <= 0)
return;
cap = &save_state->data[0];
+ pci_intx(dev, 0); /* disable intx */
control = cap[i++] >> 16;
+ msi_set_enable(dev, 0);
pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, cap[i++]);
if (control & PCI_MSI_FLAGS_64BIT) {
pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, cap[i++]);
@@ -292,7 +290,6 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
if (control & PCI_MSI_FLAGS_MASKBIT)
pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, cap[i++]);
pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
- enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
pci_remove_saved_cap(save_state);
kfree(save_state);
}
@@ -308,13 +305,11 @@ static int __pci_save_msix_state(struct pci_dev *dev)
return 0;
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos <= 0 || dev->no_msi)
+ if (pos <= 0)
return 0;
/* save the capability */
pci_read_config_word(dev, msi_control_reg(pos), &control);
- if (!(control & PCI_MSIX_FLAGS_ENABLE))
- return 0;
save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u16),
GFP_KERNEL);
if (!save_state) {
@@ -376,6 +371,8 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
return;
/* route the table */
+ pci_intx(dev, 0); /* disable intx */
+ msix_set_enable(dev, 0);
irq = head = dev->first_msi_irq;
while (head != tail) {
entry = get_irq_msi(irq);
@@ -386,7 +383,6 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
}
pci_write_config_word(dev, msi_control_reg(pos), save);
- enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
}
void pci_restore_msi_state(struct pci_dev *dev)
@@ -411,6 +407,8 @@ static int msi_capability_init(struct pci_dev *dev)
int pos, irq;
u16 control;
+ msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */
+
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
pci_read_config_word(dev, msi_control_reg(pos), &control);
/* MSI Entry Initialization */
@@ -454,7 +452,9 @@ static int msi_capability_init(struct pci_dev *dev)
set_irq_msi(irq, entry);
/* Set MSI enabled bits */
- enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+ pci_intx(dev, 0); /* disable intx */
+ msi_set_enable(dev, 1);
+ dev->msi_enabled = 1;
dev->irq = irq;
return 0;
@@ -481,6 +481,8 @@ static int msix_capability_init(struct pci_dev *dev,
u8 bir;
void __iomem *base;
+ msix_set_enable(dev, 0);/* Ensure msix is disabled as I set it up */
+
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
/* Request & Map MSI-X table region */
pci_read_config_word(dev, msi_control_reg(pos), &control);
@@ -549,7 +551,9 @@ static int msix_capability_init(struct pci_dev *dev,
}
dev->first_msi_irq = entries[0].vector;
/* Set MSI-X enabled bits */
- enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
+ pci_intx(dev, 0); /* disable intx */
+ msix_set_enable(dev, 1);
+ dev->msix_enabled = 1;
return 0;
}
@@ -611,12 +615,11 @@ int pci_enable_msi(struct pci_dev* dev)
WARN_ON(!!dev->msi_enabled);
/* Check whether driver already requested for MSI-X irqs */
- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos > 0 && dev->msix_enabled) {
- printk(KERN_INFO "PCI: %s: Can't enable MSI. "
- "Device already has MSI-X enabled\n",
- pci_name(dev));
- return -EINVAL;
+ if (dev->msix_enabled) {
+ printk(KERN_INFO "PCI: %s: Can't enable MSI. "
+ "Device already has MSI-X enabled\n",
+ pci_name(dev));
+ return -EINVAL;
}
status = msi_capability_init(dev);
return status;
@@ -625,8 +628,7 @@ int pci_enable_msi(struct pci_dev* dev)
void pci_disable_msi(struct pci_dev* dev)
{
struct msi_desc *entry;
- int pos, default_irq;
- u16 control;
+ int default_irq;
if (!pci_msi_enable)
return;
@@ -636,16 +638,9 @@ void pci_disable_msi(struct pci_dev* dev)
if (!dev->msi_enabled)
return;
- pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- if (!pos)
- return;
-
- pci_read_config_word(dev, msi_control_reg(pos), &control);
- if (!(control & PCI_MSI_FLAGS_ENABLE))
- return;
-
-
- disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+ msi_set_enable(dev, 0);
+ pci_intx(dev, 1); /* enable intx */
+ dev->msi_enabled = 0;
entry = get_irq_msi(dev->first_msi_irq);
if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
@@ -746,8 +741,7 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
WARN_ON(!!dev->msix_enabled);
/* Check whether driver already requested for MSI irq */
- if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 &&
- dev->msi_enabled) {
+ if (dev->msi_enabled) {
printk(KERN_INFO "PCI: %s: Can't enable MSI-X. "
"Device already has an MSI irq assigned\n",
pci_name(dev));
@@ -760,8 +754,6 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
void pci_disable_msix(struct pci_dev* dev)
{
int irq, head, tail = 0, warning = 0;
- int pos;
- u16 control;
if (!pci_msi_enable)
return;
@@ -771,15 +763,9 @@ void pci_disable_msix(struct pci_dev* dev)
if (!dev->msix_enabled)
return;
- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (!pos)
- return;
-
- pci_read_config_word(dev, msi_control_reg(pos), &control);
- if (!(control & PCI_MSIX_FLAGS_ENABLE))
- return;
-
- disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
+ msix_set_enable(dev, 0);
+ pci_intx(dev, 1); /* enable intx */
+ dev->msix_enabled = 0;
irq = head = dev->first_msi_irq;
while (head != tail) {
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 1e74e1ee8bd..df495300ce3 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -881,13 +881,6 @@ pci_disable_device(struct pci_dev *dev)
if (atomic_sub_return(1, &dev->enable_cnt) != 0)
return;
- if (dev->msi_enabled)
- disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
- PCI_CAP_ID_MSI);
- if (dev->msix_enabled)
- disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
- PCI_CAP_ID_MSIX);
-
pci_read_config_word(dev, PCI_COMMAND, &pci_command);
if (pci_command & PCI_COMMAND_MASTER) {
pci_command &= ~PCI_COMMAND_MASTER;
@@ -1277,6 +1270,33 @@ pci_intx(struct pci_dev *pdev, int enable)
}
}
+/**
+ * pci_msi_off - disables any msi or msix capabilities
+ * @pdev: the PCI device to operate on
+ *
+ * If you want to use msi see pci_enable_msi and friends.
+ * This is a lower level primitive that allows us to disable
+ * msi operation at the device level.
+ */
+void pci_msi_off(struct pci_dev *dev)
+{
+ int pos;
+ u16 control;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+ if (pos) {
+ pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
+ control &= ~PCI_MSI_FLAGS_ENABLE;
+ pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
+ }
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+ if (pos) {
+ pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
+ control &= ~PCI_MSIX_FLAGS_ENABLE;
+ pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
+ }
+}
+
#ifndef HAVE_ARCH_PCI_SET_DMA_MASK
/*
* These can be overridden by arch-specific implementations
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index a4f2d580625..ae7a975995a 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -46,10 +46,8 @@ extern struct rw_semaphore pci_bus_sem;
extern unsigned int pci_pm_d3_delay;
#ifdef CONFIG_PCI_MSI
-void disable_msi_mode(struct pci_dev *dev, int pos, int type);
void pci_no_msi(void);
#else
-static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { }
static inline void pci_no_msi(void) { }
#endif
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 2fe1d690eb1..a4a96826d9e 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -682,7 +682,34 @@ static void pci_read_irq(struct pci_dev *dev)
dev->irq = irq;
}
-#define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED)
+static void change_legacy_io_resource(struct pci_dev * dev, unsigned index,
+ unsigned start, unsigned end)
+{
+ unsigned base = start & PCI_BASE_ADDRESS_IO_MASK;
+ unsigned len = (end | ~PCI_BASE_ADDRESS_IO_MASK) - base + 1;
+
+ /*
+ * Some X versions get confused when the BARs reported through
+ * /sys or /proc differ from those seen in config space, thus
+ * try to update the config space values, too.
+ */
+ if (!(pci_resource_flags(dev, index) & IORESOURCE_IO))
+ printk(KERN_WARNING "%s: cannot adjust BAR%u (not I/O)\n",
+ pci_name(dev), index);
+ else if (pci_resource_len(dev, index) != len)
+ printk(KERN_WARNING "%s: cannot adjust BAR%u (size %04X)\n",
+ pci_name(dev), index, (unsigned)pci_resource_len(dev, index));
+ else {
+ printk(KERN_INFO "%s: trying to change BAR%u from %04X to %04X\n",
+ pci_name(dev), index,
+ (unsigned)pci_resource_start(dev, index), base);
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + index * 4, base);
+ }
+ pci_resource_start(dev, index) = start;
+ pci_resource_end(dev, index) = end;
+ pci_resource_flags(dev, index) =
+ IORESOURCE_IO | IORESOURCE_PCI_FIXED | PCI_BASE_ADDRESS_SPACE_IO;
+}
/**
* pci_setup_device - fill in class and map information of a device
@@ -735,20 +762,12 @@ static int pci_setup_device(struct pci_dev * dev)
u8 progif;
pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
if ((progif & 1) == 0) {
- dev->resource[0].start = 0x1F0;
- dev->resource[0].end = 0x1F7;
- dev->resource[0].flags = LEGACY_IO_RESOURCE;
- dev->resource[1].start = 0x3F6;
- dev->resource[1].end = 0x3F6;
- dev->resource[1].flags = LEGACY_IO_RESOURCE;
+ change_legacy_io_resource(dev, 0, 0x1F0, 0x1F7);
+ change_legacy_io_resource(dev, 1, 0x3F6, 0x3F6);
}
if ((progif & 4) == 0) {
- dev->resource[2].start = 0x170;
- dev->resource[2].end = 0x177;
- dev->resource[2].flags = LEGACY_IO_RESOURCE;
- dev->resource[3].start = 0x376;
- dev->resource[3].end = 0x376;
- dev->resource[3].flags = LEGACY_IO_RESOURCE;
+ change_legacy_io_resource(dev, 2, 0x170, 0x177);
+ change_legacy_io_resource(dev, 3, 0x376, 0x376);
}
}
break;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 1e6eda25c0d..7f94fc098cd 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -1218,45 +1218,68 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_a
* do this early on to make the additional device appear during
* the PCI scanning.
*/
-
-static void quirk_jmicron_dualfn(struct pci_dev *pdev)
+static void quirk_jmicron_ata(struct pci_dev *pdev)
{
- u32 conf;
+ u32 conf1, conf5, class;
u8 hdr;
/* Only poke fn 0 */
if (PCI_FUNC(pdev->devfn))
return;
- switch(pdev->device) {
- case PCI_DEVICE_ID_JMICRON_JMB365:
- case PCI_DEVICE_ID_JMICRON_JMB366:
- /* Redirect IDE second PATA port to the right spot */
- pci_read_config_dword(pdev, 0x80, &conf);
- conf |= (1 << 24);
- /* Fall through */
- pci_write_config_dword(pdev, 0x80, conf);
- case PCI_DEVICE_ID_JMICRON_JMB361:
- case PCI_DEVICE_ID_JMICRON_JMB363:
- pci_read_config_dword(pdev, 0x40, &conf);
- /* Enable dual function mode, AHCI on fn 0, IDE fn1 */
- /* Set the class codes correctly and then direct IDE 0 */
- conf &= ~0x000FF200; /* Clear bit 9 and 12-19 */
- conf |= 0x00C2A102; /* Set 1, 8, 13, 15, 17, 22, 23 */
- pci_write_config_dword(pdev, 0x40, conf);
-
- /* Reconfigure so that the PCI scanner discovers the
- device is now multifunction */
-
- pci_read_config_byte(pdev, PCI_HEADER_TYPE, &hdr);
- pdev->hdr_type = hdr & 0x7f;
- pdev->multifunction = !!(hdr & 0x80);
+ pci_read_config_dword(pdev, 0x40, &conf1);
+ pci_read_config_dword(pdev, 0x80, &conf5);
- break;
+ conf1 &= ~0x00CFF302; /* Clear bit 1, 8, 9, 12-19, 22, 23 */
+ conf5 &= ~(1 << 24); /* Clear bit 24 */
+
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_JMICRON_JMB360:
+ /* The controller should be in single function ahci mode */
+ conf1 |= 0x0002A100; /* Set 8, 13, 15, 17 */
+ break;
+
+ case PCI_DEVICE_ID_JMICRON_JMB365:
+ case PCI_DEVICE_ID_JMICRON_JMB366:
+ /* Redirect IDE second PATA port to the right spot */
+ conf5 |= (1 << 24);
+ /* Fall through */
+ case PCI_DEVICE_ID_JMICRON_JMB361:
+ case PCI_DEVICE_ID_JMICRON_JMB363:
+ /* Enable dual function mode, AHCI on fn 0, IDE fn1 */
+ /* Set the class codes correctly and then direct IDE 0 */
+ conf1 |= 0x00C2A102; /* Set 1, 8, 13, 15, 17, 22, 23 */
+ break;
+
+ case PCI_DEVICE_ID_JMICRON_JMB368:
+ /* The controller should be in single function IDE mode */
+ conf1 |= 0x00C00000; /* Set 22, 23 */
+ break;
}
-}
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn);
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn);
+
+ pci_write_config_dword(pdev, 0x40, conf1);
+ pci_write_config_dword(pdev, 0x80, conf5);
+
+ /* Update pdev accordingly */
+ pci_read_config_byte(pdev, PCI_HEADER_TYPE, &hdr);
+ pdev->hdr_type = hdr & 0x7f;
+ pdev->multifunction = !!(hdr & 0x80);
+
+ pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class);
+ pdev->class = class >> 8;
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB360, quirk_jmicron_ata);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, quirk_jmicron_ata);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, quirk_jmicron_ata);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, quirk_jmicron_ata);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, quirk_jmicron_ata);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, quirk_jmicron_ata);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB360, quirk_jmicron_ata);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, quirk_jmicron_ata);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, quirk_jmicron_ata);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, quirk_jmicron_ata);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, quirk_jmicron_ata);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, quirk_jmicron_ata);
#endif
@@ -1415,8 +1438,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quir
*/
static void __devinit quirk_pcie_pxh(struct pci_dev *dev)
{
- disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
- PCI_CAP_ID_MSI);
+ pci_msi_off(dev);
+
dev->no_msi = 1;
printk(KERN_WARNING "PCI: PXH quirk detected, "
diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c
index caca0dc9d30..f2e810f53c8 100644
--- a/drivers/pcmcia/hd64465_ss.c
+++ b/drivers/pcmcia/hd64465_ss.c
@@ -907,7 +907,7 @@ static int __init init_hs(void)
for (i=0; i<HS_MAX_SOCKETS; i++) {
unsigned int ret;
- hs_sockets[i].socket.dev.dev = &hd64465_device.dev;
+ hs_sockets[i].socket.dev.parent = &hd64465_device.dev;
hs_sockets[i].number = i;
ret = pcmcia_register_socket(&hs_sockets[i].socket);
if (ret && i)
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
index e4a94108aab..91da15b5a81 100644
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -760,7 +760,7 @@ static int __init init_m32r_pcc(void)
/* Set up interrupt handler(s) */
for (i = 0 ; i < pcc_sockets ; i++) {
- socket[i].socket.dev.dev = &pcc_device.dev;
+ socket[i].socket.dev.parent = &pcc_device.dev;
socket[i].socket.ops = &pcc_operations;
socket[i].socket.resource_ops = &pccard_nonstatic_ops;
socket[i].socket.owner = THIS_MODULE;
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index d059c919617..9721ed7bf50 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -1321,7 +1321,7 @@ static int __init m8xx_init(void)
socket[i].socket.ops = &m8xx_services;
socket[i].socket.resource_ops = &pccard_iodyn_ops;
socket[i].socket.cb_dev = NULL;
- socket[i].socket.dev.dev = &m8xx_device.dev;
+ socket[i].socket.dev.parent = &m8xx_device.dev;
}
for (i = 0; i < PCMCIA_SOCKETS_NO; i++)
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
index 76f7cbc62a8..d77f75129f8 100644
--- a/drivers/pcmcia/omap_cf.c
+++ b/drivers/pcmcia/omap_cf.c
@@ -291,7 +291,7 @@ static int __devinit omap_cf_probe(struct device *dev)
omap_cf_present() ? "present" : "(not present)");
cf->socket.owner = THIS_MODULE;
- cf->socket.dev.dev = dev;
+ cf->socket.dev.parent = dev;
cf->socket.ops = &omap_cf_ops;
cf->socket.resource_ops = &pccard_static_ops;
cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
index 81dfc2cac2b..ce2226273aa 100644
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -232,7 +232,7 @@ static struct resource *iodyn_find_io_region(unsigned long base, int num,
unsigned long align, struct pcmcia_socket *s)
{
struct resource *res = make_resource(0, num, IORESOURCE_IO,
- s->dev.class_id);
+ s->dev.bus_id);
struct pcmcia_align_data data;
unsigned long min = base;
int ret;
diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c
index 206e26c9180..eee2f1cb213 100644
--- a/drivers/pcmcia/vrc4171_card.c
+++ b/drivers/pcmcia/vrc4171_card.c
@@ -596,7 +596,7 @@ static int __devinit vrc4171_add_sockets(void)
}
sprintf(socket->name, "NEC VRC4171 Card Slot %1c", 'A' + slot);
- socket->pcmcia_socket.dev.dev = &vrc4171_card_device.dev;
+ socket->pcmcia_socket.dev.parent = &vrc4171_card_device.dev;
socket->pcmcia_socket.ops = &vrc4171_pccard_operations;
socket->pcmcia_socket.owner = THIS_MODULE;
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index deef29646e0..95826b92ca4 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -207,10 +207,12 @@ config RTC_DRV_PCF8563
config RTC_DRV_PCF8583
tristate "Philips PCF8583"
- depends on RTC_CLASS && I2C
+ depends on RTC_CLASS && I2C && ARCH_RPC
help
- If you say yes here you get support for the
- Philips PCF8583 RTC chip.
+ If you say yes here you get support for the Philips PCF8583
+ RTC chip found on Acorn RiscPCs. This driver supports the
+ platform specific method of retrieving the current year from
+ the RTC's SRAM.
This driver can also be built as a module. If so, the module
will be called rtc-pcf8583.
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 7a0d8ee2de9..04aaa634723 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -113,10 +113,16 @@ EXPORT_SYMBOL_GPL(rtc_device_register);
*/
void rtc_device_unregister(struct rtc_device *rtc)
{
- mutex_lock(&rtc->ops_lock);
- rtc->ops = NULL;
- mutex_unlock(&rtc->ops_lock);
- class_device_unregister(&rtc->class_dev);
+ if (class_device_get(&rtc->class_dev) != NULL) {
+ mutex_lock(&rtc->ops_lock);
+ /* remove innards of this RTC, then disable it, before
+ * letting any rtc_class_open() users access it again
+ */
+ class_device_unregister(&rtc->class_dev);
+ rtc->ops = NULL;
+ mutex_unlock(&rtc->ops_lock);
+ class_device_put(&rtc->class_dev);
+ }
}
EXPORT_SYMBOL_GPL(rtc_device_unregister);
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 6f11f6dfdd9..ef40df0f169 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -179,7 +179,7 @@ struct class_device *rtc_class_open(char *name)
down(&rtc_class->sem);
list_for_each_entry(class_dev_tmp, &rtc_class->children, node) {
if (strncmp(class_dev_tmp->class_id, name, BUS_ID_SIZE) == 0) {
- class_dev = class_dev_tmp;
+ class_dev = class_device_get(class_dev_tmp);
break;
}
}
@@ -197,6 +197,7 @@ EXPORT_SYMBOL_GPL(rtc_class_open);
void rtc_class_close(struct class_device *class_dev)
{
module_put(to_rtc_device(class_dev)->owner);
+ class_device_put(class_dev);
}
EXPORT_SYMBOL_GPL(rtc_class_close);
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
index 5875ebb8c79..d48b0337458 100644
--- a/drivers/rtc/rtc-pcf8583.c
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -40,7 +40,7 @@ struct pcf8583 {
#define CTRL_ALARM 0x02
#define CTRL_TIMER 0x01
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END };
/* Module parameters */
I2C_CLIENT_INSMOD;
@@ -81,11 +81,11 @@ static int pcf8583_get_datetime(struct i2c_client *client, struct rtc_time *dt)
buf[4] &= 0x3f;
buf[5] &= 0x1f;
- dt->tm_sec = BCD_TO_BIN(buf[1]);
- dt->tm_min = BCD_TO_BIN(buf[2]);
- dt->tm_hour = BCD_TO_BIN(buf[3]);
- dt->tm_mday = BCD_TO_BIN(buf[4]);
- dt->tm_mon = BCD_TO_BIN(buf[5]);
+ dt->tm_sec = BCD2BIN(buf[1]);
+ dt->tm_min = BCD2BIN(buf[2]);
+ dt->tm_hour = BCD2BIN(buf[3]);
+ dt->tm_mday = BCD2BIN(buf[4]);
+ dt->tm_mon = BCD2BIN(buf[5]) - 1;
}
return ret == 2 ? 0 : -EIO;
@@ -99,14 +99,14 @@ static int pcf8583_set_datetime(struct i2c_client *client, struct rtc_time *dt,
buf[0] = 0;
buf[1] = get_ctrl(client) | 0x80;
buf[2] = 0;
- buf[3] = BIN_TO_BCD(dt->tm_sec);
- buf[4] = BIN_TO_BCD(dt->tm_min);
- buf[5] = BIN_TO_BCD(dt->tm_hour);
+ buf[3] = BIN2BCD(dt->tm_sec);
+ buf[4] = BIN2BCD(dt->tm_min);
+ buf[5] = BIN2BCD(dt->tm_hour);
if (datetoo) {
len = 8;
- buf[6] = BIN_TO_BCD(dt->tm_mday) | (dt->tm_year << 6);
- buf[7] = BIN_TO_BCD(dt->tm_mon) | (dt->tm_wday << 5);
+ buf[6] = BIN2BCD(dt->tm_mday) | (dt->tm_year << 6);
+ buf[7] = BIN2BCD(dt->tm_mon + 1) | (dt->tm_wday << 5);
}
ret = i2c_master_send(client, (char *)buf, len);
@@ -226,7 +226,7 @@ static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm)
*/
year_offset += 4;
- tm->tm_year = real_year + year_offset + year[1] * 100;
+ tm->tm_year = (real_year + year_offset + year[1] * 100) - 1900;
return 0;
}
@@ -237,6 +237,7 @@ static int pcf8583_rtc_set_time(struct device *dev, struct rtc_time *tm)
unsigned char year[2], chk;
struct rtc_mem cmos_year = { CMOS_YEAR, sizeof(year), year };
struct rtc_mem cmos_check = { CMOS_CHECKSUM, 1, &chk };
+ unsigned int proper_year = tm->tm_year + 1900;
int ret;
/*
@@ -258,8 +259,8 @@ static int pcf8583_rtc_set_time(struct device *dev, struct rtc_time *tm)
chk -= year[1] + year[0];
- year[1] = tm->tm_year / 100;
- year[0] = tm->tm_year % 100;
+ year[1] = proper_year / 100;
+ year[0] = proper_year % 100;
chk += year[1] + year[0];
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
index 4b8a95fba1e..a1dc8c466ec 100644
--- a/drivers/s390/block/dasd_eer.c
+++ b/drivers/s390/block/dasd_eer.c
@@ -461,6 +461,7 @@ int dasd_eer_enable(struct dasd_device *device)
cqr->device = device;
cqr->retries = 255;
cqr->expires = 10 * HZ;
+ clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SNSS;
cqr->cpaddr->count = SNSS_DATA_SIZE;
diff --git a/drivers/s390/char/sclp_quiesce.c b/drivers/s390/char/sclp_quiesce.c
index ffa9282ce97..baa8fe669ed 100644
--- a/drivers/s390/char/sclp_quiesce.c
+++ b/drivers/s390/char/sclp_quiesce.c
@@ -16,6 +16,7 @@
#include <asm/atomic.h>
#include <asm/ptrace.h>
#include <asm/sigp.h>
+#include <asm/smp.h>
#include "sclp.h"
diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c
index 7a76ec413a3..2a1af4e60be 100644
--- a/drivers/s390/char/tape_std.c
+++ b/drivers/s390/char/tape_std.c
@@ -647,7 +647,10 @@ tape_std_mtcompression(struct tape_device *device, int mt_count)
return PTR_ERR(request);
request->op = TO_NOP;
/* setup ccws */
- *device->modeset_byte = (mt_count == 0) ? 0x00 : 0x08;
+ if (mt_count == 0)
+ *device->modeset_byte &= ~0x08;
+ else
+ *device->modeset_byte |= 0x08;
tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);
tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
/* execute it */
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index b3a56dc5f68..9cb129ab5be 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -21,6 +21,7 @@
#include <asm/irq_regs.h>
#include <asm/setup.h>
#include <asm/reset.h>
+#include <asm/ipl.h>
#include "airq.h"
#include "cio.h"
#include "css.h"
@@ -1047,7 +1048,7 @@ void reipl_ccw_dev(struct ccw_dev_id *devid)
do_reipl_asm(*((__u32*)&schid));
}
-extern struct schib ipl_schib;
+static struct schib __initdata ipl_schib;
/*
* ipl_save_parameters gets called very early. It is not allowed to access
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 51238e7555b..089a3ddd626 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -144,8 +144,8 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
ret = stsch(sch->schid, &sch->schib);
if (ret || !sch->schib.pmcw.dnv)
return -ENODEV;
- if (!sch->schib.pmcw.ena || sch->schib.scsw.actl == 0)
- /* Not operational or no activity -> done. */
+ if (!sch->schib.pmcw.ena)
+ /* Not operational -> done. */
return 0;
/* Stage 1: cancel io. */
if (!(sch->schib.scsw.actl & SCSW_ACTL_HALT_PEND) &&
@@ -334,20 +334,29 @@ ccw_device_oper_notify(struct work_struct *work)
struct ccw_device *cdev;
struct subchannel *sch;
int ret;
+ unsigned long flags;
priv = container_of(work, struct ccw_device_private, kick_work);
cdev = priv->cdev;
+ spin_lock_irqsave(cdev->ccwlock, flags);
sch = to_subchannel(cdev->dev.parent);
- ret = (sch->driver && sch->driver->notify) ?
- sch->driver->notify(&sch->dev, CIO_OPER) : 0;
- if (!ret)
- /* Driver doesn't want device back. */
- ccw_device_do_unreg_rereg(work);
- else {
+ if (sch->driver && sch->driver->notify) {
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
+ ret = sch->driver->notify(&sch->dev, CIO_OPER);
+ spin_lock_irqsave(cdev->ccwlock, flags);
+ } else
+ ret = 0;
+ if (ret) {
/* Reenable channel measurements, if needed. */
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
cmf_reenable(cdev);
+ spin_lock_irqsave(cdev->ccwlock, flags);
wake_up(&cdev->private->wait_q);
}
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
+ if (!ret)
+ /* Driver doesn't want device back. */
+ ccw_device_do_unreg_rereg(work);
}
/*
@@ -534,15 +543,21 @@ ccw_device_nopath_notify(struct work_struct *work)
struct ccw_device *cdev;
struct subchannel *sch;
int ret;
+ unsigned long flags;
priv = container_of(work, struct ccw_device_private, kick_work);
cdev = priv->cdev;
+ spin_lock_irqsave(cdev->ccwlock, flags);
sch = to_subchannel(cdev->dev.parent);
/* Extra sanity. */
if (sch->lpm)
- return;
- ret = (sch->driver && sch->driver->notify) ?
- sch->driver->notify(&sch->dev, CIO_NO_PATH) : 0;
+ goto out_unlock;
+ if (sch->driver && sch->driver->notify) {
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
+ ret = sch->driver->notify(&sch->dev, CIO_NO_PATH);
+ spin_lock_irqsave(cdev->ccwlock, flags);
+ } else
+ ret = 0;
if (!ret) {
if (get_device(&sch->dev)) {
/* Driver doesn't want to keep device. */
@@ -562,6 +577,8 @@ ccw_device_nopath_notify(struct work_struct *work)
cdev->private->state = DEV_STATE_DISCONNECTED;
wake_up(&cdev->private->wait_q);
}
+out_unlock:
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
}
void
@@ -607,10 +624,13 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
default:
/* Reset oper notify indication after verify error. */
cdev->private->flags.donotify = 0;
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify);
- queue_work(ccw_device_notify_work, &cdev->private->kick_work);
- ccw_device_done(cdev, DEV_STATE_NOT_OPER);
+ if (cdev->online) {
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_nopath_notify);
+ queue_work(ccw_device_notify_work,
+ &cdev->private->kick_work);
+ } else
+ ccw_device_done(cdev, DEV_STATE_NOT_OPER);
break;
}
}
@@ -756,15 +776,22 @@ static void
ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event)
{
struct subchannel *sch;
+ int ret;
sch = to_subchannel(cdev->dev.parent);
- if (sch->driver->notify &&
- sch->driver->notify(&sch->dev, sch->lpm ? CIO_GONE : CIO_NO_PATH)) {
- ccw_device_set_timeout(cdev, 0);
- cdev->private->flags.fake_irb = 0;
- cdev->private->state = DEV_STATE_DISCONNECTED;
- wake_up(&cdev->private->wait_q);
- return;
+ if (sch->driver->notify) {
+ spin_unlock_irq(cdev->ccwlock);
+ ret = sch->driver->notify(&sch->dev,
+ sch->lpm ? CIO_GONE : CIO_NO_PATH);
+ spin_lock_irq(cdev->ccwlock);
+ } else
+ ret = 0;
+ if (ret) {
+ ccw_device_set_timeout(cdev, 0);
+ cdev->private->flags.fake_irb = 0;
+ cdev->private->state = DEV_STATE_DISCONNECTED;
+ wake_up(&cdev->private->wait_q);
+ return;
}
cdev->private->state = DEV_STATE_NOT_OPER;
cio_disable_subchannel(sch);
@@ -969,18 +996,12 @@ ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event)
sch = to_subchannel(cdev->dev.parent);
ccw_device_set_timeout(cdev, 0);
+ /* Start delayed path verification. */
+ ccw_device_online_verify(cdev, 0);
/* OK, i/o is dead now. Call interrupt handler. */
- cdev->private->state = DEV_STATE_ONLINE;
if (cdev->handler)
cdev->handler(cdev, cdev->private->intparm,
ERR_PTR(-EIO));
- if (!sch->lpm) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify);
- queue_work(ccw_device_notify_work, &cdev->private->kick_work);
- } else if (cdev->private->flags.doverify)
- /* Start delayed path verification. */
- ccw_device_online_verify(cdev, 0);
}
static void
@@ -993,21 +1014,8 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event)
ccw_device_set_timeout(cdev, 3*HZ);
return;
}
- if (ret == -ENODEV) {
- struct subchannel *sch;
-
- sch = to_subchannel(cdev->dev.parent);
- if (!sch->lpm) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify);
- queue_work(ccw_device_notify_work,
- &cdev->private->kick_work);
- } else
- dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
- return;
- }
- //FIXME: Can we get here?
- cdev->private->state = DEV_STATE_ONLINE;
+ /* Start delayed path verification. */
+ ccw_device_online_verify(cdev, 0);
if (cdev->handler)
cdev->handler(cdev, cdev->private->intparm,
ERR_PTR(-EIO));
@@ -1025,26 +1033,11 @@ void device_kill_io(struct subchannel *sch)
cdev->private->state = DEV_STATE_TIMEOUT_KILL;
return;
}
- if (ret == -ENODEV) {
- if (!sch->lpm) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify);
- queue_work(ccw_device_notify_work,
- &cdev->private->kick_work);
- } else
- dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
- return;
- }
+ /* Start delayed path verification. */
+ ccw_device_online_verify(cdev, 0);
if (cdev->handler)
cdev->handler(cdev, cdev->private->intparm,
ERR_PTR(-EIO));
- if (!sch->lpm) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify);
- queue_work(ccw_device_notify_work, &cdev->private->kick_work);
- } else
- /* Start delayed path verification. */
- ccw_device_online_verify(cdev, 0);
}
static void
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 2257e45594b..d8a86f5af37 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -3654,7 +3654,7 @@ qeth_verify_vlan_dev(struct net_device *dev, struct qeth_card *card)
return rc;
for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++){
- if (vg->vlan_devices[i] == dev){
+ if (vlan_group_get_device(vg, i) == dev){
rc = QETH_VLAN_CARD;
break;
}
@@ -5261,7 +5261,7 @@ qeth_free_vlan_addresses4(struct qeth_card *card, unsigned short vid)
QETH_DBF_TEXT(trace, 4, "frvaddr4");
rcu_read_lock();
- in_dev = __in_dev_get_rcu(card->vlangrp->vlan_devices[vid]);
+ in_dev = __in_dev_get_rcu(vlan_group_get_device(card->vlangrp, vid));
if (!in_dev)
goto out;
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
@@ -5288,7 +5288,7 @@ qeth_free_vlan_addresses6(struct qeth_card *card, unsigned short vid)
QETH_DBF_TEXT(trace, 4, "frvaddr6");
- in6_dev = in6_dev_get(card->vlangrp->vlan_devices[vid]);
+ in6_dev = in6_dev_get(vlan_group_get_device(card->vlangrp, vid));
if (!in6_dev)
return;
for (ifa = in6_dev->addr_list; ifa; ifa = ifa->lst_next){
@@ -5360,7 +5360,7 @@ qeth_layer2_process_vlans(struct qeth_card *card, int clear)
if (!card->vlangrp)
return;
for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
- if (card->vlangrp->vlan_devices[i] == NULL)
+ if (vlan_group_get_device(card->vlangrp, i) == NULL)
continue;
if (clear)
qeth_layer2_send_setdelvlan(card, i, IPA_CMD_DELVLAN);
@@ -5398,8 +5398,7 @@ qeth_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
spin_lock_irqsave(&card->vlanlock, flags);
/* unregister IP addresses of vlan device */
qeth_free_vlan_addresses(card, vid);
- if (card->vlangrp)
- card->vlangrp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(card->vlangrp, vid, NULL);
spin_unlock_irqrestore(&card->vlanlock, flags);
if (card->options.layer2)
qeth_layer2_send_setdelvlan(card, vid, IPA_CMD_DELVLAN);
@@ -5662,10 +5661,11 @@ qeth_add_vlan_mc(struct qeth_card *card)
vg = card->vlangrp;
for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
- if (vg->vlan_devices[i] == NULL ||
- !(vg->vlan_devices[i]->flags & IFF_UP))
+ struct net_device *netdev = vlan_group_get_device(vg, i);
+ if (netdev == NULL ||
+ !(netdev->flags & IFF_UP))
continue;
- in_dev = in_dev_get(vg->vlan_devices[i]);
+ in_dev = in_dev_get(netdev);
if (!in_dev)
continue;
read_lock(&in_dev->mc_list_lock);
@@ -5749,10 +5749,11 @@ qeth_add_vlan_mc6(struct qeth_card *card)
vg = card->vlangrp;
for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
- if (vg->vlan_devices[i] == NULL ||
- !(vg->vlan_devices[i]->flags & IFF_UP))
+ struct net_device *netdev = vlan_group_get_device(vg, i);
+ if (netdev == NULL ||
+ !(netdev->flags & IFF_UP))
continue;
- in_dev = in6_dev_get(vg->vlan_devices[i]);
+ in_dev = in6_dev_get(netdev);
if (!in_dev)
continue;
read_lock(&in_dev->lock);
diff --git a/drivers/sbus/char/Kconfig b/drivers/sbus/char/Kconfig
index 3a8152906bf..35a73168333 100644
--- a/drivers/sbus/char/Kconfig
+++ b/drivers/sbus/char/Kconfig
@@ -46,13 +46,6 @@ config SUN_VIDEOPIX
based on the Phillips SAA9051, can handle NTSC and PAL/SECAM and
SVIDEO signals.
-config SUN_AURORA
- tristate "Aurora Multiboard 1600se (EXPERIMENTAL)"
- depends on EXPERIMENTAL && BROKEN
- help
- The Aurora Multiboard is a multi-port high-speed serial controller.
- If you have one of these, say Y.
-
config TADPOLE_TS102_UCTRL
tristate "Tadpole TS102 Microcontroller support (EXPERIMENTAL)"
depends on EXPERIMENTAL && SPARC32
diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile
index 3a5ea1dc789..7ab060e9a5f 100644
--- a/drivers/sbus/char/Makefile
+++ b/drivers/sbus/char/Makefile
@@ -19,7 +19,6 @@ obj-$(CONFIG_SUN_OPENPROMIO) += openprom.o
obj-$(CONFIG_SUN_MOSTEK_RTC) += rtc.o
obj-$(CONFIG_SUN_BPP) += bpp.o
obj-$(CONFIG_SUN_VIDEOPIX) += vfc.o
-obj-$(CONFIG_SUN_AURORA) += aurora.o
obj-$(CONFIG_TADPOLE_TS102_UCTRL) += uctrl.o
obj-$(CONFIG_SUN_JSFLASH) += jsflash.o
obj-$(CONFIG_BBC_I2C) += bbc.o
diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c
deleted file mode 100644
index a54b4ac6756..00000000000
--- a/drivers/sbus/char/aurora.c
+++ /dev/null
@@ -1,2364 +0,0 @@
-/* $Id: aurora.c,v 1.19 2002/01/08 16:00:16 davem Exp $
- * linux/drivers/sbus/char/aurora.c -- Aurora multiport driver
- *
- * Copyright (c) 1999 by Oliver Aldulea (oli at bv dot ro)
- *
- * This code is based on the RISCom/8 multiport serial driver written
- * by Dmitry Gorodchanin (pgmdsg@ibi.com), based on the Linux serial
- * driver, written by Linus Torvalds, Theodore T'so and others.
- * The Aurora multiport programming info was obtained mainly from the
- * Cirrus Logic CD180 documentation (available on the web), and by
- * doing heavy tests on the board. Many thanks to Eddie C. Dost for the
- * help on the sbus interface.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Revision 1.0
- *
- * This is the first public release.
- *
- * Most of the information you need is in the aurora.h file. Please
- * read that file before reading this one.
- *
- * Several parts of the code do not have comments yet.
- *
- * n.b. The board can support 115.2 bit rates, but only on a few
- * ports. The total badwidth of one chip (ports 0-7 or 8-15) is equal
- * to OSC_FREQ div 16. In case of my board, each chip can take 6
- * channels of 115.2 kbaud. This information is not well-tested.
- *
- * Fixed to use tty_get_baud_rate().
- * Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
- */
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#ifdef AURORA_INT_DEBUG
-#include <linux/timer.h>
-#endif
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/oplib.h>
-#include <asm/system.h>
-#include <asm/kdebug.h>
-#include <asm/sbus.h>
-#include <asm/uaccess.h>
-
-#include "aurora.h"
-#include "cd180.h"
-
-unsigned char irqs[4] = {
- 0, 0, 0, 0
-};
-
-#ifdef AURORA_INT_DEBUG
-int irqhit=0;
-#endif
-
-static struct tty_driver *aurora_driver;
-static struct Aurora_board aurora_board[AURORA_NBOARD] = {
- {0,},
-};
-
-static struct Aurora_port aurora_port[AURORA_TNPORTS] = {
- { 0, },
-};
-
-/* no longer used. static struct Aurora_board * IRQ_to_board[16] = { NULL, } ;*/
-static unsigned char * tmp_buf = NULL;
-
-DECLARE_TASK_QUEUE(tq_aurora);
-
-static inline int aurora_paranoia_check(struct Aurora_port const * port,
- char *name, const char *routine)
-{
-#ifdef AURORA_PARANOIA_CHECK
- static const char *badmagic =
- KERN_DEBUG "aurora: Warning: bad aurora port magic number for device %s in %s\n";
- static const char *badinfo =
- KERN_DEBUG "aurora: Warning: null aurora port for device %s in %s\n";
-
- if (!port) {
- printk(badinfo, name, routine);
- return 1;
- }
- if (port->magic != AURORA_MAGIC) {
- printk(badmagic, name, routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-/*
- *
- * Service functions for aurora driver.
- *
- */
-
-/* Get board number from pointer */
-static inline int board_No (struct Aurora_board const * bp)
-{
- return bp - aurora_board;
-}
-
-/* Get port number from pointer */
-static inline int port_No (struct Aurora_port const * port)
-{
- return AURORA_PORT(port - aurora_port);
-}
-
-/* Get pointer to board from pointer to port */
-static inline struct Aurora_board * port_Board(struct Aurora_port const * port)
-{
- return &aurora_board[AURORA_BOARD(port - aurora_port)];
-}
-
-/* Wait for Channel Command Register ready */
-static inline void aurora_wait_CCR(struct aurora_reg128 * r)
-{
- unsigned long delay;
-
-#ifdef AURORA_DEBUG
-printk("aurora_wait_CCR\n");
-#endif
- /* FIXME: need something more descriptive than 100000 :) */
- for (delay = 100000; delay; delay--)
- if (!sbus_readb(&r->r[CD180_CCR]))
- return;
- printk(KERN_DEBUG "aurora: Timeout waiting for CCR.\n");
-}
-
-/*
- * aurora probe functions.
- */
-
-/* Must be called with enabled interrupts */
-static inline void aurora_long_delay(unsigned long delay)
-{
- unsigned long i;
-
-#ifdef AURORA_DEBUG
- printk("aurora_long_delay: start\n");
-#endif
- for (i = jiffies + delay; time_before(jiffies, i); ) ;
-#ifdef AURORA_DEBUG
- printk("aurora_long_delay: end\n");
-#endif
-}
-
-/* Reset and setup CD180 chip */
-static int aurora_init_CD180(struct Aurora_board * bp, int chip)
-{
- unsigned long flags;
- int id;
-
-#ifdef AURORA_DEBUG
- printk("aurora_init_CD180: start %d:%d\n",
- board_No(bp), chip);
-#endif
- save_flags(flags); cli();
- sbus_writeb(0, &bp->r[chip]->r[CD180_CAR]);
- sbus_writeb(0, &bp->r[chip]->r[CD180_GSVR]);
-
- /* Wait for CCR ready */
- aurora_wait_CCR(bp->r[chip]);
-
- /* Reset CD180 chip */
- sbus_writeb(CCR_HARDRESET, &bp->r[chip]->r[CD180_CCR]);
- udelay(1);
- sti();
- id=1000;
- while((--id) &&
- (sbus_readb(&bp->r[chip]->r[CD180_GSVR])!=0xff))udelay(100);
- if(!id) {
- printk(KERN_ERR "aurora%d: Chip %d failed init.\n",
- board_No(bp), chip);
- restore_flags(flags);
- return(-1);
- }
- cli();
- sbus_writeb((board_No(bp)<<5)|((chip+1)<<3),
- &bp->r[chip]->r[CD180_GSVR]); /* Set ID for this chip */
- sbus_writeb(0x80|bp->ACK_MINT,
- &bp->r[chip]->r[CD180_MSMR]); /* Prio for modem intr */
- sbus_writeb(0x80|bp->ACK_TINT,
- &bp->r[chip]->r[CD180_TSMR]); /* Prio for transmitter intr */
- sbus_writeb(0x80|bp->ACK_RINT,
- &bp->r[chip]->r[CD180_RSMR]); /* Prio for receiver intr */
- /* Setting up prescaler. We need 4 tick per 1 ms */
- sbus_writeb((bp->oscfreq/(1000000/AURORA_TPS)) >> 8,
- &bp->r[chip]->r[CD180_PPRH]);
- sbus_writeb((bp->oscfreq/(1000000/AURORA_TPS)) & 0xff,
- &bp->r[chip]->r[CD180_PPRL]);
-
- sbus_writeb(SRCR_AUTOPRI|SRCR_GLOBPRI,
- &bp->r[chip]->r[CD180_SRCR]);
-
- id = sbus_readb(&bp->r[chip]->r[CD180_GFRCR]);
- printk(KERN_INFO "aurora%d: Chip %d id %02x: ",
- board_No(bp), chip,id);
- if(sbus_readb(&bp->r[chip]->r[CD180_SRCR]) & 128) {
- switch (id) {
- case 0x82:printk("CL-CD1864 rev A\n");break;
- case 0x83:printk("CL-CD1865 rev A\n");break;
- case 0x84:printk("CL-CD1865 rev B\n");break;
- case 0x85:printk("CL-CD1865 rev C\n");break;
- default:printk("Unknown.\n");
- };
- } else {
- switch (id) {
- case 0x81:printk("CL-CD180 rev B\n");break;
- case 0x82:printk("CL-CD180 rev C\n");break;
- default:printk("Unknown.\n");
- };
- }
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_init_CD180: end\n");
-#endif
- return 0;
-}
-
-static int valid_irq(unsigned char irq)
-{
-int i;
-for(i=0;i<TYPE_1_IRQS;i++)
- if (type_1_irq[i]==irq) return 1;
-return 0;
-}
-
-static irqreturn_t aurora_interrupt(int irq, void * dev_id);
-
-/* Main probing routine, also sets irq. */
-static int aurora_probe(void)
-{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
- int grrr;
- char buf[30];
- int bn = 0;
- struct Aurora_board *bp;
-
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
-/* printk("Try: %x %s\n",sdev,sdev->prom_name);*/
- if (!strcmp(sdev->prom_name, "sio16")) {
-#ifdef AURORA_DEBUG
- printk(KERN_INFO "aurora: sio16 at %p\n",sdev);
-#endif
- if((sdev->reg_addrs[0].reg_size!=1) &&
- (sdev->reg_addrs[1].reg_size!=128) &&
- (sdev->reg_addrs[2].reg_size!=128) &&
- (sdev->reg_addrs[3].reg_size!=4)) {
- printk(KERN_ERR "aurora%d: registers' sizes "
- "do not match.\n", bn);
- break;
- }
- bp = &aurora_board[bn];
- bp->r0 = (struct aurora_reg1 *)
- sbus_ioremap(&sdev->resource[0], 0,
- sdev->reg_addrs[0].reg_size,
- "sio16");
- if (bp->r0 == NULL) {
- printk(KERN_ERR "aurora%d: can't map "
- "reg_addrs[0]\n", bn);
- break;
- }
-#ifdef AURORA_DEBUG
- printk("Map reg 0: %p\n", bp->r0);
-#endif
- bp->r[0] = (struct aurora_reg128 *)
- sbus_ioremap(&sdev->resource[1], 0,
- sdev->reg_addrs[1].reg_size,
- "sio16");
- if (bp->r[0] == NULL) {
- printk(KERN_ERR "aurora%d: can't map "
- "reg_addrs[1]\n", bn);
- break;
- }
-#ifdef AURORA_DEBUG
- printk("Map reg 1: %p\n", bp->r[0]);
-#endif
- bp->r[1] = (struct aurora_reg128 *)
- sbus_ioremap(&sdev->resource[2], 0,
- sdev->reg_addrs[2].reg_size,
- "sio16");
- if (bp->r[1] == NULL) {
- printk(KERN_ERR "aurora%d: can't map "
- "reg_addrs[2]\n", bn);
- break;
- }
-#ifdef AURORA_DEBUG
- printk("Map reg 2: %p\n", bp->r[1]);
-#endif
- bp->r3 = (struct aurora_reg4 *)
- sbus_ioremap(&sdev->resource[3], 0,
- sdev->reg_addrs[3].reg_size,
- "sio16");
- if (bp->r3 == NULL) {
- printk(KERN_ERR "aurora%d: can't map "
- "reg_addrs[3]\n", bn);
- break;
- }
-#ifdef AURORA_DEBUG
- printk("Map reg 3: %p\n", bp->r3);
-#endif
- /* Variables setup */
- bp->flags = 0;
-#ifdef AURORA_DEBUG
- grrr=prom_getint(sdev->prom_node,"intr");
- printk("intr pri %d\n", grrr);
-#endif
- if ((bp->irq=irqs[bn]) && valid_irq(bp->irq) &&
- !request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) {
- free_irq(bp->irq|0x30, bp);
- } else
- if ((bp->irq=prom_getint(sdev->prom_node, "bintr")) && valid_irq(bp->irq) &&
- !request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) {
- free_irq(bp->irq|0x30, bp);
- } else
- if ((bp->irq=prom_getint(sdev->prom_node, "intr")) && valid_irq(bp->irq) &&
- !request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) {
- free_irq(bp->irq|0x30, bp);
- } else
- for(grrr=0;grrr<TYPE_1_IRQS;grrr++) {
- if ((bp->irq=type_1_irq[grrr])&&!request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) {
- free_irq(bp->irq|0x30, bp);
- break;
- } else {
- printk(KERN_ERR "aurora%d: Could not get an irq for this board !!!\n",bn);
- bp->flags=0xff;
- }
- }
- if(bp->flags==0xff)break;
- printk(KERN_INFO "aurora%d: irq %d\n",bn,bp->irq&0x0f);
- buf[0]=0;
- grrr=prom_getproperty(sdev->prom_node,"dtr_rts",buf,sizeof(buf));
- if(!strcmp(buf,"swapped")){
- printk(KERN_INFO "aurora%d: Swapped DTR and RTS\n",bn);
- bp->DTR=MSVR_RTS;
- bp->RTS=MSVR_DTR;
- bp->MSVDTR=CD180_MSVRTS;
- bp->MSVRTS=CD180_MSVDTR;
- bp->flags|=AURORA_BOARD_DTR_FLOW_OK;
- }else{
- #ifdef AURORA_FORCE_DTR_FLOW
- printk(KERN_INFO "aurora%d: Forcing swapped DTR-RTS\n",bn);
- bp->DTR=MSVR_RTS;
- bp->RTS=MSVR_DTR;
- bp->MSVDTR=CD180_MSVRTS;
- bp->MSVRTS=CD180_MSVDTR;
- bp->flags|=AURORA_BOARD_DTR_FLOW_OK;
- #else
- printk(KERN_INFO "aurora%d: Normal DTR and RTS\n",bn);
- bp->DTR=MSVR_DTR;
- bp->RTS=MSVR_RTS;
- bp->MSVDTR=CD180_MSVDTR;
- bp->MSVRTS=CD180_MSVRTS;
- #endif
- }
- bp->oscfreq=prom_getint(sdev->prom_node,"clk")*100;
- printk(KERN_INFO "aurora%d: Oscillator: %d Hz\n",bn,bp->oscfreq);
- grrr=prom_getproperty(sdev->prom_node,"chip",buf,sizeof(buf));
- printk(KERN_INFO "aurora%d: Chips: %s\n",bn,buf);
- grrr=prom_getproperty(sdev->prom_node,"manu",buf,sizeof(buf));
- printk(KERN_INFO "aurora%d: Manufacturer: %s\n",bn,buf);
- grrr=prom_getproperty(sdev->prom_node,"model",buf,sizeof(buf));
- printk(KERN_INFO "aurora%d: Model: %s\n",bn,buf);
- grrr=prom_getproperty(sdev->prom_node,"rev",buf,sizeof(buf));
- printk(KERN_INFO "aurora%d: Revision: %s\n",bn,buf);
- grrr=prom_getproperty(sdev->prom_node,"mode",buf,sizeof(buf));
- printk(KERN_INFO "aurora%d: Mode: %s\n",bn,buf);
- #ifdef MODULE
- bp->count=0;
- #endif
- bp->flags = AURORA_BOARD_PRESENT;
- /* hardware ack */
- bp->ACK_MINT=1;
- bp->ACK_TINT=2;
- bp->ACK_RINT=3;
- bn++;
- }
- }
- }
- return bn;
-}
-
-static void aurora_release_io_range(struct Aurora_board *bp)
-{
- sbus_iounmap((unsigned long)bp->r0, 1);
- sbus_iounmap((unsigned long)bp->r[0], 128);
- sbus_iounmap((unsigned long)bp->r[1], 128);
- sbus_iounmap((unsigned long)bp->r3, 4);
-}
-
-static inline void aurora_mark_event(struct Aurora_port * port, int event)
-{
-#ifdef AURORA_DEBUG
- printk("aurora_mark_event: start\n");
-#endif
- set_bit(event, &port->event);
- queue_task(&port->tqueue, &tq_aurora);
- mark_bh(AURORA_BH);
-#ifdef AURORA_DEBUG
- printk("aurora_mark_event: end\n");
-#endif
-}
-
-static __inline__ struct Aurora_port * aurora_get_port(struct Aurora_board const * bp,
- int chip,
- unsigned char const *what)
-{
- unsigned char channel;
- struct Aurora_port * port;
-
- channel = ((chip << 3) |
- ((sbus_readb(&bp->r[chip]->r[CD180_GSCR]) & GSCR_CHAN) >> GSCR_CHAN_OFF));
- port = &aurora_port[board_No(bp) * AURORA_NPORT * AURORA_NCD180 + channel];
- if (port->flags & ASYNC_INITIALIZED)
- return port;
-
- printk(KERN_DEBUG "aurora%d: %s interrupt from invalid port %d\n",
- board_No(bp), what, channel);
- return NULL;
-}
-
-static void aurora_receive_exc(struct Aurora_board const * bp, int chip)
-{
- struct Aurora_port *port;
- struct tty_struct *tty;
- unsigned char status;
- unsigned char ch;
-
- if (!(port = aurora_get_port(bp, chip, "Receive_x")))
- return;
-
- tty = port->tty;
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-#ifdef AURORA_INTNORM
- printk("aurora%d: port %d: Working around flip buffer overflow.\n",
- board_No(bp), port_No(port));
-#endif
- return;
- }
-
-#ifdef AURORA_REPORT_OVERRUN
- status = sbus_readb(&bp->r[chip]->r[CD180_RCSR]);
- if (status & RCSR_OE) {
- port->overrun++;
-#if 1
- printk("aurora%d: port %d: Overrun. Total %ld overruns.\n",
- board_No(bp), port_No(port), port->overrun);
-#endif
- }
- status &= port->mark_mask;
-#else
- status = sbus_readb(&bp->r[chip]->r[CD180_RCSR]) & port->mark_mask;
-#endif
- ch = sbus_readb(&bp->r[chip]->r[CD180_RDR]);
- if (!status)
- return;
-
- if (status & RCSR_TOUT) {
-/* printk("aurora%d: port %d: Receiver timeout. Hardware problems ?\n",
- board_No(bp), port_No(port));*/
- return;
-
- } else if (status & RCSR_BREAK) {
- printk(KERN_DEBUG "aurora%d: port %d: Handling break...\n",
- board_No(bp), port_No(port));
- *tty->flip.flag_buf_ptr++ = TTY_BREAK;
- if (port->flags & ASYNC_SAK)
- do_SAK(tty);
-
- } else if (status & RCSR_PE)
- *tty->flip.flag_buf_ptr++ = TTY_PARITY;
-
- else if (status & RCSR_FE)
- *tty->flip.flag_buf_ptr++ = TTY_FRAME;
-
- else if (status & RCSR_OE)
- *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
-
- else
- *tty->flip.flag_buf_ptr++ = 0;
-
- *tty->flip.char_buf_ptr++ = ch;
- tty->flip.count++;
- queue_task(&tty->flip.tqueue, &tq_timer);
-}
-
-static void aurora_receive(struct Aurora_board const * bp, int chip)
-{
- struct Aurora_port *port;
- struct tty_struct *tty;
- unsigned char count,cnt;
-
- if (!(port = aurora_get_port(bp, chip, "Receive")))
- return;
-
- tty = port->tty;
-
- count = sbus_readb(&bp->r[chip]->r[CD180_RDCR]);
-
-#ifdef AURORA_REPORT_FIFO
- port->hits[count > 8 ? 9 : count]++;
-#endif
-
- while (count--) {
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-#ifdef AURORA_INTNORM
- printk("aurora%d: port %d: Working around flip buffer overflow.\n",
- board_No(bp), port_No(port));
-#endif
- break;
- }
- cnt = sbus_readb(&bp->r[chip]->r[CD180_RDR]);
- *tty->flip.char_buf_ptr++ = cnt;
- *tty->flip.flag_buf_ptr++ = 0;
- tty->flip.count++;
- }
- queue_task(&tty->flip.tqueue, &tq_timer);
-}
-
-static void aurora_transmit(struct Aurora_board const * bp, int chip)
-{
- struct Aurora_port *port;
- struct tty_struct *tty;
- unsigned char count;
-
- if (!(port = aurora_get_port(bp, chip, "Transmit")))
- return;
-
- tty = port->tty;
-
- if (port->SRER & SRER_TXEMPTY) {
- /* FIFO drained */
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- port->SRER &= ~SRER_TXEMPTY;
- sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
- return;
- }
-
- if ((port->xmit_cnt <= 0 && !port->break_length)
- || tty->stopped || tty->hw_stopped) {
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- port->SRER &= ~SRER_TXRDY;
- sbus_writeb(port->SRER,
- &bp->r[chip]->r[CD180_SRER]);
- return;
- }
-
- if (port->break_length) {
- if (port->break_length > 0) {
- if (port->COR2 & COR2_ETC) {
- sbus_writeb(CD180_C_ESC,
- &bp->r[chip]->r[CD180_TDR]);
- sbus_writeb(CD180_C_SBRK,
- &bp->r[chip]->r[CD180_TDR]);
- port->COR2 &= ~COR2_ETC;
- }
- count = min(port->break_length, 0xff);
- sbus_writeb(CD180_C_ESC,
- &bp->r[chip]->r[CD180_TDR]);
- sbus_writeb(CD180_C_DELAY,
- &bp->r[chip]->r[CD180_TDR]);
- sbus_writeb(count,
- &bp->r[chip]->r[CD180_TDR]);
- if (!(port->break_length -= count))
- port->break_length--;
- } else {
- sbus_writeb(CD180_C_ESC,
- &bp->r[chip]->r[CD180_TDR]);
- sbus_writeb(CD180_C_EBRK,
- &bp->r[chip]->r[CD180_TDR]);
- sbus_writeb(port->COR2,
- &bp->r[chip]->r[CD180_COR2]);
- aurora_wait_CCR(bp->r[chip]);
- sbus_writeb(CCR_CORCHG2,
- &bp->r[chip]->r[CD180_CCR]);
- port->break_length = 0;
- }
- return;
- }
-
- count = CD180_NFIFO;
- do {
- u8 byte = port->xmit_buf[port->xmit_tail++];
-
- sbus_writeb(byte, &bp->r[chip]->r[CD180_TDR]);
- port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1);
- if (--port->xmit_cnt <= 0)
- break;
- } while (--count > 0);
-
- if (port->xmit_cnt <= 0) {
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- port->SRER &= ~SRER_TXRDY;
- sbus_writeb(port->SRER,
- &bp->r[chip]->r[CD180_SRER]);
- }
- if (port->xmit_cnt <= port->wakeup_chars)
- aurora_mark_event(port, RS_EVENT_WRITE_WAKEUP);
-}
-
-static void aurora_check_modem(struct Aurora_board const * bp, int chip)
-{
- struct Aurora_port *port;
- struct tty_struct *tty;
- unsigned char mcr;
-
- if (!(port = aurora_get_port(bp, chip, "Modem")))
- return;
-
- tty = port->tty;
-
- mcr = sbus_readb(&bp->r[chip]->r[CD180_MCR]);
- if (mcr & MCR_CDCHG) {
- if (sbus_readb(&bp->r[chip]->r[CD180_MSVR]) & MSVR_CD)
- wake_up_interruptible(&port->open_wait);
- else
- schedule_task(&port->tqueue_hangup);
- }
-
-/* We don't have such things yet. My aurora board has DTR and RTS swapped, but that doesn't count in this driver. Let's hope
- * Aurora didn't made any boards with CTS or DSR broken...
- */
-/* #ifdef AURORA_BRAIN_DAMAGED_CTS
- if (mcr & MCR_CTSCHG) {
- if (aurora_in(bp, CD180_MSVR) & MSVR_CTS) {
- tty->hw_stopped = 0;
- port->SRER |= SRER_TXRDY;
- if (port->xmit_cnt <= port->wakeup_chars)
- aurora_mark_event(port, RS_EVENT_WRITE_WAKEUP);
- } else {
- tty->hw_stopped = 1;
- port->SRER &= ~SRER_TXRDY;
- }
- sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
- }
- if (mcr & MCR_DSRCHG) {
- if (aurora_in(bp, CD180_MSVR) & MSVR_DSR) {
- tty->hw_stopped = 0;
- port->SRER |= SRER_TXRDY;
- if (port->xmit_cnt <= port->wakeup_chars)
- aurora_mark_event(port, RS_EVENT_WRITE_WAKEUP);
- } else {
- tty->hw_stopped = 1;
- port->SRER &= ~SRER_TXRDY;
- }
- sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
- }
-#endif AURORA_BRAIN_DAMAGED_CTS */
-
- /* Clear change bits */
- sbus_writeb(0, &bp->r[chip]->r[CD180_MCR]);
-}
-
-/* The main interrupt processing routine */
-static irqreturn_t aurora_interrupt(int irq, void * dev_id)
-{
- unsigned char status;
- unsigned char ack,chip/*,chip_id*/;
- struct Aurora_board * bp = (struct Aurora_board *) dev_id;
- unsigned long loop = 0;
-
-#ifdef AURORA_INT_DEBUG
- printk("IRQ%d %d\n",irq,++irqhit);
-#ifdef AURORA_FLOODPRO
- if (irqhit>=AURORA_FLOODPRO)
- sbus_writeb(8, &bp->r0->r);
-#endif
-#endif
-
-/* old bp = IRQ_to_board[irq&0x0f];*/
-
- if (!bp || !(bp->flags & AURORA_BOARD_ACTIVE))
- return IRQ_NONE;
-
-/* The while() below takes care of this.
- status = sbus_readb(&bp->r[0]->r[CD180_SRSR]);
-#ifdef AURORA_INT_DEBUG
- printk("mumu: %02x\n", status);
-#endif
- if (!(status&SRSR_ANYINT))
- return IRQ_NONE; * Nobody has anything to say, so exit *
-*/
- while ((loop++ < 48) &&
- (status = sbus_readb(&bp->r[0]->r[CD180_SRSR]) & SRSR_ANYINT)){
-#ifdef AURORA_INT_DEBUG
- printk("SRSR: %02x\n", status);
-#endif
- if (status & SRSR_REXT) {
- ack = sbus_readb(&bp->r3->r[bp->ACK_RINT]);
-#ifdef AURORA_INT_DEBUG
- printk("R-ACK %02x\n", ack);
-#endif
- if ((ack >> 5) == board_No(bp)) {
- if ((chip=((ack>>3)&3)-1) < AURORA_NCD180) {
- if ((ack&GSVR_ITMASK)==GSVR_IT_RGD) {
- aurora_receive(bp,chip);
- sbus_writeb(0,
- &bp->r[chip]->r[CD180_EOSRR]);
- } else if ((ack & GSVR_ITMASK) == GSVR_IT_REXC) {
- aurora_receive_exc(bp,chip);
- sbus_writeb(0,
- &bp->r[chip]->r[CD180_EOSRR]);
- }
- }
- }
- } else if (status & SRSR_TEXT) {
- ack = sbus_readb(&bp->r3->r[bp->ACK_TINT]);
-#ifdef AURORA_INT_DEBUG
- printk("T-ACK %02x\n", ack);
-#endif
- if ((ack >> 5) == board_No(bp)) {
- if ((chip=((ack>>3)&3)-1) < AURORA_NCD180) {
- if ((ack&GSVR_ITMASK)==GSVR_IT_TX) {
- aurora_transmit(bp,chip);
- sbus_writeb(0,
- &bp->r[chip]->r[CD180_EOSRR]);
- }
- }
- }
- } else if (status & SRSR_MEXT) {
- ack = sbus_readb(&bp->r3->r[bp->ACK_MINT]);
-#ifdef AURORA_INT_DEBUG
- printk("M-ACK %02x\n", ack);
-#endif
- if ((ack >> 5) == board_No(bp)) {
- if ((chip = ((ack>>3)&3)-1) < AURORA_NCD180) {
- if ((ack&GSVR_ITMASK)==GSVR_IT_MDM) {
- aurora_check_modem(bp,chip);
- sbus_writeb(0,
- &bp->r[chip]->r[CD180_EOSRR]);
- }
- }
- }
- }
- }
-/* I guess this faster code can be used with CD1865, using AUROPRI and GLOBPRI. */
-#if 0
- while ((loop++ < 48)&&(status=bp->r[0]->r[CD180_SRSR]&SRSR_ANYINT)){
-#ifdef AURORA_INT_DEBUG
- printk("SRSR: %02x\n",status);
-#endif
- ack = sbus_readb(&bp->r3->r[0]);
-#ifdef AURORA_INT_DEBUG
- printk("ACK: %02x\n",ack);
-#endif
- if ((ack>>5)==board_No(bp)) {
- if ((chip=((ack>>3)&3)-1) < AURORA_NCD180) {
- ack&=GSVR_ITMASK;
- if (ack==GSVR_IT_RGD) {
- aurora_receive(bp,chip);
- sbus_writeb(0,
- &bp->r[chip]->r[CD180_EOSRR]);
- } else if (ack==GSVR_IT_REXC) {
- aurora_receive_exc(bp,chip);
- sbus_writeb(0,
- &bp->r[chip]->r[CD180_EOSRR]);
- } else if (ack==GSVR_IT_TX) {
- aurora_transmit(bp,chip);
- sbus_writeb(0,
- &bp->r[chip]->r[CD180_EOSRR]);
- } else if (ack==GSVR_IT_MDM) {
- aurora_check_modem(bp,chip);
- sbus_writeb(0,
- &bp->r[chip]->r[CD180_EOSRR]);
- }
- }
- }
- }
-#endif
-
-/* This is the old handling routine, used in riscom8 for only one CD180. I keep it here for reference. */
-#if 0
- for(chip=0;chip<AURORA_NCD180;chip++){
- chip_id=(board_No(bp)<<5)|((chip+1)<<3);
- loop=0;
- while ((loop++ < 1) &&
- ((status = sbus_readb(&bp->r[chip]->r[CD180_SRSR])) &
- (SRSR_TEXT | SRSR_MEXT | SRSR_REXT))) {
-
- if (status & SRSR_REXT) {
- ack = sbus_readb(&bp->r3->r[bp->ACK_RINT]);
- if (ack == (chip_id | GSVR_IT_RGD)) {
-#ifdef AURORA_INTMSG
- printk("RX ACK\n");
-#endif
- aurora_receive(bp,chip);
- } else if (ack == (chip_id | GSVR_IT_REXC)) {
-#ifdef AURORA_INTMSG
- printk("RXC ACK\n");
-#endif
- aurora_receive_exc(bp,chip);
- } else {
-#ifdef AURORA_INTNORM
- printk("aurora%d-%d: Bad receive ack 0x%02x.\n",
- board_No(bp), chip, ack);
-#endif
- }
- } else if (status & SRSR_TEXT) {
- ack = sbus_readb(&bp->r3->r[bp->ACK_TINT]);
- if (ack == (chip_id | GSVR_IT_TX)){
-#ifdef AURORA_INTMSG
- printk("TX ACK\n");
-#endif
- aurora_transmit(bp,chip);
- } else {
-#ifdef AURORA_INTNORM
- printk("aurora%d-%d: Bad transmit ack 0x%02x.\n",
- board_No(bp), chip, ack);
-#endif
- }
- } else if (status & SRSR_MEXT) {
- ack = sbus_readb(&bp->r3->r[bp->ACK_MINT]);
- if (ack == (chip_id | GSVR_IT_MDM)){
-#ifdef AURORA_INTMSG
- printk("MDM ACK\n");
-#endif
- aurora_check_modem(bp,chip);
- } else {
-#ifdef AURORA_INTNORM
- printk("aurora%d-%d: Bad modem ack 0x%02x.\n",
- board_No(bp), chip, ack);
-#endif
- }
- }
- sbus_writeb(0, &bp->r[chip]->r[CD180_EOSRR]);
- }
- }
-#endif
-
- return IRQ_HANDLED;
-}
-
-#ifdef AURORA_INT_DEBUG
-static void aurora_timer (unsigned long ignored);
-
-static DEFINE_TIMER(aurora_poll_timer, aurora_timer, 0, 0);
-
-static void
-aurora_timer (unsigned long ignored)
-{
- unsigned long flags;
- int i;
-
- save_flags(flags); cli();
-
- printk("SRSR: %02x,%02x - ",
- sbus_readb(&aurora_board[0].r[0]->r[CD180_SRSR]),
- sbus_readb(&aurora_board[0].r[1]->r[CD180_SRSR]));
- for (i = 0; i < 4; i++) {
- udelay(1);
- printk("%02x ",
- sbus_readb(&aurora_board[0].r3->r[i]));
- }
- printk("\n");
-
- aurora_poll_timer.expires = jiffies + 300;
- add_timer (&aurora_poll_timer);
-
- restore_flags(flags);
-}
-#endif
-
-/*
- * Routines for open & close processing.
- */
-
-/* Called with disabled interrupts */
-static int aurora_setup_board(struct Aurora_board * bp)
-{
- int error;
-
-#ifdef AURORA_ALLIRQ
- int i;
- for (i = 0; i < AURORA_ALLIRQ; i++) {
- error = request_irq(allirq[i]|0x30, aurora_interrupt, IRQF_SHARED,
- "sio16", bp);
- if (error)
- printk(KERN_ERR "IRQ%d request error %d\n",
- allirq[i], error);
- }
-#else
- error = request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED,
- "sio16", bp);
- if (error) {
- printk(KERN_ERR "IRQ request error %d\n", error);
- return error;
- }
-#endif
- /* Board reset */
- sbus_writeb(0, &bp->r0->r);
- udelay(1);
- if (bp->flags & AURORA_BOARD_TYPE_2) {
- /* unknown yet */
- } else {
- sbus_writeb((AURORA_CFG_ENABLE_IO | AURORA_CFG_ENABLE_IRQ |
- (((bp->irq)&0x0f)>>2)),
- &bp->r0->r);
- }
- udelay(10000);
-
- if (aurora_init_CD180(bp,0))error=1;error=0;
- if (aurora_init_CD180(bp,1))error++;
- if (error == AURORA_NCD180) {
- printk(KERN_ERR "Both chips failed initialisation.\n");
- return -EIO;
- }
-
-#ifdef AURORA_INT_DEBUG
- aurora_poll_timer.expires= jiffies + 1;
- add_timer(&aurora_poll_timer);
-#endif
-#ifdef AURORA_DEBUG
- printk("aurora_setup_board: end\n");
-#endif
- return 0;
-}
-
-/* Called with disabled interrupts */
-static void aurora_shutdown_board(struct Aurora_board *bp)
-{
- int i;
-
-#ifdef AURORA_DEBUG
- printk("aurora_shutdown_board: start\n");
-#endif
-
-#ifdef AURORA_INT_DEBUG
- del_timer(&aurora_poll_timer);
-#endif
-
-#ifdef AURORA_ALLIRQ
- for(i=0;i<AURORA_ALLIRQ;i++){
- free_irq(allirq[i]|0x30, bp);
-/* IRQ_to_board[allirq[i]&0xf] = NULL;*/
- }
-#else
- free_irq(bp->irq|0x30, bp);
-/* IRQ_to_board[bp->irq&0xf] = NULL;*/
-#endif
- /* Drop all DTR's */
- for(i=0;i<16;i++){
- sbus_writeb(i & 7, &bp->r[i>>3]->r[CD180_CAR]);
- udelay(1);
- sbus_writeb(0, &bp->r[i>>3]->r[CD180_MSVR]);
- udelay(1);
- }
- /* Board shutdown */
- sbus_writeb(0, &bp->r0->r);
-
-#ifdef AURORA_DEBUG
- printk("aurora_shutdown_board: end\n");
-#endif
-}
-
-/* Setting up port characteristics.
- * Must be called with disabled interrupts
- */
-static void aurora_change_speed(struct Aurora_board *bp, struct Aurora_port *port)
-{
- struct tty_struct *tty;
- unsigned long baud;
- long tmp;
- unsigned char cor1 = 0, cor3 = 0;
- unsigned char mcor1 = 0, mcor2 = 0,chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_change_speed: start\n");
-#endif
- if (!(tty = port->tty) || !tty->termios)
- return;
-
- chip = AURORA_CD180(port_No(port));
-
- port->SRER = 0;
- port->COR2 = 0;
- port->MSVR = MSVR_RTS|MSVR_DTR;
-
- baud = tty_get_baud_rate(tty);
-
- /* Select port on the board */
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
-
- if (!baud) {
- /* Drop DTR & exit */
- port->MSVR &= ~(bp->DTR|bp->RTS);
- sbus_writeb(port->MSVR,
- &bp->r[chip]->r[CD180_MSVR]);
- return;
- } else {
- /* Set DTR on */
- port->MSVR |= bp->DTR;
- sbus_writeb(port->MSVR,
- &bp->r[chip]->r[CD180_MSVR]);
- }
-
- /* Now we must calculate some speed dependent things. */
-
- /* Set baud rate for port. */
- tmp = (((bp->oscfreq + baud/2) / baud +
- CD180_TPC/2) / CD180_TPC);
-
-/* tmp = (bp->oscfreq/7)/baud;
- if((tmp%10)>4)tmp=tmp/10+1;else tmp=tmp/10;*/
-/* printk("Prescaler period: %d\n",tmp);*/
-
- sbus_writeb((tmp >> 8) & 0xff,
- &bp->r[chip]->r[CD180_RBPRH]);
- sbus_writeb((tmp >> 8) & 0xff,
- &bp->r[chip]->r[CD180_TBPRH]);
- sbus_writeb(tmp & 0xff, &bp->r[chip]->r[CD180_RBPRL]);
- sbus_writeb(tmp & 0xff, &bp->r[chip]->r[CD180_TBPRL]);
-
- baud = (baud + 5) / 10; /* Estimated CPS */
-
- /* Two timer ticks seems enough to wakeup something like SLIP driver */
- tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO;
- port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ?
- SERIAL_XMIT_SIZE - 1 : tmp);
-
- /* Receiver timeout will be transmission time for 1.5 chars */
- tmp = (AURORA_TPS + AURORA_TPS/2 + baud/2) / baud;
- tmp = (tmp > 0xff) ? 0xff : tmp;
- sbus_writeb(tmp, &bp->r[chip]->r[CD180_RTPR]);
-
- switch (C_CSIZE(tty)) {
- case CS5:
- cor1 |= COR1_5BITS;
- break;
- case CS6:
- cor1 |= COR1_6BITS;
- break;
- case CS7:
- cor1 |= COR1_7BITS;
- break;
- case CS8:
- cor1 |= COR1_8BITS;
- break;
- }
-
- if (C_CSTOPB(tty))
- cor1 |= COR1_2SB;
-
- cor1 |= COR1_IGNORE;
- if (C_PARENB(tty)) {
- cor1 |= COR1_NORMPAR;
- if (C_PARODD(tty))
- cor1 |= COR1_ODDP;
- if (I_INPCK(tty))
- cor1 &= ~COR1_IGNORE;
- }
- /* Set marking of some errors */
- port->mark_mask = RCSR_OE | RCSR_TOUT;
- if (I_INPCK(tty))
- port->mark_mask |= RCSR_FE | RCSR_PE;
- if (I_BRKINT(tty) || I_PARMRK(tty))
- port->mark_mask |= RCSR_BREAK;
- if (I_IGNPAR(tty))
- port->mark_mask &= ~(RCSR_FE | RCSR_PE);
- if (I_IGNBRK(tty)) {
- port->mark_mask &= ~RCSR_BREAK;
- if (I_IGNPAR(tty))
- /* Real raw mode. Ignore all */
- port->mark_mask &= ~RCSR_OE;
- }
- /* Enable Hardware Flow Control */
- if (C_CRTSCTS(tty)) {
-/*#ifdef AURORA_BRAIN_DAMAGED_CTS
- port->SRER |= SRER_DSR | SRER_CTS;
- mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
- mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
- tty->hw_stopped = !(aurora_in(bp, CD180_MSVR) & (MSVR_CTS|MSVR_DSR));
-#else*/
- port->COR2 |= COR2_CTSAE;
-/*#endif*/
- if (bp->flags&AURORA_BOARD_DTR_FLOW_OK) {
- mcor1 |= AURORA_RXTH;
- }
- }
- /* Enable Software Flow Control. FIXME: I'm not sure about this */
- /* Some people reported that it works, but I still doubt */
- if (I_IXON(tty)) {
- port->COR2 |= COR2_TXIBE;
- cor3 |= (COR3_FCT | COR3_SCDE);
- if (I_IXANY(tty))
- port->COR2 |= COR2_IXM;
- sbus_writeb(START_CHAR(tty),
- &bp->r[chip]->r[CD180_SCHR1]);
- sbus_writeb(STOP_CHAR(tty),
- &bp->r[chip]->r[CD180_SCHR2]);
- sbus_writeb(START_CHAR(tty),
- &bp->r[chip]->r[CD180_SCHR3]);
- sbus_writeb(STOP_CHAR(tty),
- &bp->r[chip]->r[CD180_SCHR4]);
- }
- if (!C_CLOCAL(tty)) {
- /* Enable CD check */
- port->SRER |= SRER_CD;
- mcor1 |= MCOR1_CDZD;
- mcor2 |= MCOR2_CDOD;
- }
-
- if (C_CREAD(tty))
- /* Enable receiver */
- port->SRER |= SRER_RXD;
-
- /* Set input FIFO size (1-8 bytes) */
- cor3 |= AURORA_RXFIFO;
- /* Setting up CD180 channel registers */
- sbus_writeb(cor1, &bp->r[chip]->r[CD180_COR1]);
- sbus_writeb(port->COR2, &bp->r[chip]->r[CD180_COR2]);
- sbus_writeb(cor3, &bp->r[chip]->r[CD180_COR3]);
- /* Make CD180 know about registers change */
- aurora_wait_CCR(bp->r[chip]);
- sbus_writeb(CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3,
- &bp->r[chip]->r[CD180_CCR]);
- /* Setting up modem option registers */
- sbus_writeb(mcor1, &bp->r[chip]->r[CD180_MCOR1]);
- sbus_writeb(mcor2, &bp->r[chip]->r[CD180_MCOR2]);
- /* Enable CD180 transmitter & receiver */
- aurora_wait_CCR(bp->r[chip]);
- sbus_writeb(CCR_TXEN | CCR_RXEN, &bp->r[chip]->r[CD180_CCR]);
- /* Enable interrupts */
- sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
- /* And finally set RTS on */
- sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]);
-#ifdef AURORA_DEBUG
- printk("aurora_change_speed: end\n");
-#endif
-}
-
-/* Must be called with interrupts enabled */
-static int aurora_setup_port(struct Aurora_board *bp, struct Aurora_port *port)
-{
- unsigned long flags;
-
-#ifdef AURORA_DEBUG
- printk("aurora_setup_port: start %d\n",port_No(port));
-#endif
- if (port->flags & ASYNC_INITIALIZED)
- return 0;
-
- if (!port->xmit_buf) {
- /* We may sleep in get_zeroed_page() */
- unsigned long tmp;
-
- if (!(tmp = get_zeroed_page(GFP_KERNEL)))
- return -ENOMEM;
-
- if (port->xmit_buf) {
- free_page(tmp);
- return -ERESTARTSYS;
- }
- port->xmit_buf = (unsigned char *) tmp;
- }
-
- save_flags(flags); cli();
-
- if (port->tty)
- clear_bit(TTY_IO_ERROR, &port->tty->flags);
-
-#ifdef MODULE
- if ((port->count == 1) && ((++bp->count) == 1))
- bp->flags |= AURORA_BOARD_ACTIVE;
-#endif
-
- port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- aurora_change_speed(bp, port);
- port->flags |= ASYNC_INITIALIZED;
-
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_setup_port: end\n");
-#endif
- return 0;
-}
-
-/* Must be called with interrupts disabled */
-static void aurora_shutdown_port(struct Aurora_board *bp, struct Aurora_port *port)
-{
- struct tty_struct *tty;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_shutdown_port: start\n");
-#endif
- if (!(port->flags & ASYNC_INITIALIZED))
- return;
-
- chip = AURORA_CD180(port_No(port));
-
-#ifdef AURORA_REPORT_OVERRUN
- printk("aurora%d: port %d: Total %ld overruns were detected.\n",
- board_No(bp), port_No(port), port->overrun);
-#endif
-#ifdef AURORA_REPORT_FIFO
- {
- int i;
-
- printk("aurora%d: port %d: FIFO hits [ ",
- board_No(bp), port_No(port));
- for (i = 0; i < 10; i++) {
- printk("%ld ", port->hits[i]);
- }
- printk("].\n");
- }
-#endif
- if (port->xmit_buf) {
- free_page((unsigned long) port->xmit_buf);
- port->xmit_buf = NULL;
- }
-
- if (!(tty = port->tty) || C_HUPCL(tty)) {
- /* Drop DTR */
- port->MSVR &= ~(bp->DTR|bp->RTS);
- sbus_writeb(port->MSVR,
- &bp->r[chip]->r[CD180_MSVR]);
- }
-
- /* Select port */
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
-
- /* Reset port */
- aurora_wait_CCR(bp->r[chip]);
- sbus_writeb(CCR_SOFTRESET, &bp->r[chip]->r[CD180_CCR]);
-
- /* Disable all interrupts from this port */
- port->SRER = 0;
- sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
-
- if (tty)
- set_bit(TTY_IO_ERROR, &tty->flags);
- port->flags &= ~ASYNC_INITIALIZED;
-
-#ifdef MODULE
- if (--bp->count < 0) {
- printk(KERN_DEBUG "aurora%d: aurora_shutdown_port: "
- "bad board count: %d\n",
- board_No(bp), bp->count);
- bp->count = 0;
- }
-
- if (!bp->count)
- bp->flags &= ~AURORA_BOARD_ACTIVE;
-#endif
-
-#ifdef AURORA_DEBUG
- printk("aurora_shutdown_port: end\n");
-#endif
-}
-
-
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
- struct Aurora_port *port)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct Aurora_board *bp = port_Board(port);
- int retval;
- int do_clocal = 0;
- int CD;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("block_til_ready: start\n");
-#endif
- chip = AURORA_CD180(port_No(port));
-
- /* If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
- interruptible_sleep_on(&port->close_wait);
- if (port->flags & ASYNC_HUP_NOTIFY)
- return -EAGAIN;
- else
- return -ERESTARTSYS;
- }
-
- /* If non-blocking mode is set, or the port is not enabled,
- * then make the check up front and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
- port->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
- }
-
- if (C_CLOCAL(tty))
- do_clocal = 1;
-
- /* Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * rs_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&port->open_wait, &wait);
- cli();
- if (!tty_hung_up_p(filp))
- port->count--;
- sti();
- port->blocked_open++;
- while (1) {
- cli();
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- CD = sbus_readb(&bp->r[chip]->r[CD180_MSVR]) & MSVR_CD;
- port->MSVR=bp->RTS;
-
- /* auto drops DTR */
- sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]);
- sti();
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(port->flags & ASYNC_INITIALIZED)) {
- if (port->flags & ASYNC_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
- break;
- }
- if (!(port->flags & ASYNC_CLOSING) &&
- (do_clocal || CD))
- break;
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&port->open_wait, &wait);
- if (!tty_hung_up_p(filp))
- port->count++;
- port->blocked_open--;
- if (retval)
- return retval;
-
- port->flags |= ASYNC_NORMAL_ACTIVE;
-#ifdef AURORA_DEBUG
- printk("block_til_ready: end\n");
-#endif
- return 0;
-}
-
-static int aurora_open(struct tty_struct * tty, struct file * filp)
-{
- int board;
- int error;
- struct Aurora_port * port;
- struct Aurora_board * bp;
- unsigned long flags;
-
-#ifdef AURORA_DEBUG
- printk("aurora_open: start\n");
-#endif
-
- board = AURORA_BOARD(tty->index);
- if (board > AURORA_NBOARD ||
- !(aurora_board[board].flags & AURORA_BOARD_PRESENT)) {
-#ifdef AURORA_DEBUG
- printk("aurora_open: error board %d present %d\n",
- board, aurora_board[board].flags & AURORA_BOARD_PRESENT);
-#endif
- return -ENODEV;
- }
-
- bp = &aurora_board[board];
- port = aurora_port + board * AURORA_NPORT * AURORA_NCD180 + AURORA_PORT(tty->index);
- if ((aurora_paranoia_check(port, tty->name, "aurora_open")) {
-#ifdef AURORA_DEBUG
- printk("aurora_open: error paranoia check\n");
-#endif
- return -ENODEV;
- }
-
- port->count++;
- tty->driver_data = port;
- port->tty = tty;
-
- if ((error = aurora_setup_port(bp, port))) {
-#ifdef AURORA_DEBUG
- printk("aurora_open: error aurora_setup_port ret %d\n",error);
-#endif
- return error;
- }
-
- if ((error = block_til_ready(tty, filp, port))) {
-#ifdef AURORA_DEBUG
- printk("aurora_open: error block_til_ready ret %d\n",error);
-#endif
- return error;
- }
-
-#ifdef AURORA_DEBUG
- printk("aurora_open: end\n");
-#endif
- return 0;
-}
-
-static void aurora_close(struct tty_struct * tty, struct file * filp)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- struct Aurora_board *bp;
- unsigned long flags;
- unsigned long timeout;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_close: start\n");
-#endif
-
- if (!port || (aurora_paranoia_check(port, tty->name, "close"))
- return;
-
- chip = AURORA_CD180(port_No(port));
-
- save_flags(flags); cli();
- if (tty_hung_up_p(filp)) {
- restore_flags(flags);
- return;
- }
-
- bp = port_Board(port);
- if ((tty->count == 1) && (port->count != 1)) {
- printk(KERN_DEBUG "aurora%d: aurora_close: bad port count; "
- "tty->count is 1, port count is %d\n",
- board_No(bp), port->count);
- port->count = 1;
- }
- if (--port->count < 0) {
- printk(KERN_DEBUG "aurora%d: aurora_close: bad port "
- "count for tty%d: %d\n",
- board_No(bp), port_No(port), port->count);
- port->count = 0;
- }
- if (port->count) {
- restore_flags(flags);
- return;
- }
- port->flags |= ASYNC_CLOSING;
-
- /* Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
- if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE){
-#ifdef AURORA_DEBUG
- printk("aurora_close: waiting to flush...\n");
-#endif
- tty_wait_until_sent(tty, port->closing_wait);
- }
-
- /* At this point we stop accepting input. To do this, we
- * disable the receive line status interrupts, and tell the
- * interrupt driver to stop checking the data ready bit in the
- * line status register.
- */
- port->SRER &= ~SRER_RXD;
- if (port->flags & ASYNC_INITIALIZED) {
- port->SRER &= ~SRER_TXRDY;
- port->SRER |= SRER_TXEMPTY;
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
- /*
- * Before we drop DTR, make sure the UART transmitter
- * has completely drained; this is especially
- * important if there is a transmit FIFO!
- */
- timeout = jiffies+HZ;
- while(port->SRER & SRER_TXEMPTY) {
- msleep_interruptible(jiffies_to_msecs(port->timeout));
- if (time_after(jiffies, timeout))
- break;
- }
- }
-#ifdef AURORA_DEBUG
- printk("aurora_close: shutdown_port\n");
-#endif
- aurora_shutdown_port(bp, port);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- tty_ldisc_flush(tty);
- tty->closing = 0;
- port->event = 0;
- port->tty = 0;
- if (port->blocked_open) {
- if (port->close_delay) {
- msleep_interruptible(jiffies_to_msecs(port->close_delay));
- }
- wake_up_interruptible(&port->open_wait);
- }
- port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
- wake_up_interruptible(&port->close_wait);
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_close: end\n");
-#endif
-}
-
-static int aurora_write(struct tty_struct * tty,
- const unsigned char *buf, int count)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- struct Aurora_board *bp;
- int c, total = 0;
- unsigned long flags;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_write: start %d\n",count);
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_write"))
- return 0;
-
- chip = AURORA_CD180(port_No(port));
-
- bp = port_Board(port);
-
- if (!tty || !port->xmit_buf || !tmp_buf)
- return 0;
-
- save_flags(flags);
- while (1) {
- cli();
- c = min(count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - port->xmit_head));
- if (c <= 0) {
- restore_flags(flags);
- break;
- }
- memcpy(port->xmit_buf + port->xmit_head, buf, c);
- port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- port->xmit_cnt += c;
- restore_flags(flags);
-
- buf += c;
- count -= c;
- total += c;
- }
-
- cli();
- if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
- !(port->SRER & SRER_TXRDY)) {
- port->SRER |= SRER_TXRDY;
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
- }
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_write: end %d\n",total);
-#endif
- return total;
-}
-
-static void aurora_put_char(struct tty_struct * tty, unsigned char ch)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- unsigned long flags;
-
-#ifdef AURORA_DEBUG
- printk("aurora_put_char: start %c\n",ch);
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_put_char"))
- return;
-
- if (!tty || !port->xmit_buf)
- return;
-
- save_flags(flags); cli();
-
- if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
- restore_flags(flags);
- return;
- }
-
- port->xmit_buf[port->xmit_head++] = ch;
- port->xmit_head &= SERIAL_XMIT_SIZE - 1;
- port->xmit_cnt++;
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_put_char: end\n");
-#endif
-}
-
-static void aurora_flush_chars(struct tty_struct * tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- unsigned long flags;
- unsigned char chip;
-
-/*#ifdef AURORA_DEBUG
- printk("aurora_flush_chars: start\n");
-#endif*/
- if ((aurora_paranoia_check(port, tty->name, "aurora_flush_chars"))
- return;
-
- chip = AURORA_CD180(port_No(port));
-
- if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
- !port->xmit_buf)
- return;
-
- save_flags(flags); cli();
- port->SRER |= SRER_TXRDY;
- sbus_writeb(port_No(port) & 7,
- &port_Board(port)->r[chip]->r[CD180_CAR]);
- udelay(1);
- sbus_writeb(port->SRER,
- &port_Board(port)->r[chip]->r[CD180_SRER]);
- restore_flags(flags);
-/*#ifdef AURORA_DEBUG
- printk("aurora_flush_chars: end\n");
-#endif*/
-}
-
-static int aurora_write_room(struct tty_struct * tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- int ret;
-
-#ifdef AURORA_DEBUG
- printk("aurora_write_room: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_write_room"))
- return 0;
-
- ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
-#ifdef AURORA_DEBUG
- printk("aurora_write_room: end\n");
-#endif
- return ret;
-}
-
-static int aurora_chars_in_buffer(struct tty_struct *tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-
- if ((aurora_paranoia_check(port, tty->name, "aurora_chars_in_buffer"))
- return 0;
-
- return port->xmit_cnt;
-}
-
-static void aurora_flush_buffer(struct tty_struct *tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- unsigned long flags;
-
-#ifdef AURORA_DEBUG
- printk("aurora_flush_buffer: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_flush_buffer"))
- return;
-
- save_flags(flags); cli();
- port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- restore_flags(flags);
-
- tty_wakeup(tty);
-#ifdef AURORA_DEBUG
- printk("aurora_flush_buffer: end\n");
-#endif
-}
-
-static int aurora_tiocmget(struct tty_struct *tty, struct file *file)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- struct Aurora_board * bp;
- unsigned char status,chip;
- unsigned int result;
- unsigned long flags;
-
-#ifdef AURORA_DEBUG
- printk("aurora_get_modem_info: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, __FUNCTION__))
- return -ENODEV;
-
- chip = AURORA_CD180(port_No(port));
-
- bp = port_Board(port);
-
- save_flags(flags); cli();
-
- sbus_writeb(port_No(port) & 7, &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
-
- status = sbus_readb(&bp->r[chip]->r[CD180_MSVR]);
- result = 0/*bp->r[chip]->r[AURORA_RI] & (1u << port_No(port)) ? 0 : TIOCM_RNG*/;
-
- restore_flags(flags);
-
- result |= ((status & bp->RTS) ? TIOCM_RTS : 0)
- | ((status & bp->DTR) ? TIOCM_DTR : 0)
- | ((status & MSVR_CD) ? TIOCM_CAR : 0)
- | ((status & MSVR_DSR) ? TIOCM_DSR : 0)
- | ((status & MSVR_CTS) ? TIOCM_CTS : 0);
-
-#ifdef AURORA_DEBUG
- printk("aurora_get_modem_info: end\n");
-#endif
- return result;
-}
-
-static int aurora_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- unsigned int arg;
- unsigned long flags;
- struct Aurora_board *bp = port_Board(port);
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_set_modem_info: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, __FUNCTION__))
- return -ENODEV;
-
- chip = AURORA_CD180(port_No(port));
-
- save_flags(flags); cli();
- if (set & TIOCM_RTS)
- port->MSVR |= bp->RTS;
- if (set & TIOCM_DTR)
- port->MSVR |= bp->DTR;
- if (clear & TIOCM_RTS)
- port->MSVR &= ~bp->RTS;
- if (clear & TIOCM_DTR)
- port->MSVR &= ~bp->DTR;
-
- sbus_writeb(port_No(port) & 7, &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
-
- sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]);
-
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_set_modem_info: end\n");
-#endif
- return 0;
-}
-
-static void aurora_send_break(struct Aurora_port * port, unsigned long length)
-{
- struct Aurora_board *bp = port_Board(port);
- unsigned long flags;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_send_break: start\n");
-#endif
- chip = AURORA_CD180(port_No(port));
-
- save_flags(flags); cli();
-
- port->break_length = AURORA_TPS / HZ * length;
- port->COR2 |= COR2_ETC;
- port->SRER |= SRER_TXRDY;
- sbus_writeb(port_No(port) & 7, &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
-
- sbus_writeb(port->COR2, &bp->r[chip]->r[CD180_COR2]);
- sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
- aurora_wait_CCR(bp->r[chip]);
-
- sbus_writeb(CCR_CORCHG2, &bp->r[chip]->r[CD180_CCR]);
- aurora_wait_CCR(bp->r[chip]);
-
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_send_break: end\n");
-#endif
-}
-
-static int aurora_set_serial_info(struct Aurora_port * port,
- struct serial_struct * newinfo)
-{
- struct serial_struct tmp;
- struct Aurora_board *bp = port_Board(port);
- int change_speed;
- unsigned long flags;
-
-#ifdef AURORA_DEBUG
- printk("aurora_set_serial_info: start\n");
-#endif
- if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
- return -EFAULT;
-#if 0
- if ((tmp.irq != bp->irq) ||
- (tmp.port != bp->base) ||
- (tmp.type != PORT_CIRRUS) ||
- (tmp.baud_base != (bp->oscfreq + CD180_TPC/2) / CD180_TPC) ||
- (tmp.custom_divisor != 0) ||
- (tmp.xmit_fifo_size != CD180_NFIFO) ||
- (tmp.flags & ~AURORA_LEGAL_FLAGS))
- return -EINVAL;
-#endif
-
- change_speed = ((port->flags & ASYNC_SPD_MASK) !=
- (tmp.flags & ASYNC_SPD_MASK));
-
- if (!capable(CAP_SYS_ADMIN)) {
- if ((tmp.close_delay != port->close_delay) ||
- (tmp.closing_wait != port->closing_wait) ||
- ((tmp.flags & ~ASYNC_USR_MASK) !=
- (port->flags & ~ASYNC_USR_MASK)))
- return -EPERM;
- port->flags = ((port->flags & ~ASYNC_USR_MASK) |
- (tmp.flags & ASYNC_USR_MASK));
- } else {
- port->flags = ((port->flags & ~ASYNC_FLAGS) |
- (tmp.flags & ASYNC_FLAGS));
- port->close_delay = tmp.close_delay;
- port->closing_wait = tmp.closing_wait;
- }
- if (change_speed) {
- save_flags(flags); cli();
- aurora_change_speed(bp, port);
- restore_flags(flags);
- }
-#ifdef AURORA_DEBUG
- printk("aurora_set_serial_info: end\n");
-#endif
- return 0;
-}
-
-extern int aurora_get_serial_info(struct Aurora_port * port,
- struct serial_struct * retinfo)
-{
- struct serial_struct tmp;
- struct Aurora_board *bp = port_Board(port);
-
-#ifdef AURORA_DEBUG
- printk("aurora_get_serial_info: start\n");
-#endif
- if (!access_ok(VERIFY_WRITE, (void *) retinfo, sizeof(tmp)))
- return -EFAULT;
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = PORT_CIRRUS;
- tmp.line = port - aurora_port;
- tmp.port = 0;
- tmp.irq = bp->irq;
- tmp.flags = port->flags;
- tmp.baud_base = (bp->oscfreq + CD180_TPC/2) / CD180_TPC;
- tmp.close_delay = port->close_delay * HZ/100;
- tmp.closing_wait = port->closing_wait * HZ/100;
- tmp.xmit_fifo_size = CD180_NFIFO;
- copy_to_user(retinfo, &tmp, sizeof(tmp));
-#ifdef AURORA_DEBUG
-printk("aurora_get_serial_info: end\n");
-#endif
- return 0;
-}
-
-static int aurora_ioctl(struct tty_struct * tty, struct file * filp,
- unsigned int cmd, unsigned long arg)
-
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- int retval;
-
-#ifdef AURORA_DEBUG
- printk("aurora_ioctl: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_ioctl"))
- return -ENODEV;
-
- switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (!arg)
- aurora_send_break(port, HZ/4); /* 1/4 second */
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- aurora_send_break(port, arg ? arg*(HZ/10) : HZ/4);
- return 0;
- case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg);
- case TIOCSSOFTCAR:
- if (get_user(arg,(unsigned long *)arg))
- return -EFAULT;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
- case TIOCGSERIAL:
- return aurora_get_serial_info(port, (struct serial_struct *) arg);
- case TIOCSSERIAL:
- return aurora_set_serial_info(port, (struct serial_struct *) arg);
- default:
- return -ENOIOCTLCMD;
- };
-#ifdef AURORA_DEBUG
- printk("aurora_ioctl: end\n");
-#endif
- return 0;
-}
-
-static void aurora_throttle(struct tty_struct * tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- struct Aurora_board *bp;
- unsigned long flags;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_throttle: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_throttle"))
- return;
-
- bp = port_Board(port);
- chip = AURORA_CD180(port_No(port));
-
- save_flags(flags); cli();
- port->MSVR &= ~bp->RTS;
- sbus_writeb(port_No(port) & 7, &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- if (I_IXOFF(tty)) {
- aurora_wait_CCR(bp->r[chip]);
- sbus_writeb(CCR_SSCH2, &bp->r[chip]->r[CD180_CCR]);
- aurora_wait_CCR(bp->r[chip]);
- }
- sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]);
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_throttle: end\n");
-#endif
-}
-
-static void aurora_unthrottle(struct tty_struct * tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- struct Aurora_board *bp;
- unsigned long flags;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_unthrottle: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_unthrottle"))
- return;
-
- bp = port_Board(port);
-
- chip = AURORA_CD180(port_No(port));
-
- save_flags(flags); cli();
- port->MSVR |= bp->RTS;
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- if (I_IXOFF(tty)) {
- aurora_wait_CCR(bp->r[chip]);
- sbus_writeb(CCR_SSCH1,
- &bp->r[chip]->r[CD180_CCR]);
- aurora_wait_CCR(bp->r[chip]);
- }
- sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]);
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_unthrottle: end\n");
-#endif
-}
-
-static void aurora_stop(struct tty_struct * tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- struct Aurora_board *bp;
- unsigned long flags;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_stop: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_stop"))
- return;
-
- bp = port_Board(port);
-
- chip = AURORA_CD180(port_No(port));
-
- save_flags(flags); cli();
- port->SRER &= ~SRER_TXRDY;
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- sbus_writeb(port->SRER,
- &bp->r[chip]->r[CD180_SRER]);
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_stop: end\n");
-#endif
-}
-
-static void aurora_start(struct tty_struct * tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- struct Aurora_board *bp;
- unsigned long flags;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_start: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_start"))
- return;
-
- bp = port_Board(port);
-
- chip = AURORA_CD180(port_No(port));
-
- save_flags(flags); cli();
- if (port->xmit_cnt && port->xmit_buf && !(port->SRER & SRER_TXRDY)) {
- port->SRER |= SRER_TXRDY;
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- sbus_writeb(port->SRER,
- &bp->r[chip]->r[CD180_SRER]);
- }
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_start: end\n");
-#endif
-}
-
-/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred. The path of
- * hangup processing is:
- *
- * serial interrupt routine -> (scheduler tqueue) ->
- * do_aurora_hangup() -> tty->hangup() -> aurora_hangup()
- *
- */
-static void do_aurora_hangup(void *private_)
-{
- struct Aurora_port *port = (struct Aurora_port *) private_;
- struct tty_struct *tty;
-
-#ifdef AURORA_DEBUG
- printk("do_aurora_hangup: start\n");
-#endif
- tty = port->tty;
- if (tty != NULL) {
- tty_hangup(tty); /* FIXME: module removal race - AKPM */
-#ifdef AURORA_DEBUG
- printk("do_aurora_hangup: end\n");
-#endif
- }
-}
-
-static void aurora_hangup(struct tty_struct * tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- struct Aurora_board *bp;
-
-#ifdef AURORA_DEBUG
- printk("aurora_hangup: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_hangup"))
- return;
-
- bp = port_Board(port);
-
- aurora_shutdown_port(bp, port);
- port->event = 0;
- port->count = 0;
- port->flags &= ~ASYNC_NORMAL_ACTIVE;
- port->tty = 0;
- wake_up_interruptible(&port->open_wait);
-#ifdef AURORA_DEBUG
- printk("aurora_hangup: end\n");
-#endif
-}
-
-static void aurora_set_termios(struct tty_struct * tty, struct termios * old_termios)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- unsigned long flags;
-
-#ifdef AURORA_DEBUG
- printk("aurora_set_termios: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_set_termios"))
- return;
-
- if (tty->termios->c_cflag == old_termios->c_cflag &&
- tty->termios->c_iflag == old_termios->c_iflag)
- return;
-
- save_flags(flags); cli();
- aurora_change_speed(port_Board(port), port);
- restore_flags(flags);
-
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- aurora_start(tty);
- }
-#ifdef AURORA_DEBUG
- printk("aurora_set_termios: end\n");
-#endif
-}
-
-static void do_aurora_bh(void)
-{
- run_task_queue(&tq_aurora);
-}
-
-static void do_softint(void *private_)
-{
- struct Aurora_port *port = (struct Aurora_port *) private_;
- struct tty_struct *tty;
-
-#ifdef AURORA_DEBUG
- printk("do_softint: start\n");
-#endif
- tty = port->tty;
- if (tty == NULL)
- return;
-
- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
- tty_wakeup(tty);
- }
-#ifdef AURORA_DEBUG
- printk("do_softint: end\n");
-#endif
-}
-
-static const struct tty_operations aurora_ops = {
- .open = aurora_open,
- .close = aurora_close,
- .write = aurora_write,
- .put_char = aurora_put_char,
- .flush_chars = aurora_flush_chars,
- .write_room = aurora_write_room,
- .chars_in_buffer = aurora_chars_in_buffer,
- .flush_buffer = aurora_flush_buffer,
- .ioctl = aurora_ioctl,
- .throttle = aurora_throttle,
- .unthrottle = aurora_unthrottle,
- .set_termios = aurora_set_termios,
- .stop = aurora_stop,
- .start = aurora_start,
- .hangup = aurora_hangup,
- .tiocmget = aurora_tiocmget,
- .tiocmset = aurora_tiocmset,
-};
-
-static int aurora_init_drivers(void)
-{
- int error;
- int i;
-
-#ifdef AURORA_DEBUG
- printk("aurora_init_drivers: start\n");
-#endif
- tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
- if (tmp_buf == NULL) {
- printk(KERN_ERR "aurora: Couldn't get free page.\n");
- return 1;
- }
- init_bh(AURORA_BH, do_aurora_bh);
- aurora_driver = alloc_tty_driver(AURORA_INPORTS);
- if (!aurora_driver) {
- printk(KERN_ERR "aurora: Couldn't allocate tty driver.\n");
- free_page((unsigned long) tmp_buf);
- return 1;
- }
- aurora_driver->owner = THIS_MODULE;
- aurora_driver->name = "ttyA";
- aurora_driver->major = AURORA_MAJOR;
- aurora_driver->type = TTY_DRIVER_TYPE_SERIAL;
- aurora_driver->subtype = SERIAL_TYPE_NORMAL;
- aurora_driver->init_termios = tty_std_termios;
- aurora_driver->init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- aurora_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(aurora_driver, &aurora_ops);
- error = tty_register_driver(aurora_driver);
- if (error) {
- put_tty_driver(aurora_driver);
- free_page((unsigned long) tmp_buf);
- printk(KERN_ERR "aurora: Couldn't register aurora driver, error = %d\n",
- error);
- return 1;
- }
-
- memset(aurora_port, 0, sizeof(aurora_port));
- for (i = 0; i < AURORA_TNPORTS; i++) {
- aurora_port[i].magic = AURORA_MAGIC;
- aurora_port[i].tqueue.routine = do_softint;
- aurora_port[i].tqueue.data = &aurora_port[i];
- aurora_port[i].tqueue_hangup.routine = do_aurora_hangup;
- aurora_port[i].tqueue_hangup.data = &aurora_port[i];
- aurora_port[i].close_delay = 50 * HZ/100;
- aurora_port[i].closing_wait = 3000 * HZ/100;
- init_waitqueue_head(&aurora_port[i].open_wait);
- init_waitqueue_head(&aurora_port[i].close_wait);
- }
-#ifdef AURORA_DEBUG
- printk("aurora_init_drivers: end\n");
-#endif
- return 0;
-}
-
-static void aurora_release_drivers(void)
-{
-#ifdef AURORA_DEBUG
- printk("aurora_release_drivers: start\n");
-#endif
- free_page((unsigned long)tmp_buf);
- tty_unregister_driver(aurora_driver);
- put_tty_driver(aurora_driver);
-#ifdef AURORA_DEBUG
- printk("aurora_release_drivers: end\n");
-#endif
-}
-
-/*
- * Called at boot time.
- *
- * You can specify IO base for up to RC_NBOARD cards,
- * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt.
- * Note that there will be no probing at default
- * addresses in this case.
- *
- */
-void __init aurora_setup(char *str, int *ints)
-{
- int i;
-
- for(i=0;(i<ints[0])&&(i<4);i++) {
- if (ints[i+1]) irqs[i]=ints[i+1];
- }
-}
-
-static int __init aurora_real_init(void)
-{
- int found;
- int i;
-
- printk(KERN_INFO "aurora: Driver starting.\n");
- if(aurora_init_drivers())
- return -EIO;
- found = aurora_probe();
- if(!found) {
- aurora_release_drivers();
- printk(KERN_INFO "aurora: No Aurora Multiport boards detected.\n");
- return -EIO;
- } else {
- printk(KERN_INFO "aurora: %d boards found.\n", found);
- }
- for (i = 0; i < found; i++) {
- int ret = aurora_setup_board(&aurora_board[i]);
-
- if (ret) {
-#ifdef AURORA_DEBUG
- printk(KERN_ERR "aurora_init: error aurora_setup_board ret %d\n",
- ret);
-#endif
- return ret;
- }
- }
- return 0;
-}
-
-int irq = 0;
-int irq1 = 0;
-int irq2 = 0;
-int irq3 = 0;
-module_param(irq , int, 0);
-module_param(irq1, int, 0);
-module_param(irq2, int, 0);
-module_param(irq3, int, 0);
-
-static int __init aurora_init(void)
-{
- if (irq ) irqs[0]=irq ;
- if (irq1) irqs[1]=irq1;
- if (irq2) irqs[2]=irq2;
- if (irq3) irqs[3]=irq3;
- return aurora_real_init();
-}
-
-static void __exit aurora_cleanup(void)
-{
- int i;
-
-#ifdef AURORA_DEBUG
-printk("cleanup_module: aurora_release_drivers\n");
-#endif
-
- aurora_release_drivers();
- for (i = 0; i < AURORA_NBOARD; i++)
- if (aurora_board[i].flags & AURORA_BOARD_PRESENT) {
- aurora_shutdown_board(&aurora_board[i]);
- aurora_release_io_range(&aurora_board[i]);
- }
-}
-
-module_init(aurora_init);
-module_exit(aurora_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/aurora.h b/drivers/sbus/char/aurora.h
deleted file mode 100644
index b8b5476d986..00000000000
--- a/drivers/sbus/char/aurora.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/* $Id: aurora.h,v 1.6 2001/06/05 12:23:38 davem Exp $
- * linux/drivers/sbus/char/aurora.h -- Aurora multiport driver
- *
- * Copyright (c) 1999 by Oliver Aldulea (oli@bv.ro)
- *
- * This code is based on the RISCom/8 multiport serial driver written
- * by Dmitry Gorodchanin (pgmdsg@ibi.com), based on the Linux serial
- * driver, written by Linus Torvalds, Theodore T'so and others.
- * The Aurora multiport programming info was obtained mainly from the
- * Cirrus Logic CD180 documentation (available on the web), and by
- * doing heavy tests on the board. Many thanks to Eddie C. Dost for the
- * help on the sbus interface.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Revision 1.0
- *
- * This is the first public release.
- *
- * This version needs a lot of feedback. This is the version that works
- * with _my_ board. My board is model 1600se, revision '@(#)1600se.fth
- * 1.2 3/28/95 1'. The driver might work with your board, but I do not
- * guarantee it. If you have _any_ type of board, I need to know if the
- * driver works or not, I need to know exactly your board parameters
- * (get them with 'cd /proc/openprom/iommu/sbus/sio16/; ls *; cat *')
- * Also, I need your board revision code, which is written on the board.
- * Send me the output of my driver too (it outputs through klogd).
- *
- * If the driver does not work, you can try enabling the debug options
- * to see what's wrong or what should be done.
- *
- * I'm sorry about the alignment of the code. It was written in a
- * 128x48 environment.
- *
- * I must say that I do not like Aurora Technologies' policy. I asked
- * them to help me do this driver faster, but they ended by something
- * like "don't call us, we'll call you", and I never heard anything
- * from them. They told me "knowing the way the board works, I don't
- * doubt you and others on the net will make the driver."
- * The truth about this board is that it has nothing intelligent on it.
- * If you want to say to somebody what kind of board you have, say that
- * it uses Cirrus Logic processors (CD180). The power of the board is
- * in those two chips. The rest of the board is the interface to the
- * sbus and to the peripherals. Still, they did something smart: they
- * reversed DTR and RTS to make on-board automatic hardware flow
- * control usable.
- * Thanks to Aurora Technologies for wasting my time, nerves and money.
- */
-
-#ifndef __LINUX_AURORA_H
-#define __LINUX_AURORA_H
-
-#include <linux/serial.h>
-#include <linux/serialP.h>
-
-#ifdef __KERNEL__
-
-/* This is the number of boards to support. I've only tested this driver with
- * one board, so it might not work.
- */
-#define AURORA_NBOARD 1
-
-/* Useful ? Yes. But you can safely comment the warnings if they annoy you
- * (let me say that again: the warnings in the code, not this define).
- */
-#define AURORA_PARANOIA_CHECK
-
-/* Well, after many lost nights, I found that the IRQ for this board is
- * selected from four built-in values by writing some bits in the
- * configuration register. This causes a little problem to occur: which
- * IRQ to select ? Which one is the best for the user ? Well, I finally
- * decided for the following algorithm: if the "bintr" value is not acceptable
- * (not within type_1_irq[], then test the "intr" value, if that fails too,
- * try each value from type_1_irq until succeded. Hope it's ok.
- * You can safely reorder the irq's.
- */
-#define TYPE_1_IRQS 4
-unsigned char type_1_irq[TYPE_1_IRQS] = {
- 3, 5, 9, 13
-};
-/* I know something about another method of interrupt setting, but not enough.
- * Also, this is for another type of board, so I first have to learn how to
- * detect it.
-#define TYPE_2_IRQS 3
-unsigned char type_2_irq[TYPE_2_IRQS] = {
- 0, 0, 0 ** could anyone find these for me ? (see AURORA_ALLIRQ below) **
- };
-unsigned char type_2_mask[TYPE_2_IRQS] = {
- 32, 64, 128
- };
-*/
-
-/* The following section should only be modified by those who know what
- * they're doing (or don't, but want to help with some feedback). Modifying
- * anything raises a _big_ probability for your system to hang, but the
- * sacrifice worths. (I sacrificed my ext2fs many, many times...)
- */
-
-/* This one tries to dump to console the name of almost every function called,
- * and many other debugging info.
- */
-#undef AURORA_DEBUG
-
-/* These are the most dangerous and useful defines. They do printk() during
- * the interrupt processing routine(s), so if you manage to get "flooded" by
- * irq's, start thinking about the "Power off/on" button...
- */
-#undef AURORA_INTNORM /* This one enables the "normal" messages, but some
- * of them cause flood, so I preffered putting
- * them under a define */
-#undef AURORA_INT_DEBUG /* This one is really bad. */
-
-/* Here's something helpful: after n irq's, the board will be disabled. This
- * prevents irq flooding during debug (no need to think about power
- * off/on anymore...)
- */
-#define AURORA_FLOODPRO 10
-
-/* This one helps finding which irq the board calls, in case of a strange/
- * unsupported board. AURORA_INT_DEBUG should be enabled, because I don't
- * think /proc/interrupts or any command will be available in case of an irq
- * flood... "allirq" is the list of all free irq's.
- */
-/*
-#define AURORA_ALLIRQ 6
-int allirq[AURORA_ALLIRQ]={
- 2,3,5,7,9,13
- };
-*/
-
-/* These must not be modified. These values are assumed during the code for
- * performance optimisations.
- */
-#define AURORA_NCD180 2 /* two chips per board */
-#define AURORA_NPORT 8 /* 8 ports per chip */
-
-/* several utilities */
-#define AURORA_BOARD(line) (((line) >> 4) & 0x01)
-#define AURORA_CD180(line) (((line) >> 3) & 0x01)
-#define AURORA_PORT(line) ((line) & 15)
-
-#define AURORA_TNPORTS (AURORA_NBOARD*AURORA_NCD180*AURORA_NPORT)
-
-/* Ticks per sec. Used for setting receiver timeout and break length */
-#define AURORA_TPS 4000
-
-#define AURORA_MAGIC 0x0A18
-
-/* Yeah, after heavy testing I decided it must be 6.
- * Sure, You can change it if needed.
- */
-#define AURORA_RXFIFO 6 /* Max. receiver FIFO size (1-8) */
-
-#define AURORA_RXTH 7
-
-struct aurora_reg1 {
- __volatile__ unsigned char r;
-};
-
-struct aurora_reg128 {
- __volatile__ unsigned char r[128];
-};
-
-struct aurora_reg4 {
- __volatile__ unsigned char r[4];
-};
-
-struct Aurora_board {
- unsigned long flags;
- struct aurora_reg1 * r0; /* This is the board configuration
- * register (write-only). */
- struct aurora_reg128 * r[2]; /* These are the registers for the
- * two chips. */
- struct aurora_reg4 * r3; /* These are used for hardware-based
- * acknowledge. Software-based ack is
- * not supported by CD180. */
- unsigned int oscfreq; /* The on-board oscillator
- * frequency, in Hz. */
- unsigned char irq;
-#ifdef MODULE
- signed char count; /* counts the use of the board */
-#endif
- /* Values for the dtr_rts swapped mode. */
- unsigned char DTR;
- unsigned char RTS;
- unsigned char MSVDTR;
- unsigned char MSVRTS;
- /* Values for hardware acknowledge. */
- unsigned char ACK_MINT, ACK_TINT, ACK_RINT;
-};
-
-/* Board configuration register */
-#define AURORA_CFG_ENABLE_IO 8
-#define AURORA_CFG_ENABLE_IRQ 4
-
-/* Board flags */
-#define AURORA_BOARD_PRESENT 0x00000001
-#define AURORA_BOARD_ACTIVE 0x00000002
-#define AURORA_BOARD_TYPE_2 0x00000004 /* don't know how to
- * detect this yet */
-#define AURORA_BOARD_DTR_FLOW_OK 0x00000008
-
-/* The story goes like this: Cirrus programmed the CD-180 chip to do automatic
- * hardware flow control, and do it using CTS and DTR. CTS is ok, but, if you
- * have a modem and the chip drops DTR, then the modem will drop the carrier
- * (ain't that cute...). Luckily, the guys at Aurora decided to swap DTR and
- * RTS, which makes the flow control usable. I hope that all the boards made
- * by Aurora have these two signals swapped. If your's doesn't but you have a
- * breakout box, you can try to reverse them yourself, then set the following
- * flag.
- */
-#undef AURORA_FORCE_DTR_FLOW
-
-/* In fact, a few more words have to be said about hardware flow control.
- * This driver handles "output" flow control through the on-board facility
- * CTS Auto Enable. For the "input" flow control there are two cases when
- * the flow should be controlled. The first case is when the kernel is so
- * busy that it cannot process IRQ's in time; this flow control can only be
- * activated by the on-board chip, and if the board has RTS and DTR swapped,
- * this facility is usable. The second case is when the application is so
- * busy that it cannot receive bytes from the kernel, and this flow must be
- * activated by software. This second case is not yet implemented in this
- * driver. Unfortunately, I estimate that the second case is the one that
- * occurs the most.
- */
-
-
-struct Aurora_port {
- int magic;
- int baud_base;
- int flags;
- struct tty_struct * tty;
- int count;
- int blocked_open;
- long event;
- int timeout;
- int close_delay;
- unsigned char * xmit_buf;
- int custom_divisor;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
- struct tq_struct tqueue;
- struct tq_struct tqueue_hangup;
- short wakeup_chars;
- short break_length;
- unsigned short closing_wait;
- unsigned char mark_mask;
- unsigned char SRER;
- unsigned char MSVR;
- unsigned char COR2;
-#ifdef AURORA_REPORT_OVERRUN
- unsigned long overrun;
-#endif
-#ifdef AURORA_REPORT_FIFO
- unsigned long hits[10];
-#endif
-};
-
-#endif
-#endif /*__LINUX_AURORA_H*/
-
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c
index 22631f8b9b4..8410587348f 100644
--- a/drivers/sbus/char/bbc_i2c.c
+++ b/drivers/sbus/char/bbc_i2c.c
@@ -187,19 +187,20 @@ static int wait_for_pin(struct bbc_i2c_bus *bp, u8 *status)
bp->waiting = 1;
add_wait_queue(&bp->wq, &wait);
while (limit-- > 0) {
- u8 val;
-
- set_current_state(TASK_INTERRUPTIBLE);
- *status = val = readb(bp->i2c_control_regs + 0);
- if ((val & I2C_PCF_PIN) == 0) {
+ unsigned long val;
+
+ val = wait_event_interruptible_timeout(
+ bp->wq,
+ (((*status = readb(bp->i2c_control_regs + 0))
+ & I2C_PCF_PIN) == 0),
+ msecs_to_jiffies(250));
+ if (val > 0) {
ret = 0;
break;
}
- msleep_interruptible(250);
}
remove_wait_queue(&bp->wq, &wait);
bp->waiting = 0;
- current->state = TASK_RUNNING;
return ret;
}
@@ -340,7 +341,7 @@ static irqreturn_t bbc_i2c_interrupt(int irq, void *dev_id)
*/
if (bp->waiting &&
!(readb(bp->i2c_control_regs + 0x0) & I2C_PCF_PIN))
- wake_up(&bp->wq);
+ wake_up_interruptible(&bp->wq);
return IRQ_HANDLED;
}
diff --git a/drivers/sbus/char/cd180.h b/drivers/sbus/char/cd180.h
deleted file mode 100644
index 445b86cc65e..00000000000
--- a/drivers/sbus/char/cd180.h
+++ /dev/null
@@ -1,240 +0,0 @@
-
-/* Definitions for Cirrus Logic CL-CD180 8-port async mux chip */
-#define CD180_NCH 8 /* Total number of channels */
-#define CD180_TPC 16 /* Ticks per character */
-#define CD180_NFIFO 8 /* TX FIFO size */
-
-/* Global registers */
-#define CD180_GFRCR 0x6b /* Global Firmware Revision Code Register */
-#define CD180_SRCR 0x66 /* Service Request Configuration Register */
-#define CD180_PPRH 0x70 /* Prescaler Period Register High */
-#define CD180_PPRL 0x71 /* Prescaler Period Register Low */
-#define CD180_MSMR 0x61 /* Modem Service Match Register */
-#define CD180_TSMR 0x62 /* Transmit Service Match Register */
-#define CD180_RSMR 0x63 /* Receive Service Match Register */
-#define CD180_GSVR 0x40 /* Global Service Vector Register */
-#define CD180_SRSR 0x65 /* Service Request Status Register */
-#define CD180_GSCR 0x41 /* Global Service Channel Register */
-#define CD180_CAR 0x64 /* Channel Access Register */
-
-/* Indexed registers */
-#define CD180_RDCR 0x07 /* Receive Data Count Register */
-#define CD180_RDR 0x78 /* Receiver Data Register */
-#define CD180_RCSR 0x7a /* Receiver Character Status Register */
-#define CD180_TDR 0x7b /* Transmit Data Register */
-#define CD180_EOSRR 0x7f /* End of Service Request Register */
-
-/* Channel Registers */
-#define CD180_SRER 0x02 /* Service Request Enable Register */
-#define CD180_CCR 0x01 /* Channel Command Register */
-#define CD180_COR1 0x03 /* Channel Option Register 1 */
-#define CD180_COR2 0x04 /* Channel Option Register 2 */
-#define CD180_COR3 0x05 /* Channel Option Register 3 */
-#define CD180_CCSR 0x06 /* Channel Control Status Register */
-#define CD180_RTPR 0x18 /* Receive Timeout Period Register */
-#define CD180_RBPRH 0x31 /* Receive Bit Rate Period Register High */
-#define CD180_RBPRL 0x32 /* Receive Bit Rate Period Register Low */
-#define CD180_TBPRH 0x39 /* Transmit Bit Rate Period Register High */
-#define CD180_TBPRL 0x3a /* Transmit Bit Rate Period Register Low */
-#define CD180_SCHR1 0x09 /* Special Character Register 1 */
-#define CD180_SCHR2 0x0a /* Special Character Register 2 */
-#define CD180_SCHR3 0x0b /* Special Character Register 3 */
-#define CD180_SCHR4 0x0c /* Special Character Register 4 */
-#define CD180_MCR 0x12 /* Modem Change Register */
-#define CD180_MCOR1 0x10 /* Modem Change Option 1 Register */
-#define CD180_MCOR2 0x11 /* Modem Change Option 2 Register */
-#define CD180_MSVR 0x28 /* Modem Signal Value Register */
-#define CD180_MSVRTS 0x29 /* Modem Signal Value RTS */
-#define CD180_MSVDTR 0x2a /* Modem Signal Value DTR */
-
-/* Global Interrupt Vector Register (R/W) */
-
-#define GSVR_ITMASK 0x07 /* Interrupt type mask */
-#define GSVR_IT_MDM 0x01 /* Modem Signal Change Interrupt */
-#define GSVR_IT_TX 0x02 /* Transmit Data Interrupt */
-#define GSVR_IT_RGD 0x03 /* Receive Good Data Interrupt */
-#define GSVR_IT_REXC 0x07 /* Receive Exception Interrupt */
-
-
-/* Global Interrupt Channel Register (R/W) */
-
-#define GSCR_CHAN 0x1c /* Channel Number Mask */
-#define GSCR_CHAN_OFF 2 /* Channel Number Offset */
-
-
-/* Channel Address Register (R/W) */
-
-#define CAR_CHAN 0x07 /* Channel Number Mask */
-
-
-/* Receive Character Status Register (R/O) */
-
-#define RCSR_TOUT 0x80 /* Rx Timeout */
-#define RCSR_SCDET 0x70 /* Special Character Detected Mask */
-#define RCSR_NO_SC 0x00 /* No Special Characters Detected */
-#define RCSR_SC_1 0x10 /* Special Char 1 (or 1 & 3) Detected */
-#define RCSR_SC_2 0x20 /* Special Char 2 (or 2 & 4) Detected */
-#define RCSR_SC_3 0x30 /* Special Char 3 Detected */
-#define RCSR_SC_4 0x40 /* Special Char 4 Detected */
-#define RCSR_BREAK 0x08 /* Break has been detected */
-#define RCSR_PE 0x04 /* Parity Error */
-#define RCSR_FE 0x02 /* Frame Error */
-#define RCSR_OE 0x01 /* Overrun Error */
-
-
-/* Channel Command Register (R/W) (commands in groups can be OR-ed) */
-
-#define CCR_HARDRESET 0x81 /* Reset the chip */
-
-#define CCR_SOFTRESET 0x80 /* Soft Channel Reset */
-
-#define CCR_CORCHG1 0x42 /* Channel Option Register 1 Changed */
-#define CCR_CORCHG2 0x44 /* Channel Option Register 2 Changed */
-#define CCR_CORCHG3 0x48 /* Channel Option Register 3 Changed */
-
-#define CCR_SSCH1 0x21 /* Send Special Character 1 */
-
-#define CCR_SSCH2 0x22 /* Send Special Character 2 */
-
-#define CCR_SSCH3 0x23 /* Send Special Character 3 */
-
-#define CCR_SSCH4 0x24 /* Send Special Character 4 */
-
-#define CCR_TXEN 0x18 /* Enable Transmitter */
-#define CCR_RXEN 0x12 /* Enable Receiver */
-
-#define CCR_TXDIS 0x14 /* Disable Transmitter */
-#define CCR_RXDIS 0x11 /* Disable Receiver */
-
-
-/* Service Request Enable Register (R/W) */
-
-#define SRER_DSR 0x80 /* Enable interrupt on DSR change */
-#define SRER_CD 0x40 /* Enable interrupt on CD change */
-#define SRER_CTS 0x20 /* Enable interrupt on CTS change */
-#define SRER_RXD 0x10 /* Enable interrupt on Receive Data */
-#define SRER_RXSC 0x08 /* Enable interrupt on Receive Spec. Char */
-#define SRER_TXRDY 0x04 /* Enable interrupt on TX FIFO empty */
-#define SRER_TXEMPTY 0x02 /* Enable interrupt on TX completely empty */
-#define SRER_RET 0x01 /* Enable interrupt on RX Exc. Timeout */
-
-
-/* Channel Option Register 1 (R/W) */
-
-#define COR1_ODDP 0x80 /* Odd Parity */
-#define COR1_PARMODE 0x60 /* Parity Mode mask */
-#define COR1_NOPAR 0x00 /* No Parity */
-#define COR1_FORCEPAR 0x20 /* Force Parity */
-#define COR1_NORMPAR 0x40 /* Normal Parity */
-#define COR1_IGNORE 0x10 /* Ignore Parity on RX */
-#define COR1_STOPBITS 0x0c /* Number of Stop Bits */
-#define COR1_1SB 0x00 /* 1 Stop Bit */
-#define COR1_15SB 0x04 /* 1.5 Stop Bits */
-#define COR1_2SB 0x08 /* 2 Stop Bits */
-#define COR1_CHARLEN 0x03 /* Character Length */
-#define COR1_5BITS 0x00 /* 5 bits */
-#define COR1_6BITS 0x01 /* 6 bits */
-#define COR1_7BITS 0x02 /* 7 bits */
-#define COR1_8BITS 0x03 /* 8 bits */
-
-
-/* Channel Option Register 2 (R/W) */
-
-#define COR2_IXM 0x80 /* Implied XON mode */
-#define COR2_TXIBE 0x40 /* Enable In-Band (XON/XOFF) Flow Control */
-#define COR2_ETC 0x20 /* Embedded Tx Commands Enable */
-#define COR2_LLM 0x10 /* Local Loopback Mode */
-#define COR2_RLM 0x08 /* Remote Loopback Mode */
-#define COR2_RTSAO 0x04 /* RTS Automatic Output Enable */
-#define COR2_CTSAE 0x02 /* CTS Automatic Enable */
-#define COR2_DSRAE 0x01 /* DSR Automatic Enable */
-
-
-/* Channel Option Register 3 (R/W) */
-
-#define COR3_XONCH 0x80 /* XON is a pair of characters (1 & 3) */
-#define COR3_XOFFCH 0x40 /* XOFF is a pair of characters (2 & 4) */
-#define COR3_FCT 0x20 /* Flow-Control Transparency Mode */
-#define COR3_SCDE 0x10 /* Special Character Detection Enable */
-#define COR3_RXTH 0x0f /* RX FIFO Threshold value (1-8) */
-
-
-/* Channel Control Status Register (R/O) */
-
-#define CCSR_RXEN 0x80 /* Receiver Enabled */
-#define CCSR_RXFLOFF 0x40 /* Receive Flow Off (XOFF was sent) */
-#define CCSR_RXFLON 0x20 /* Receive Flow On (XON was sent) */
-#define CCSR_TXEN 0x08 /* Transmitter Enabled */
-#define CCSR_TXFLOFF 0x04 /* Transmit Flow Off (got XOFF) */
-#define CCSR_TXFLON 0x02 /* Transmit Flow On (got XON) */
-
-
-/* Modem Change Option Register 1 (R/W) */
-
-#define MCOR1_DSRZD 0x80 /* Detect 0->1 transition of DSR */
-#define MCOR1_CDZD 0x40 /* Detect 0->1 transition of CD */
-#define MCOR1_CTSZD 0x20 /* Detect 0->1 transition of CTS */
-#define MCOR1_DTRTH 0x0f /* Auto DTR flow control Threshold (1-8) */
-#define MCOR1_NODTRFC 0x0 /* Automatic DTR flow control disabled */
-
-
-/* Modem Change Option Register 2 (R/W) */
-
-#define MCOR2_DSROD 0x80 /* Detect 1->0 transition of DSR */
-#define MCOR2_CDOD 0x40 /* Detect 1->0 transition of CD */
-#define MCOR2_CTSOD 0x20 /* Detect 1->0 transition of CTS */
-
-
-/* Modem Change Register (R/W) */
-
-#define MCR_DSRCHG 0x80 /* DSR Changed */
-#define MCR_CDCHG 0x40 /* CD Changed */
-#define MCR_CTSCHG 0x20 /* CTS Changed */
-
-
-/* Modem Signal Value Register (R/W) */
-
-#define MSVR_DSR 0x80 /* Current state of DSR input */
-#define MSVR_CD 0x40 /* Current state of CD input */
-#define MSVR_CTS 0x20 /* Current state of CTS input */
-#define MSVR_DTR 0x02 /* Current state of DTR output */
-#define MSVR_RTS 0x01 /* Current state of RTS output */
-
-
-/* Service Request Status Register */
-
-#define SRSR_CMASK 0xC0 /* Current Service Context Mask */
-#define SRSR_CNONE 0x00 /* Not in a service context */
-#define SRSR_CRX 0x40 /* Rx Context */
-#define SRSR_CTX 0x80 /* Tx Context */
-#define SRSR_CMDM 0xC0 /* Modem Context */
-#define SRSR_ANYINT 0x6F /* Any interrupt flag */
-#define SRSR_RINT 0x10 /* Receive Interrupt */
-#define SRSR_TINT 0x04 /* Transmit Interrupt */
-#define SRSR_MINT 0x01 /* Modem Interrupt */
-#define SRSR_REXT 0x20 /* Receive External Interrupt */
-#define SRSR_TEXT 0x08 /* Transmit External Interrupt */
-#define SRSR_MEXT 0x02 /* Modem External Interrupt */
-
-
-/* Service Request Configuration Register */
-
-#define SRCR_PKGTYPE 0x80
-#define SRCR_REGACKEN 0x40
-#define SRCR_DAISYEN 0x20
-#define SRCR_GLOBPRI 0x10
-#define SRCR_UNFAIR 0x08
-#define SRCR_AUTOPRI 0x02
-#define SRCR_PRISEL 0x01
-
-/* Values for register-based Interrupt ACKs */
-#define CD180_ACK_MINT 0x75 /* goes to MSMR */
-#define CD180_ACK_TINT 0x76 /* goes to TSMR */
-#define CD180_ACK_RINT 0x77 /* goes to RSMR */
-
-/* Escape characters */
-
-#define CD180_C_ESC 0x00 /* Escape character */
-#define CD180_C_SBRK 0x81 /* Start sending BREAK */
-#define CD180_C_DELAY 0x82 /* Delay output */
-#define CD180_C_EBRK 0x83 /* Stop sending BREAK */
diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index 45cf5bc0bbe..44d2ef906ac 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -364,6 +364,7 @@ static int __init ts102_uctrl_init(void)
struct linux_prom_irqs tmp_irq[2];
unsigned int vaddr[2] = { 0, 0 };
int tmpnode, uctrlnode = prom_getchild(prom_root_node);
+ int err;
tmpnode = prom_searchsiblings(uctrlnode, "obio");
@@ -389,7 +390,12 @@ static int __init ts102_uctrl_init(void)
if(!driver->irq)
driver->irq = tmp_irq[0].pri;
- request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
+ err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
+ if (err) {
+ printk("%s: unable to register irq %d\n",
+ __FUNCTION__, driver->irq);
+ return err;
+ }
if (misc_register(&uctrl_dev)) {
printk("%s: unable to get misc minor %d\n",
diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c
index d2d51dc51ab..82add77ad13 100644
--- a/drivers/scsi/arm/cumana_2.c
+++ b/drivers/scsi/arm/cumana_2.c
@@ -178,10 +178,10 @@ cumanascsi_2_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp,
dma_dir = DMA_MODE_READ,
alatch_dir = ALATCH_DMA_IN;
- dma_map_sg(dev, info->sg, bufs + 1, map_dir);
+ dma_map_sg(dev, info->sg, bufs, map_dir);
disable_dma(dmach);
- set_dma_sg(dmach, info->sg, bufs + 1);
+ set_dma_sg(dmach, info->sg, bufs);
writeb(alatch_dir, info->base + CUMANASCSI2_ALATCH);
set_dma_mode(dmach, dma_dir);
enable_dma(dmach);
diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c
index d4136524fc4..ed06a8c19ad 100644
--- a/drivers/scsi/arm/eesox.c
+++ b/drivers/scsi/arm/eesox.c
@@ -175,10 +175,10 @@ eesoxscsi_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp,
map_dir = DMA_FROM_DEVICE,
dma_dir = DMA_MODE_READ;
- dma_map_sg(dev, info->sg, bufs + 1, map_dir);
+ dma_map_sg(dev, info->sg, bufs, map_dir);
disable_dma(dmach);
- set_dma_sg(dmach, info->sg, bufs + 1);
+ set_dma_sg(dmach, info->sg, bufs);
set_dma_mode(dmach, dma_dir);
enable_dma(dmach);
return fasdma_real_all;
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index 2969cc0ff25..fb5f2028438 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -633,7 +633,7 @@ static void fas216_updateptrs(FAS216_Info *info, int bytes_transferred)
BUG_ON(bytes_transferred < 0);
- info->SCpnt->request_bufflen -= bytes_transferred;
+ SCp->phase -= bytes_transferred;
while (bytes_transferred != 0) {
if (SCp->this_residual > bytes_transferred)
@@ -715,7 +715,7 @@ static void fas216_cleanuptransfer(FAS216_Info *info)
return;
if (dmatype == fasdma_real_all)
- total = info->SCpnt->request_bufflen;
+ total = info->scsi.SCp.phase;
else
total = info->scsi.SCp.this_residual;
@@ -753,7 +753,7 @@ static void fas216_transfer(FAS216_Info *info)
fas216_log(info, LOG_BUFFER,
"starttransfer: buffer %p length 0x%06x reqlen 0x%06x",
info->scsi.SCp.ptr, info->scsi.SCp.this_residual,
- info->SCpnt->request_bufflen);
+ info->scsi.SCp.phase);
if (!info->scsi.SCp.ptr) {
fas216_log(info, LOG_ERROR, "null buffer passed to "
@@ -784,7 +784,7 @@ static void fas216_transfer(FAS216_Info *info)
info->dma.transfer_type = dmatype;
if (dmatype == fasdma_real_all)
- fas216_set_stc(info, info->SCpnt->request_bufflen);
+ fas216_set_stc(info, info->scsi.SCp.phase);
else
fas216_set_stc(info, info->scsi.SCp.this_residual);
@@ -2114,6 +2114,7 @@ request_sense:
SCpnt->SCp.buffers_residual = 0;
SCpnt->SCp.ptr = (char *)SCpnt->sense_buffer;
SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer);
+ SCpnt->SCp.phase = sizeof(SCpnt->sense_buffer);
SCpnt->SCp.Message = 0;
SCpnt->SCp.Status = 0;
SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c
index f9cd20bfb95..159047a3499 100644
--- a/drivers/scsi/arm/powertec.c
+++ b/drivers/scsi/arm/powertec.c
@@ -148,10 +148,10 @@ powertecscsi_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp,
map_dir = DMA_FROM_DEVICE,
dma_dir = DMA_MODE_READ;
- dma_map_sg(dev, info->sg, bufs + 1, map_dir);
+ dma_map_sg(dev, info->sg, bufs, map_dir);
disable_dma(dmach);
- set_dma_sg(dmach, info->sg, bufs + 1);
+ set_dma_sg(dmach, info->sg, bufs);
set_dma_mode(dmach, dma_dir);
enable_dma(dmach);
return fasdma_real_all;
@@ -342,6 +342,7 @@ powertecscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
info->base = base;
powertecscsi_terminator_ctl(host, term[ec->slot_no]);
+ info->ec = ec;
info->info.scsi.io_base = base + POWERTEC_FAS216_OFFSET;
info->info.scsi.io_shift = POWERTEC_FAS216_SHIFT;
info->info.scsi.irq = ec->irq;
diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h
index 3a39579bd08..21ba57155be 100644
--- a/drivers/scsi/arm/scsi.h
+++ b/drivers/scsi/arm/scsi.h
@@ -80,6 +80,7 @@ static inline void init_SCp(struct scsi_cmnd *SCpnt)
(page_address(SCpnt->SCp.buffer->page) +
SCpnt->SCp.buffer->offset);
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
+ SCpnt->SCp.phase = SCpnt->request_bufflen;
#ifdef BELT_AND_BRACES
/*
@@ -98,6 +99,7 @@ static inline void init_SCp(struct scsi_cmnd *SCpnt)
} else {
SCpnt->SCp.ptr = (unsigned char *)SCpnt->request_buffer;
SCpnt->SCp.this_residual = SCpnt->request_bufflen;
+ SCpnt->SCp.phase = SCpnt->request_bufflen;
}
/*
diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c
index 587d87b9eb3..d31721f2744 100644
--- a/drivers/serial/dz.c
+++ b/drivers/serial/dz.c
@@ -170,8 +170,7 @@ static void dz_enable_ms(struct uart_port *port)
* This routine deals with inputs from any lines.
* ------------------------------------------------------------
*/
-static inline void dz_receive_chars(struct dz_port *dport_in,
- struct pt_regs *regs)
+static inline void dz_receive_chars(struct dz_port *dport_in)
{
struct dz_port *dport;
struct tty_struct *tty = NULL;
@@ -226,7 +225,7 @@ static inline void dz_receive_chars(struct dz_port *dport_in,
break;
}
- if (uart_handle_sysrq_char(&dport->port, ch, regs))
+ if (uart_handle_sysrq_char(&dport->port, ch))
continue;
if ((status & dport->port.ignore_status_mask) == 0) {
@@ -332,7 +331,7 @@ static irqreturn_t dz_interrupt(int irq, void *dev)
status = dz_in(dport, DZ_CSR);
if ((status & (DZ_RDONE | DZ_RIE)) == (DZ_RDONE | DZ_RIE))
- dz_receive_chars(dport, regs);
+ dz_receive_chars(dport);
if ((status & (DZ_TRDY | DZ_TIE)) == (DZ_TRDY | DZ_TIE))
dz_transmit_chars(dport);
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
index 08430961a89..99af084c7ce 100644
--- a/drivers/serial/mcfserial.c
+++ b/drivers/serial/mcfserial.c
@@ -425,15 +425,13 @@ irqreturn_t mcfrs_interrupt(int irq, void *dev_id)
* -------------------------------------------------------------------
*/
-static void mcfrs_offintr(void *private)
+static void mcfrs_offintr(struct work_struct *work)
{
- struct mcf_serial *info = (struct mcf_serial *) private;
- struct tty_struct *tty;
+ struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue);
+ struct tty_struct *tty = info->tty;
- tty = info->tty;
- if (!tty)
- return;
- tty_wakeup(tty);
+ if (tty)
+ tty_wakeup(tty);
}
@@ -497,16 +495,13 @@ static void mcfrs_timer(void)
* do_serial_hangup() -> tty->hangup() -> mcfrs_hangup()
*
*/
-static void do_serial_hangup(void *private)
+static void do_serial_hangup(struct work_struct *work)
{
- struct mcf_serial *info = (struct mcf_serial *) private;
- struct tty_struct *tty;
+ struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue_hangup);
+ struct tty_struct *tty = info->tty;
- tty = info->tty;
- if (!tty)
- return;
-
- tty_hangup(tty);
+ if (tty)
+ tty_hangup(tty);
}
static int startup(struct mcf_serial * info)
@@ -857,7 +852,7 @@ static void mcfrs_throttle(struct tty_struct * tty)
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
- printk("throttle %s: %d....\n", _tty_name(tty, buf),
+ printk("throttle %s: %d....\n", tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty));
#endif
@@ -876,7 +871,7 @@ static void mcfrs_unthrottle(struct tty_struct * tty)
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
- printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+ printk("unthrottle %s: %d....\n", tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty));
#endif
@@ -1541,8 +1536,8 @@ static void mcfrs_irqinit(struct mcf_serial *info)
* External Pin Mask Setting & Enable External Pin for Interface
* mrcbis@aliceposta.it
*/
- unsigned short *serpin_enable_mask;
- serpin_enable_mask = (MCF_IPSBAR + MCF_GPIO_PAR_UART);
+ u16 *serpin_enable_mask;
+ serpin_enable_mask = (u16 *) (MCF_IPSBAR + MCF_GPIO_PAR_UART);
if (info->line == 0)
*serpin_enable_mask |= UART0_ENABLE_MASK;
else if (info->line == 1)
@@ -1551,6 +1546,13 @@ static void mcfrs_irqinit(struct mcf_serial *info)
*serpin_enable_mask |= UART2_ENABLE_MASK;
}
#endif
+#if defined(CONFIG_M528x)
+ /* make sure PUAPAR is set for UART0 and UART1 */
+ if (info->line < 2) {
+ volatile unsigned char *portp = (volatile unsigned char *) (MCF_MBAR + MCF5282_GPIO_PUAPAR);
+ *portp |= (0x03 << (info->line * 2));
+ }
+#endif
#elif defined(CONFIG_M520x)
volatile unsigned char *icrp, *uartp;
volatile unsigned long *imrp;
@@ -1783,8 +1785,8 @@ mcfrs_init(void)
info->event = 0;
info->count = 0;
info->blocked_open = 0;
- INIT_WORK(&info->tqueue, mcfrs_offintr, info);
- INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info);
+ INIT_WORK(&info->tqueue, mcfrs_offintr);
+ INIT_WORK(&info->tqueue_hangup, do_serial_hangup);
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c
index ccb8fa1800a..83211013deb 100644
--- a/drivers/serial/mux.c
+++ b/drivers/serial/mux.c
@@ -51,7 +51,11 @@
#define MUX_NR 256
static unsigned int port_cnt __read_mostly;
-static struct uart_port mux_ports[MUX_NR];
+struct mux_port {
+ struct uart_port port;
+ int enabled;
+};
+static struct mux_port mux_ports[MUX_NR];
static struct uart_driver mux_driver = {
.owner = THIS_MODULE,
@@ -66,7 +70,36 @@ static struct timer_list mux_timer;
#define UART_PUT_CHAR(p, c) __raw_writel((c), (p)->membase + IO_DATA_REG_OFFSET)
#define UART_GET_FIFO_CNT(p) __raw_readl((p)->membase + IO_DCOUNT_REG_OFFSET)
-#define GET_MUX_PORTS(iodc_data) ((((iodc_data)[4] & 0xf0) >> 4) * 8) + 8
+
+/**
+ * get_mux_port_count - Get the number of available ports on the Mux.
+ * @dev: The parisc device.
+ *
+ * This function is used to determine the number of ports the Mux
+ * supports. The IODC data reports the number of ports the Mux
+ * can support, but there are cases where not all the Mux ports
+ * are connected. This function can override the IODC and
+ * return the true port count.
+ */
+static int __init get_mux_port_count(struct parisc_device *dev)
+{
+ int status;
+ u8 iodc_data[32];
+ unsigned long bytecnt;
+
+ /* If this is the built-in Mux for the K-Class (Eole CAP/MUX),
+ * we only need to allocate resources for 1 port since the
+ * other 7 ports are not connected.
+ */
+ if(dev->id.hversion == 0x15)
+ return 1;
+
+ status = pdc_iodc_read(&bytecnt, dev->hpa.start, 0, iodc_data, 32);
+ BUG_ON(status != PDC_OK);
+
+ /* Return the number of ports specified in the iodc data. */
+ return ((((iodc_data)[4] & 0xf0) >> 4) * 8) + 8;
+}
/**
* mux_tx_empty - Check if the transmitter fifo is empty.
@@ -250,7 +283,7 @@ static void mux_read(struct uart_port *port)
*/
static int mux_startup(struct uart_port *port)
{
- mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
+ mux_ports[port->line].enabled = 1;
return 0;
}
@@ -262,6 +295,7 @@ static int mux_startup(struct uart_port *port)
*/
static void mux_shutdown(struct uart_port *port)
{
+ mux_ports[port->line].enabled = 0;
}
/**
@@ -319,7 +353,7 @@ static int mux_request_port(struct uart_port *port)
* @port: Ptr to the uart_port.
* @type: Bitmask of required configurations.
*
- * Perform any autoconfiguration steps for the port. This functino is
+ * Perform any autoconfiguration steps for the port. This function is
* called if the UPF_BOOT_AUTOCONF flag is specified for the port.
* [Note: This is required for now because of a bug in the Serial core.
* rmk has already submitted a patch to linus, should be available for
@@ -357,11 +391,11 @@ static void mux_poll(unsigned long unused)
int i;
for(i = 0; i < port_cnt; ++i) {
- if(!mux_ports[i].info)
+ if(!mux_ports[i].enabled)
continue;
- mux_read(&mux_ports[i]);
- mux_write(&mux_ports[i]);
+ mux_read(&mux_ports[i].port);
+ mux_write(&mux_ports[i].port);
}
mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
@@ -371,8 +405,17 @@ static void mux_poll(unsigned long unused)
#ifdef CONFIG_SERIAL_MUX_CONSOLE
static void mux_console_write(struct console *co, const char *s, unsigned count)
{
- while(count--)
- pdc_iodc_putc(*s++);
+ /* Wait until the FIFO drains. */
+ while(UART_GET_FIFO_CNT(&mux_ports[0].port))
+ udelay(1);
+
+ while(count--) {
+ if(*s == '\n') {
+ UART_PUT_CHAR(&mux_ports[0].port, '\r');
+ }
+ UART_PUT_CHAR(&mux_ports[0].port, *s++);
+ }
+
}
static int mux_console_setup(struct console *co, char *options)
@@ -428,19 +471,14 @@ static struct uart_ops mux_pops = {
*/
static int __init mux_probe(struct parisc_device *dev)
{
- int i, status, ports;
- u8 iodc_data[32];
- unsigned long bytecnt;
- struct uart_port *port;
+ int i, status;
- status = pdc_iodc_read(&bytecnt, dev->hpa.start, 0, iodc_data, 32);
- if(status != PDC_OK) {
- printk(KERN_ERR "Serial mux: Unable to read IODC.\n");
- return 1;
- }
+ int port_count = get_mux_port_count(dev);
+ printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.6\n", port_count);
- ports = GET_MUX_PORTS(iodc_data);
- printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.3\n", ports);
+ dev_set_drvdata(&dev->dev, (void *)(long)port_count);
+ request_mem_region(dev->hpa.start + MUX_OFFSET,
+ port_count * MUX_LINE_OFFSET, "Mux");
if(!port_cnt) {
mux_driver.cons = MUX_CONSOLE;
@@ -450,13 +488,10 @@ static int __init mux_probe(struct parisc_device *dev)
printk(KERN_ERR "Serial mux: Unable to register driver.\n");
return 1;
}
-
- init_timer(&mux_timer);
- mux_timer.function = mux_poll;
}
- for(i = 0; i < ports; ++i, ++port_cnt) {
- port = &mux_ports[port_cnt];
+ for(i = 0; i < port_count; ++i, ++port_cnt) {
+ struct uart_port *port = &mux_ports[port_cnt].port;
port->iobase = 0;
port->mapbase = dev->hpa.start + MUX_OFFSET +
(i * MUX_LINE_OFFSET);
@@ -477,27 +512,73 @@ static int __init mux_probe(struct parisc_device *dev)
*/
port->timeout = HZ / 50;
spin_lock_init(&port->lock);
+
status = uart_add_one_port(&mux_driver, port);
BUG_ON(status);
}
-#ifdef CONFIG_SERIAL_MUX_CONSOLE
- register_console(&mux_console);
-#endif
return 0;
}
+static int __devexit mux_remove(struct parisc_device *dev)
+{
+ int i, j;
+ int port_count = (long)dev_get_drvdata(&dev->dev);
+
+ /* Find Port 0 for this card in the mux_ports list. */
+ for(i = 0; i < port_cnt; ++i) {
+ if(mux_ports[i].port.mapbase == dev->hpa.start + MUX_OFFSET)
+ break;
+ }
+ BUG_ON(i + port_count > port_cnt);
+
+ /* Release the resources associated with each port on the device. */
+ for(j = 0; j < port_count; ++j, ++i) {
+ struct uart_port *port = &mux_ports[i].port;
+
+ uart_remove_one_port(&mux_driver, port);
+ if(port->membase)
+ iounmap(port->membase);
+ }
+
+ release_mem_region(dev->hpa.start + MUX_OFFSET, port_count * MUX_LINE_OFFSET);
+ return 0;
+}
+
+/* Hack. This idea was taken from the 8250_gsc.c on how to properly order
+ * the serial port detection in the proper order. The idea is we always
+ * want the builtin mux to be detected before addin mux cards, so we
+ * specifically probe for the builtin mux cards first.
+ *
+ * This table only contains the parisc_device_id of known builtin mux
+ * devices. All other mux cards will be detected by the generic mux_tbl.
+ */
+static struct parisc_device_id builtin_mux_tbl[] = {
+ { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x15, 0x0000D }, /* All K-class */
+ { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x44, 0x0000D }, /* E35, E45, and E55 */
+ { 0, }
+};
+
static struct parisc_device_id mux_tbl[] = {
{ HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D },
{ 0, }
};
+MODULE_DEVICE_TABLE(parisc, builtin_mux_tbl);
MODULE_DEVICE_TABLE(parisc, mux_tbl);
+static struct parisc_driver builtin_serial_mux_driver = {
+ .name = "builtin_serial_mux",
+ .id_table = builtin_mux_tbl,
+ .probe = mux_probe,
+ .remove = __devexit_p(mux_remove),
+};
+
static struct parisc_driver serial_mux_driver = {
.name = "serial_mux",
.id_table = mux_tbl,
.probe = mux_probe,
+ .remove = __devexit_p(mux_remove),
};
/**
@@ -507,7 +588,21 @@ static struct parisc_driver serial_mux_driver = {
*/
static int __init mux_init(void)
{
- return register_parisc_driver(&serial_mux_driver);
+ register_parisc_driver(&builtin_serial_mux_driver);
+ register_parisc_driver(&serial_mux_driver);
+
+ if(port_cnt > 0) {
+ /* Start the Mux timer */
+ init_timer(&mux_timer);
+ mux_timer.function = mux_poll;
+ mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY);
+
+#ifdef CONFIG_SERIAL_MUX_CONSOLE
+ register_console(&mux_console);
+#endif
+ }
+
+ return 0;
}
/**
@@ -517,14 +612,16 @@ static int __init mux_init(void)
*/
static void __exit mux_exit(void)
{
- int i;
-
- for (i = 0; i < port_cnt; i++) {
- uart_remove_one_port(&mux_driver, &mux_ports[i]);
- if (mux_ports[i].membase)
- iounmap(mux_ports[i].membase);
+ /* Delete the Mux timer. */
+ if(port_cnt > 0) {
+ del_timer(&mux_timer);
+#ifdef CONFIG_SERIAL_MUX_CONSOLE
+ unregister_console(&mux_console);
+#endif
}
+ unregister_parisc_driver(&builtin_serial_mux_driver);
+ unregister_parisc_driver(&serial_mux_driver);
uart_unregister_driver(&mux_driver);
}
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index f4440d32931..509ace7e688 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -38,6 +38,8 @@
* Fix some spin_locks.
* Do not call uart_add_one_port for absent ports.
* 1.07 Use CONFIG_SERIAL_TXX9_NR_UARTS. Cleanup.
+ * 1.08 Use platform_device.
+ * Fix and cleanup suspend/resume/initialization codes.
*/
#if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
@@ -50,7 +52,7 @@
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/delay.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
#include <linux/pci.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -60,7 +62,7 @@
#include <asm/io.h>
-static char *serial_version = "1.07";
+static char *serial_version = "1.08";
static char *serial_name = "TX39/49 Serial driver";
#define PASS_LIMIT 256
@@ -94,12 +96,7 @@ static char *serial_name = "TX39/49 Serial driver";
struct uart_txx9_port {
struct uart_port port;
-
- /*
- * We provide a per-port pm hook.
- */
- void (*pm)(struct uart_port *port,
- unsigned int state, unsigned int old);
+ /* No additional info for now */
};
#define TXX9_REGION_SIZE 0x24
@@ -277,6 +274,31 @@ static void serial_txx9_enable_ms(struct uart_port *port)
/* TXX9-SIO can not control DTR... */
}
+static void serial_txx9_initialize(struct uart_port *port)
+{
+ struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+ unsigned int tmout = 10000;
+
+ sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST);
+ /* TX4925 BUG WORKAROUND. Accessing SIOC register
+ * immediately after soft reset causes bus error. */
+ mmiowb();
+ udelay(1);
+ while ((sio_in(up, TXX9_SIFCR) & TXX9_SIFCR_SWRST) && --tmout)
+ udelay(1);
+ /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */
+ sio_set(up, TXX9_SIFCR,
+ TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1);
+ /* initial settings */
+ sio_out(up, TXX9_SILCR,
+ TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT |
+ ((up->port.flags & UPF_TXX9_USE_SCLK) ?
+ TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG));
+ sio_quot_set(up, uart_get_divisor(port, 9600));
+ sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */);
+ sio_out(up, TXX9_SIDICR, 0);
+}
+
static inline void
receive_chars(struct uart_txx9_port *up, unsigned int *status)
{
@@ -657,9 +679,8 @@ static void
serial_txx9_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
- struct uart_txx9_port *up = (struct uart_txx9_port *)port;
- if (up->pm)
- up->pm(port, state, oldstate);
+ if (state == 0)
+ serial_txx9_initialize(port);
}
static int serial_txx9_request_resource(struct uart_txx9_port *up)
@@ -732,7 +753,6 @@ static int serial_txx9_request_port(struct uart_port *port)
static void serial_txx9_config_port(struct uart_port *port, int uflags)
{
struct uart_txx9_port *up = (struct uart_txx9_port *)port;
- unsigned long flags;
int ret;
/*
@@ -749,30 +769,7 @@ static void serial_txx9_config_port(struct uart_port *port, int uflags)
if (up->port.line == up->port.cons->index)
return;
#endif
- spin_lock_irqsave(&up->port.lock, flags);
- /*
- * Reset the UART.
- */
- sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST);
-#ifdef CONFIG_CPU_TX49XX
- /* TX4925 BUG WORKAROUND. Accessing SIOC register
- * immediately after soft reset causes bus error. */
- iob();
- udelay(1);
-#endif
- while (sio_in(up, TXX9_SIFCR) & TXX9_SIFCR_SWRST)
- ;
- /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */
- sio_set(up, TXX9_SIFCR,
- TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1);
- /* initial settings */
- sio_out(up, TXX9_SILCR,
- TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT |
- ((up->port.flags & UPF_TXX9_USE_SCLK) ?
- TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG));
- sio_quot_set(up, uart_get_divisor(port, 9600));
- sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */);
- spin_unlock_irqrestore(&up->port.lock, flags);
+ serial_txx9_initialize(port);
}
static int
@@ -818,7 +815,8 @@ static struct uart_ops serial_txx9_pops = {
static struct uart_txx9_port serial_txx9_ports[UART_NR];
-static void __init serial_txx9_register_ports(struct uart_driver *drv)
+static void __init serial_txx9_register_ports(struct uart_driver *drv,
+ struct device *dev)
{
int i;
@@ -827,6 +825,7 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv)
up->port.line = i;
up->port.ops = &serial_txx9_pops;
+ up->port.dev = dev;
if (up->port.iobase || up->port.mapbase)
uart_add_one_port(drv, &up->port);
}
@@ -898,7 +897,7 @@ serial_txx9_console_write(struct console *co, const char *s, unsigned int count)
sio_out(up, TXX9_SIDICR, ier);
}
-static int serial_txx9_console_setup(struct console *co, char *options)
+static int __init serial_txx9_console_setup(struct console *co, char *options)
{
struct uart_port *port;
struct uart_txx9_port *up;
@@ -919,17 +918,7 @@ static int serial_txx9_console_setup(struct console *co, char *options)
if (!port->ops)
return -ENODEV;
- /*
- * Disable UART interrupts, set DTR and RTS high
- * and set speed.
- */
- sio_out(up, TXX9_SIDICR, 0);
- /* initial settings */
- sio_out(up, TXX9_SILCR,
- TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT |
- ((port->flags & UPF_TXX9_USE_SCLK) ?
- TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG));
- sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */);
+ serial_txx9_initialize(&up->port);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -981,31 +970,6 @@ int __init early_serial_txx9_setup(struct uart_port *port)
return 0;
}
-#ifdef ENABLE_SERIAL_TXX9_PCI
-#ifdef CONFIG_PM
-/**
- * serial_txx9_suspend_port - suspend one serial port
- * @line: serial line number
- *
- * Suspend one serial port.
- */
-static void serial_txx9_suspend_port(int line)
-{
- uart_suspend_port(&serial_txx9_reg, &serial_txx9_ports[line].port);
-}
-
-/**
- * serial_txx9_resume_port - resume one serial port
- * @line: serial line number
- *
- * Resume one serial port.
- */
-static void serial_txx9_resume_port(int line)
-{
- uart_resume_port(&serial_txx9_reg, &serial_txx9_ports[line].port);
-}
-#endif
-
static DEFINE_MUTEX(serial_txx9_mutex);
/**
@@ -1028,8 +992,18 @@ static int __devinit serial_txx9_register_port(struct uart_port *port)
mutex_lock(&serial_txx9_mutex);
for (i = 0; i < UART_NR; i++) {
uart = &serial_txx9_ports[i];
- if (!(uart->port.iobase || uart->port.mapbase))
+ if (uart_match_port(&uart->port, port)) {
+ uart_remove_one_port(&serial_txx9_reg, &uart->port);
break;
+ }
+ }
+ if (i == UART_NR) {
+ /* Find unused port */
+ for (i = 0; i < UART_NR; i++) {
+ uart = &serial_txx9_ports[i];
+ if (!(uart->port.iobase || uart->port.mapbase))
+ break;
+ }
}
if (i < UART_NR) {
uart->port.iobase = port->iobase;
@@ -1072,6 +1046,95 @@ static void __devexit serial_txx9_unregister_port(int line)
}
/*
+ * Register a set of serial devices attached to a platform device.
+ */
+static int __devinit serial_txx9_probe(struct platform_device *dev)
+{
+ struct uart_port *p = dev->dev.platform_data;
+ struct uart_port port;
+ int ret, i;
+
+ memset(&port, 0, sizeof(struct uart_port));
+ for (i = 0; p && p->uartclk != 0; p++, i++) {
+ port.iobase = p->iobase;
+ port.membase = p->membase;
+ port.irq = p->irq;
+ port.uartclk = p->uartclk;
+ port.iotype = p->iotype;
+ port.flags = p->flags;
+ port.mapbase = p->mapbase;
+ port.dev = &dev->dev;
+ ret = serial_txx9_register_port(&port);
+ if (ret < 0) {
+ dev_err(&dev->dev, "unable to register port at index %d "
+ "(IO%x MEM%lx IRQ%d): %d\n", i,
+ p->iobase, p->mapbase, p->irq, ret);
+ }
+ }
+ return 0;
+}
+
+/*
+ * Remove serial ports registered against a platform device.
+ */
+static int __devexit serial_txx9_remove(struct platform_device *dev)
+{
+ int i;
+
+ for (i = 0; i < UART_NR; i++) {
+ struct uart_txx9_port *up = &serial_txx9_ports[i];
+
+ if (up->port.dev == &dev->dev)
+ serial_txx9_unregister_port(i);
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int serial_txx9_suspend(struct platform_device *dev, pm_message_t state)
+{
+ int i;
+
+ for (i = 0; i < UART_NR; i++) {
+ struct uart_txx9_port *up = &serial_txx9_ports[i];
+
+ if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
+ uart_suspend_port(&serial_txx9_reg, &up->port);
+ }
+
+ return 0;
+}
+
+static int serial_txx9_resume(struct platform_device *dev)
+{
+ int i;
+
+ for (i = 0; i < UART_NR; i++) {
+ struct uart_txx9_port *up = &serial_txx9_ports[i];
+
+ if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
+ uart_resume_port(&serial_txx9_reg, &up->port);
+ }
+
+ return 0;
+}
+#endif
+
+static struct platform_driver serial_txx9_plat_driver = {
+ .probe = serial_txx9_probe,
+ .remove = __devexit_p(serial_txx9_remove),
+#ifdef CONFIG_PM
+ .suspend = serial_txx9_suspend,
+ .resume = serial_txx9_resume,
+#endif
+ .driver = {
+ .name = "serial_txx9",
+ .owner = THIS_MODULE,
+ },
+};
+
+#ifdef ENABLE_SERIAL_TXX9_PCI
+/*
* Probe one serial board. Unfortunately, there is no rhyme nor reason
* to the arrangement of serial ports on a PCI card.
*/
@@ -1097,20 +1160,22 @@ pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
line = serial_txx9_register_port(&port);
if (line < 0) {
printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), line);
+ pci_disable_device(dev);
+ return line;
}
- pci_set_drvdata(dev, (void *)(long)line);
+ pci_set_drvdata(dev, &serial_txx9_ports[line]);
return 0;
}
static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev)
{
- int line = (int)(long)pci_get_drvdata(dev);
+ struct uart_txx9_port *up = pci_get_drvdata(dev);
pci_set_drvdata(dev, NULL);
- if (line) {
- serial_txx9_unregister_port(line);
+ if (up) {
+ serial_txx9_unregister_port(up->port.line);
pci_disable_device(dev);
}
}
@@ -1118,10 +1183,10 @@ static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev)
#ifdef CONFIG_PM
static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state)
{
- int line = (int)(long)pci_get_drvdata(dev);
+ struct uart_txx9_port *up = pci_get_drvdata(dev);
- if (line)
- serial_txx9_suspend_port(line);
+ if (up)
+ uart_suspend_port(&serial_txx9_reg, &up->port);
pci_save_state(dev);
pci_set_power_state(dev, pci_choose_state(dev, state));
return 0;
@@ -1129,15 +1194,12 @@ static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state)
static int pciserial_txx9_resume_one(struct pci_dev *dev)
{
- int line = (int)(long)pci_get_drvdata(dev);
+ struct uart_txx9_port *up = pci_get_drvdata(dev);
pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev);
-
- if (line) {
- pci_enable_device(dev);
- serial_txx9_resume_port(line);
- }
+ if (up)
+ uart_resume_port(&serial_txx9_reg, &up->port);
return 0;
}
#endif
@@ -1161,6 +1223,8 @@ static struct pci_driver serial_txx9_pci_driver = {
MODULE_DEVICE_TABLE(pci, serial_txx9_pci_tbl);
#endif /* ENABLE_SERIAL_TXX9_PCI */
+static struct platform_device *serial_txx9_plat_devs;
+
static int __init serial_txx9_init(void)
{
int ret;
@@ -1168,13 +1232,39 @@ static int __init serial_txx9_init(void)
printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
ret = uart_register_driver(&serial_txx9_reg);
- if (ret >= 0) {
- serial_txx9_register_ports(&serial_txx9_reg);
+ if (ret)
+ goto out;
+
+ serial_txx9_plat_devs = platform_device_alloc("serial_txx9", -1);
+ if (!serial_txx9_plat_devs) {
+ ret = -ENOMEM;
+ goto unreg_uart_drv;
+ }
+
+ ret = platform_device_add(serial_txx9_plat_devs);
+ if (ret)
+ goto put_dev;
+
+ serial_txx9_register_ports(&serial_txx9_reg,
+ &serial_txx9_plat_devs->dev);
+
+ ret = platform_driver_register(&serial_txx9_plat_driver);
+ if (ret)
+ goto del_dev;
#ifdef ENABLE_SERIAL_TXX9_PCI
- ret = pci_register_driver(&serial_txx9_pci_driver);
+ ret = pci_register_driver(&serial_txx9_pci_driver);
#endif
- }
+ if (ret == 0)
+ goto out;
+
+ del_dev:
+ platform_device_del(serial_txx9_plat_devs);
+ put_dev:
+ platform_device_put(serial_txx9_plat_devs);
+ unreg_uart_drv:
+ uart_unregister_driver(&serial_txx9_reg);
+ out:
return ret;
}
@@ -1185,6 +1275,8 @@ static void __exit serial_txx9_exit(void)
#ifdef ENABLE_SERIAL_TXX9_PCI
pci_unregister_driver(&serial_txx9_pci_driver);
#endif
+ platform_driver_unregister(&serial_txx9_plat_driver);
+ platform_device_unregister(serial_txx9_plat_devs);
for (i = 0; i < UART_NR; i++) {
struct uart_txx9_port *up = &serial_txx9_ports[i];
if (up->port.iobase || up->port.mapbase)
diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
index 253ceb895ca..a27e9e92cb5 100644
--- a/drivers/serial/sn_console.c
+++ b/drivers/serial/sn_console.c
@@ -636,25 +636,6 @@ static irqreturn_t sn_sal_interrupt(int irq, void *dev_id)
}
/**
- * sn_sal_connect_interrupt - Request interrupt, handled by sn_sal_interrupt
- * @port: Our sn_cons_port (which contains the uart port)
- *
- * returns the console irq if interrupt is successfully registered, else 0
- *
- */
-static int sn_sal_connect_interrupt(struct sn_cons_port *port)
-{
- if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt,
- IRQF_DISABLED | IRQF_SHARED,
- "SAL console driver", port) >= 0) {
- return SGI_UART_VECTOR;
- }
-
- printk(KERN_INFO "sn_console: console proceeding in polled mode\n");
- return 0;
-}
-
-/**
* sn_sal_timer_poll - this function handles polled console mode
* @data: A pointer to our sn_cons_port (which contains the uart port)
*
@@ -746,30 +727,31 @@ static void __init sn_sal_switch_to_asynch(struct sn_cons_port *port)
* mode. We were previously in asynch/polling mode (using init_timer).
*
* We attempt to switch to interrupt mode here by calling
- * sn_sal_connect_interrupt. If that works out, we enable receive interrupts.
+ * request_irq. If that works out, we enable receive interrupts.
*/
static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port)
{
- int irq;
unsigned long flags;
- if (!port)
- return;
-
- DPRINTF("sn_console: switching to interrupt driven console\n");
-
- spin_lock_irqsave(&port->sc_port.lock, flags);
+ if (port) {
+ DPRINTF("sn_console: switching to interrupt driven console\n");
- irq = sn_sal_connect_interrupt(port);
+ if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt,
+ IRQF_DISABLED | IRQF_SHARED,
+ "SAL console driver", port) >= 0) {
+ spin_lock_irqsave(&port->sc_port.lock, flags);
+ port->sc_port.irq = SGI_UART_VECTOR;
+ port->sc_ops = &intr_ops;
- if (irq) {
- port->sc_port.irq = irq;
- port->sc_ops = &intr_ops;
-
- /* turn on receive interrupts */
- ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV);
+ /* turn on receive interrupts */
+ ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV);
+ spin_unlock_irqrestore(&port->sc_port.lock, flags);
+ }
+ else {
+ printk(KERN_INFO
+ "sn_console: console proceeding in polled mode\n");
+ }
}
- spin_unlock_irqrestore(&port->sc_port.lock, flags);
}
/*
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index 34e9bac319b..b6078706fb9 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -4,7 +4,7 @@
usbcore-objs := usb.o hub.o hcd.o urb.o message.o driver.o \
config.o file.o buffer.o sysfs.o endpoint.o \
- devio.o notify.o generic.o
+ devio.o notify.o generic.o quirks.o
ifeq ($(CONFIG_PCI),y)
usbcore-objs += hcd-pci.o
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 2aded261f42..9e3e943f313 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -366,19 +366,8 @@ void usb_driver_release_interface(struct usb_driver *driver,
EXPORT_SYMBOL(usb_driver_release_interface);
/* returns 0 if no match, 1 if match */
-int usb_match_one_id(struct usb_interface *interface,
- const struct usb_device_id *id)
+int usb_match_device(struct usb_device *dev, const struct usb_device_id *id)
{
- struct usb_host_interface *intf;
- struct usb_device *dev;
-
- /* proc_connectinfo in devio.c may call us with id == NULL. */
- if (id == NULL)
- return 0;
-
- intf = interface->cur_altsetting;
- dev = interface_to_usbdev(interface);
-
if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
return 0;
@@ -409,6 +398,26 @@ int usb_match_one_id(struct usb_interface *interface,
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
return 0;
+ return 1;
+}
+
+/* returns 0 if no match, 1 if match */
+int usb_match_one_id(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_host_interface *intf;
+ struct usb_device *dev;
+
+ /* proc_connectinfo in devio.c may call us with id == NULL. */
+ if (id == NULL)
+ return 0;
+
+ intf = interface->cur_altsetting;
+ dev = interface_to_usbdev(interface);
+
+ if (!usb_match_device(dev, id))
+ return 0;
+
/* The interface class, subclass, and protocol should never be
* checked for a match if the device class is Vendor Specific,
* unless the match record specifies the Vendor ID. */
@@ -954,12 +963,16 @@ static int autosuspend_check(struct usb_device *udev)
int i;
struct usb_interface *intf;
- /* For autosuspend, fail fast if anything is in use.
- * Also fail if any interfaces require remote wakeup but it
- * isn't available. */
+ /* For autosuspend, fail fast if anything is in use or autosuspend
+ * is disabled. Also fail if any interfaces require remote wakeup
+ * but it isn't available.
+ */
udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
if (udev->pm_usage_cnt > 0)
return -EBUSY;
+ if (!udev->autosuspend_delay)
+ return -EPERM;
+
if (udev->actconfig) {
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
intf = udev->actconfig->interface[i];
@@ -982,7 +995,7 @@ static int autosuspend_check(struct usb_device *udev)
#define autosuspend_check(udev) 0
-#endif
+#endif /* CONFIG_USB_SUSPEND */
/**
* usb_suspend_both - suspend a USB device and its interfaces
@@ -1177,7 +1190,7 @@ static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt)
udev->pm_usage_cnt -= inc_usage_cnt;
} else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0)
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
- USB_AUTOSUSPEND_DELAY);
+ udev->autosuspend_delay);
usb_pm_unlock(udev);
return status;
}
@@ -1212,6 +1225,26 @@ void usb_autosuspend_device(struct usb_device *udev)
}
/**
+ * usb_try_autosuspend_device - attempt an autosuspend of a USB device and its interfaces
+ * @udev: the usb_device to autosuspend
+ *
+ * This routine should be called when a core subsystem thinks @udev may
+ * be ready to autosuspend.
+ *
+ * @udev's usage counter left unchanged. If it or any of the usage counters
+ * for an active interface is greater than 0, or autosuspend is not allowed
+ * for any other reason, no autosuspend request will be queued.
+ *
+ * This routine can run only in process context.
+ */
+void usb_try_autosuspend_device(struct usb_device *udev)
+{
+ usb_autopm_do_device(udev, 0);
+ // dev_dbg(&udev->dev, "%s: cnt %d\n",
+ // __FUNCTION__, udev->pm_usage_cnt);
+}
+
+/**
* usb_autoresume_device - immediately autoresume a USB device and its interfaces
* @udev: the usb_device to autoresume
*
@@ -1261,7 +1294,7 @@ static int usb_autopm_do_interface(struct usb_interface *intf,
intf->pm_usage_cnt -= inc_usage_cnt;
} else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0)
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
- USB_AUTOSUSPEND_DELAY);
+ udev->autosuspend_delay);
}
usb_pm_unlock(udev);
return status;
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 50c0db15304..41400743ce2 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1287,6 +1287,9 @@ int usb_new_device(struct usb_device *udev)
if (!try_module_get(THIS_MODULE))
return -EINVAL;
+ /* Determine quirks */
+ usb_detect_quirks(udev);
+
err = usb_get_configuration(udev);
if (err < 0) {
dev_err(&udev->dev, "can't read configurations, error %d\n",
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 74edaea5665..2f17468b5c1 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -11,6 +11,7 @@
#include <linux/timer.h>
#include <linux/ctype.h>
#include <linux/device.h>
+#include <linux/usb/quirks.h>
#include <asm/byteorder.h>
#include <asm/scatterlist.h>
@@ -685,7 +686,10 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid,
/* Try to read the string descriptor by asking for the maximum
* possible number of bytes */
- rc = usb_get_string(dev, langid, index, buf, 255);
+ if (dev->quirks & USB_QUIRK_STRING_FETCH_255)
+ rc = -EIO;
+ else
+ rc = usb_get_string(dev, langid, index, buf, 255);
/* If that failed try to read the descriptor length, then
* ask for just that many bytes */
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
new file mode 100644
index 00000000000..0e5c646cb4f
--- /dev/null
+++ b/drivers/usb/core/quirks.c
@@ -0,0 +1,77 @@
+/*
+ * USB device quirk handling logic and table
+ *
+ * Copyright (c) 2007 Oliver Neukum
+ * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/usb/quirks.h>
+#include "usb.h"
+
+/* List of quirky USB devices. Please keep this list ordered by:
+ * 1) Vendor ID
+ * 2) Product ID
+ * 3) Class ID
+ *
+ * as we want specific devices to be overridden first, and only after that, any
+ * class specific quirks.
+ *
+ * Right now the logic aborts if it finds a valid device in the table, we might
+ * want to change that in the future if it turns out that a whole class of
+ * devices is broken...
+ */
+static const struct usb_device_id usb_quirk_list[] = {
+ /* HP 5300/5370C scanner */
+ { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
+
+ /* Elsa MicroLink 56k (V.250) */
+ { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
+ { } /* terminating entry must be last */
+};
+
+static void usb_autosuspend_quirk(struct usb_device *udev)
+{
+#ifdef CONFIG_USB_SUSPEND
+ /* disable autosuspend, but allow the user to re-enable it via sysfs */
+ udev->autosuspend_delay = 0;
+#endif
+}
+
+static const struct usb_device_id *find_id(struct usb_device *udev)
+{
+ const struct usb_device_id *id = usb_quirk_list;
+
+ for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
+ id->driver_info; id++) {
+ if (usb_match_device(udev, id))
+ return id;
+ }
+ return NULL;
+}
+
+/*
+ * Detect any quirks the device has, and do any housekeeping for it if needed.
+ */
+void usb_detect_quirks(struct usb_device *udev)
+{
+ const struct usb_device_id *id = usb_quirk_list;
+
+ id = find_id(udev);
+ if (id)
+ udev->quirks = (u32)(id->driver_info);
+ if (udev->quirks)
+ dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
+ udev->quirks);
+
+ /* do any special quirk handling here if needed */
+ if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND)
+ usb_autosuspend_quirk(udev);
+}
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 0edfbafd702..311d5df8038 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -148,6 +148,75 @@ show_maxchild(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
+static ssize_t
+show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev;
+
+ udev = to_usb_device(dev);
+ return sprintf(buf, "0x%x\n", udev->quirks);
+}
+static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
+
+#ifdef CONFIG_USB_SUSPEND
+
+static ssize_t
+show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+
+ return sprintf(buf, "%u\n", udev->autosuspend_delay / HZ);
+}
+
+static ssize_t
+set_autosuspend(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ unsigned value, old;
+
+ if (sscanf(buf, "%u", &value) != 1 || value >= INT_MAX/HZ)
+ return -EINVAL;
+ value *= HZ;
+
+ old = udev->autosuspend_delay;
+ udev->autosuspend_delay = value;
+ if (value > 0 && old == 0)
+ usb_try_autosuspend_device(udev);
+
+ return count;
+}
+
+static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR,
+ show_autosuspend, set_autosuspend);
+
+static char power_group[] = "power";
+
+static int add_power_attributes(struct device *dev)
+{
+ int rc = 0;
+
+ if (is_usb_device(dev))
+ rc = sysfs_add_file_to_group(&dev->kobj,
+ &dev_attr_autosuspend.attr,
+ power_group);
+ return rc;
+}
+
+static void remove_power_attributes(struct device *dev)
+{
+ sysfs_remove_file_from_group(&dev->kobj,
+ &dev_attr_autosuspend.attr,
+ power_group);
+}
+
+#else
+
+#define add_power_attributes(dev) 0
+#define remove_power_attributes(dev) do {} while (0)
+
+#endif /* CONFIG_USB_SUSPEND */
+
/* Descriptor fields */
#define usb_descriptor_attr_le16(field, format_string) \
static ssize_t \
@@ -204,6 +273,7 @@ static struct attribute *dev_attrs[] = {
&dev_attr_devnum.attr,
&dev_attr_version.attr,
&dev_attr_maxchild.attr,
+ &dev_attr_quirks.attr,
NULL,
};
static struct attribute_group dev_attr_grp = {
@@ -219,6 +289,10 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
if (retval)
return retval;
+ retval = add_power_attributes(dev);
+ if (retval)
+ goto error;
+
if (udev->manufacturer) {
retval = device_create_file(dev, &dev_attr_manufacturer);
if (retval)
@@ -239,10 +313,7 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
goto error;
return 0;
error:
- usb_remove_ep_files(&udev->ep0);
- device_remove_file(dev, &dev_attr_manufacturer);
- device_remove_file(dev, &dev_attr_product);
- device_remove_file(dev, &dev_attr_serial);
+ usb_remove_sysfs_dev_files(udev);
return retval;
}
@@ -251,14 +322,11 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
struct device *dev = &udev->dev;
usb_remove_ep_files(&udev->ep0);
+ device_remove_file(dev, &dev_attr_manufacturer);
+ device_remove_file(dev, &dev_attr_product);
+ device_remove_file(dev, &dev_attr_serial);
+ remove_power_attributes(dev);
sysfs_remove_group(&dev->kobj, &dev_attr_grp);
-
- if (udev->manufacturer)
- device_remove_file(dev, &dev_attr_manufacturer);
- if (udev->product)
- device_remove_file(dev, &dev_attr_product);
- if (udev->serial)
- device_remove_file(dev, &dev_attr_serial);
}
/* Interface fields */
@@ -362,33 +430,28 @@ static inline void usb_remove_intf_ep_files(struct usb_interface *intf)
int usb_create_sysfs_intf_files(struct usb_interface *intf)
{
+ struct device *dev = &intf->dev;
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_host_interface *alt = intf->cur_altsetting;
int retval;
- retval = sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
+ retval = sysfs_create_group(&dev->kobj, &intf_attr_grp);
if (retval)
- goto error;
+ return retval;
if (alt->string == NULL)
alt->string = usb_cache_string(udev, alt->desc.iInterface);
if (alt->string)
- retval = device_create_file(&intf->dev, &dev_attr_interface);
+ retval = device_create_file(dev, &dev_attr_interface);
usb_create_intf_ep_files(intf, udev);
return 0;
-error:
- if (alt->string)
- device_remove_file(&intf->dev, &dev_attr_interface);
- sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
- usb_remove_intf_ep_files(intf);
- return retval;
}
void usb_remove_sysfs_intf_files(struct usb_interface *intf)
{
- usb_remove_intf_ep_files(intf);
- sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
+ struct device *dev = &intf->dev;
- if (intf->cur_altsetting->string)
- device_remove_file(&intf->dev, &dev_attr_interface);
+ usb_remove_intf_ep_files(intf);
+ device_remove_file(dev, &dev_attr_interface);
+ sysfs_remove_group(&dev->kobj, &intf_attr_grp);
}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 3db721cd557..54b42ce311c 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -22,6 +22,7 @@
*/
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/bitops.h>
#include <linux/slab.h>
@@ -50,6 +51,16 @@ static int nousb; /* Disable USB when built into kernel image */
struct workqueue_struct *ksuspend_usb_wq; /* For autosuspend */
+#ifdef CONFIG_USB_SUSPEND
+static int usb_autosuspend_delay = 2; /* Default delay value,
+ * in seconds */
+module_param_named(autosuspend, usb_autosuspend_delay, uint, 0644);
+MODULE_PARM_DESC(autosuspend, "default autosuspend delay");
+
+#else
+#define usb_autosuspend_delay 0
+#endif
+
/**
* usb_ifnum_to_if - get the interface object with a given interface number
@@ -306,6 +317,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
#ifdef CONFIG_PM
mutex_init(&dev->pm_mutex);
INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
+ dev->autosuspend_delay = usb_autosuspend_delay * HZ;
#endif
return dev;
}
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 17830a81be1..08b5a04e375 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -13,6 +13,7 @@ extern void usb_disable_interface (struct usb_device *dev,
struct usb_interface *intf);
extern void usb_release_interface_cache(struct kref *ref);
extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
+extern void usb_detect_quirks(struct usb_device *udev);
extern int usb_get_device_descriptor(struct usb_device *dev,
unsigned int size);
@@ -21,6 +22,8 @@ extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern void usb_kick_khubd(struct usb_device *dev);
extern void usb_resume_root_hub(struct usb_device *dev);
+extern int usb_match_device(struct usb_device *dev,
+ const struct usb_device_id *id);
extern int usb_hub_init(void);
extern void usb_hub_cleanup(void);
@@ -62,14 +65,14 @@ static inline void usb_pm_unlock(struct usb_device *udev) {}
#ifdef CONFIG_USB_SUSPEND
-#define USB_AUTOSUSPEND_DELAY (HZ*2)
-
extern void usb_autosuspend_device(struct usb_device *udev);
+extern void usb_try_autosuspend_device(struct usb_device *udev);
extern int usb_autoresume_device(struct usb_device *udev);
#else
-#define usb_autosuspend_device(udev) do {} while (0)
+#define usb_autosuspend_device(udev) do {} while (0)
+#define usb_try_autosuspend_device(udev) do {} while (0)
static inline int usb_autoresume_device(struct usb_device *udev)
{
return 0;
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 34296e79edc..188c74a9521 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -553,6 +553,7 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
{
struct kiocb_priv *priv = iocb->private;
ssize_t len, total;
+ void *to_copy;
int i;
/* we "retry" to get the right mm context for this: */
@@ -560,10 +561,11 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
/* copy stuff into user buffers */
total = priv->actual;
len = 0;
+ to_copy = priv->buf;
for (i=0; i < priv->nr_segs; i++) {
ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
- if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
+ if (copy_to_user(priv->iv[i].iov_base, to_copy, this)) {
if (len == 0)
len = -EFAULT;
break;
@@ -571,6 +573,7 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
total -= this;
len += this;
+ to_copy += this;
if (total == 0)
break;
}
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 5d6c06bc452..8d24d3dc0a6 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -196,7 +196,7 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
struct uhci_td *td = list_entry(urbp->td_list.next,
struct uhci_td, list);
- if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS))
+ if (element != LINK_TO_TD(td))
out += sprintf(out, "%*s Element != First TD\n",
space, "");
i = nurbs = 0;
@@ -220,16 +220,6 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
return out - buf;
}
-static const char * const qh_names[] = {
- "skel_unlink_qh", "skel_iso_qh",
- "skel_int128_qh", "skel_int64_qh",
- "skel_int32_qh", "skel_int16_qh",
- "skel_int8_qh", "skel_int4_qh",
- "skel_int2_qh", "skel_int1_qh",
- "skel_ls_control_qh", "skel_fs_control_qh",
- "skel_bulk_qh", "skel_term_qh"
-};
-
static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
{
char *out = buf;
@@ -352,6 +342,12 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
struct uhci_td *td;
struct list_head *tmp, *head;
int nframes, nerrs;
+ __le32 link;
+
+ static const char * const qh_names[] = {
+ "unlink", "iso", "int128", "int64", "int32", "int16",
+ "int8", "int4", "int2", "async", "term"
+ };
out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
out += sprintf(out, "HC status\n");
@@ -374,7 +370,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
nframes = 10;
nerrs = 0;
for (i = 0; i < UHCI_NUMFRAMES; ++i) {
- __le32 link, qh_dma;
+ __le32 qh_dma;
j = 0;
td = uhci->frame_cpu[i];
@@ -393,7 +389,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
do {
td = list_entry(tmp, struct uhci_td, fl_list);
tmp = tmp->next;
- if (cpu_to_le32(td->dma_handle) != link) {
+ if (link != LINK_TO_TD(td)) {
if (nframes > 0)
out += sprintf(out, " link does "
"not match list entry!\n");
@@ -430,23 +426,21 @@ check_link:
for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
int cnt = 0;
+ __le32 fsbr_link = 0;
qh = uhci->skelqh[i];
- out += sprintf(out, "- %s\n", qh_names[i]); \
+ out += sprintf(out, "- skel_%s_qh\n", qh_names[i]); \
out += uhci_show_qh(qh, out, len - (out - buf), 4);
/* Last QH is the Terminating QH, it's different */
- if (i == UHCI_NUM_SKELQH - 1) {
- if (qh->link != UHCI_PTR_TERM)
- out += sprintf(out, " bandwidth reclamation on!\n");
-
- if (qh_element(qh) != cpu_to_le32(uhci->term_td->dma_handle))
+ if (i == SKEL_TERM) {
+ if (qh_element(qh) != LINK_TO_TD(uhci->term_td))
out += sprintf(out, " skel_term_qh element is not set to term_td!\n");
-
+ if (link == LINK_TO_QH(uhci->skel_term_qh))
+ goto check_qh_link;
continue;
}
- j = (i < 9) ? 9 : i+1; /* Next skeleton */
head = &qh->node;
tmp = head->next;
@@ -456,15 +450,26 @@ check_link:
if (++cnt <= 10)
out += uhci_show_qh(qh, out,
len - (out - buf), 4);
+ if (!fsbr_link && qh->skel >= SKEL_FSBR)
+ fsbr_link = LINK_TO_QH(qh);
}
if ((cnt -= 10) > 0)
out += sprintf(out, " Skipped %d QHs\n", cnt);
- if (i > 1 && i < UHCI_NUM_SKELQH - 1) {
- if (qh->link !=
- (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH))
- out += sprintf(out, " last QH not linked to next skeleton!\n");
- }
+ link = UHCI_PTR_TERM;
+ if (i <= SKEL_ISO)
+ ;
+ else if (i < SKEL_ASYNC)
+ link = LINK_TO_QH(uhci->skel_async_qh);
+ else if (!uhci->fsbr_is_on)
+ ;
+ else if (fsbr_link)
+ link = fsbr_link;
+ else
+ link = LINK_TO_QH(uhci->skel_term_qh);
+check_qh_link:
+ if (qh->link != link)
+ out += sprintf(out, " last QH not linked to next skeleton!\n");
}
return out - buf;
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index ded4df30a63..44da4334f1d 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -13,7 +13,7 @@
* (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
* support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
* (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu
+ * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
*
* Intel documents this fairly well, and as far as I know there
* are no royalties or anything like that, but even so there are
@@ -107,16 +107,16 @@ static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
* interrupt QHs, which will help spread out bandwidth utilization.
*
* ffs (Find First bit Set) does exactly what we need:
- * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8],
- * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
+ * 1,3,5,... => ffs = 0 => use period-2 QH = skelqh[8],
+ * 2,6,10,... => ffs = 1 => use period-4 QH = skelqh[7], etc.
* ffs >= 7 => not on any high-period queue, so use
- * skel_int1_qh = skelqh[9].
+ * period-1 QH = skelqh[9].
* Add in UHCI_NUMFRAMES to insure at least one bit is set.
*/
skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES);
if (skelnum <= 1)
skelnum = 9;
- return UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[skelnum]->dma_handle);
+ return LINK_TO_QH(uhci->skelqh[skelnum]);
}
#include "uhci-debug.c"
@@ -540,16 +540,18 @@ static void uhci_shutdown(struct pci_dev *pdev)
*
* The hardware doesn't really know any difference
* in the queues, but the order does matter for the
- * protocols higher up. The order is:
+ * protocols higher up. The order in which the queues
+ * are encountered by the hardware is:
*
- * - any isochronous events handled before any
+ * - All isochronous events are handled before any
* of the queues. We don't do that here, because
* we'll create the actual TD entries on demand.
- * - The first queue is the interrupt queue.
- * - The second queue is the control queue, split into low- and full-speed
- * - The third queue is bulk queue.
- * - The fourth queue is the bandwidth reclamation queue, which loops back
- * to the full-speed control queue.
+ * - The first queue is the high-period interrupt queue.
+ * - The second queue is the period-1 interrupt and async
+ * (low-speed control, full-speed control, then bulk) queue.
+ * - The third queue is the terminating bandwidth reclamation queue,
+ * which contains no members, loops back to itself, and is present
+ * only when FSBR is on and there are no full-speed control or bulk QHs.
*/
static int uhci_start(struct usb_hcd *hcd)
{
@@ -626,34 +628,18 @@ static int uhci_start(struct usb_hcd *hcd)
}
/*
- * 8 Interrupt queues; link all higher int queues to int1,
- * then link int1 to control and control to bulk
+ * 8 Interrupt queues; link all higher int queues to int1 = async
*/
- uhci->skel_int128_qh->link =
- uhci->skel_int64_qh->link =
- uhci->skel_int32_qh->link =
- uhci->skel_int16_qh->link =
- uhci->skel_int8_qh->link =
- uhci->skel_int4_qh->link =
- uhci->skel_int2_qh->link = UHCI_PTR_QH |
- cpu_to_le32(uhci->skel_int1_qh->dma_handle);
-
- uhci->skel_int1_qh->link = UHCI_PTR_QH |
- cpu_to_le32(uhci->skel_ls_control_qh->dma_handle);
- uhci->skel_ls_control_qh->link = UHCI_PTR_QH |
- cpu_to_le32(uhci->skel_fs_control_qh->dma_handle);
- uhci->skel_fs_control_qh->link = UHCI_PTR_QH |
- cpu_to_le32(uhci->skel_bulk_qh->dma_handle);
- uhci->skel_bulk_qh->link = UHCI_PTR_QH |
- cpu_to_le32(uhci->skel_term_qh->dma_handle);
+ for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i)
+ uhci->skelqh[i]->link = LINK_TO_QH(uhci->skel_async_qh);
+ uhci->skel_async_qh->link = uhci->skel_term_qh->link = UHCI_PTR_TERM;
/* This dummy TD is to work around a bug in Intel PIIX controllers */
uhci_fill_td(uhci->term_td, 0, uhci_explen(0) |
- (0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0);
- uhci->term_td->link = cpu_to_le32(uhci->term_td->dma_handle);
-
- uhci->skel_term_qh->link = UHCI_PTR_TERM;
- uhci->skel_term_qh->element = cpu_to_le32(uhci->term_td->dma_handle);
+ (0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0);
+ uhci->term_td->link = UHCI_PTR_TERM;
+ uhci->skel_async_qh->element = uhci->skel_term_qh->element =
+ LINK_TO_TD(uhci->term_td);
/*
* Fill the frame list: make all entries point to the proper
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 74469b5bcb6..1b3d23406ac 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -129,11 +129,12 @@ struct uhci_qh {
__le32 element; /* Queue element (TD) pointer */
/* Software fields */
+ dma_addr_t dma_handle;
+
struct list_head node; /* Node in the list of QHs */
struct usb_host_endpoint *hep; /* Endpoint information */
struct usb_device *udev;
struct list_head queue; /* Queue of urbps for this QH */
- struct uhci_qh *skel; /* Skeleton for this QH */
struct uhci_td *dummy_td; /* Dummy TD to end the queue */
struct uhci_td *post_td; /* Last TD completed */
@@ -149,8 +150,7 @@ struct uhci_qh {
int state; /* QH_STATE_xxx; see above */
int type; /* Queue type (control, bulk, etc) */
-
- dma_addr_t dma_handle;
+ int skel; /* Skeleton queue number */
unsigned int initial_toggle:1; /* Endpoint's current toggle value */
unsigned int needs_fixup:1; /* Must fix the TD toggle values */
@@ -171,6 +171,8 @@ static inline __le32 qh_element(struct uhci_qh *qh) {
return element;
}
+#define LINK_TO_QH(qh) (UHCI_PTR_QH | cpu_to_le32((qh)->dma_handle))
+
/*
* Transfer Descriptors
@@ -264,6 +266,8 @@ static inline u32 td_status(struct uhci_td *td) {
return le32_to_cpu(status);
}
+#define LINK_TO_TD(td) (cpu_to_le32((td)->dma_handle))
+
/*
* Skeleton Queue Headers
@@ -272,12 +276,13 @@ static inline u32 td_status(struct uhci_td *td) {
/*
* The UHCI driver uses QHs with Interrupt, Control and Bulk URBs for
* automatic queuing. To make it easy to insert entries into the schedule,
- * we have a skeleton of QHs for each predefined Interrupt latency,
- * low-speed control, full-speed control, bulk, and terminating QH
- * (see explanation for the terminating QH below).
+ * we have a skeleton of QHs for each predefined Interrupt latency.
+ * Asynchronous QHs (low-speed control, full-speed control, and bulk)
+ * go onto the period-1 interrupt list, since they all get accessed on
+ * every frame.
*
- * When we want to add a new QH, we add it to the end of the list for the
- * skeleton QH. For instance, the schedule list can look like this:
+ * When we want to add a new QH, we add it to the list starting from the
+ * appropriate skeleton QH. For instance, the schedule can look like this:
*
* skel int128 QH
* dev 1 interrupt QH
@@ -285,50 +290,47 @@ static inline u32 td_status(struct uhci_td *td) {
* skel int64 QH
* skel int32 QH
* ...
- * skel int1 QH
- * skel low-speed control QH
- * dev 5 control QH
- * skel full-speed control QH
- * skel bulk QH
+ * skel int1 + async QH
+ * dev 5 low-speed control QH
* dev 1 bulk QH
* dev 2 bulk QH
- * skel terminating QH
*
- * The terminating QH is used for 2 reasons:
- * - To place a terminating TD which is used to workaround a PIIX bug
- * (see Intel errata for explanation), and
- * - To loop back to the full-speed control queue for full-speed bandwidth
- * reclamation.
+ * There is a special terminating QH used to keep full-speed bandwidth
+ * reclamation active when no full-speed control or bulk QHs are linked
+ * into the schedule. It has an inactive TD (to work around a PIIX bug,
+ * see the Intel errata) and it points back to itself.
*
- * There's a special skeleton QH for Isochronous QHs. It never appears
- * on the schedule, and Isochronous TDs go on the schedule before the
+ * There's a special skeleton QH for Isochronous QHs which never appears
+ * on the schedule. Isochronous TDs go on the schedule before the
* the skeleton QHs. The hardware accesses them directly rather than
* through their QH, which is used only for bookkeeping purposes.
* While the UHCI spec doesn't forbid the use of QHs for Isochronous,
* it doesn't use them either. And the spec says that queues never
* advance on an error completion status, which makes them totally
* unsuitable for Isochronous transfers.
+ *
+ * There's also a special skeleton QH used for QHs which are in the process
+ * of unlinking and so may still be in use by the hardware. It too never
+ * appears on the schedule.
*/
-#define UHCI_NUM_SKELQH 14
-#define skel_unlink_qh skelqh[0]
-#define skel_iso_qh skelqh[1]
-#define skel_int128_qh skelqh[2]
-#define skel_int64_qh skelqh[3]
-#define skel_int32_qh skelqh[4]
-#define skel_int16_qh skelqh[5]
-#define skel_int8_qh skelqh[6]
-#define skel_int4_qh skelqh[7]
-#define skel_int2_qh skelqh[8]
-#define skel_int1_qh skelqh[9]
-#define skel_ls_control_qh skelqh[10]
-#define skel_fs_control_qh skelqh[11]
-#define skel_bulk_qh skelqh[12]
-#define skel_term_qh skelqh[13]
-
-/* Find the skelqh entry corresponding to an interval exponent */
-#define UHCI_SKEL_INDEX(exponent) (9 - exponent)
-
+#define UHCI_NUM_SKELQH 11
+#define SKEL_UNLINK 0
+#define skel_unlink_qh skelqh[SKEL_UNLINK]
+#define SKEL_ISO 1
+#define skel_iso_qh skelqh[SKEL_ISO]
+ /* int128, int64, ..., int1 = 2, 3, ..., 9 */
+#define SKEL_INDEX(exponent) (9 - exponent)
+#define SKEL_ASYNC 9
+#define skel_async_qh skelqh[SKEL_ASYNC]
+#define SKEL_TERM 10
+#define skel_term_qh skelqh[SKEL_TERM]
+
+/* The following entries refer to sublists of skel_async_qh */
+#define SKEL_LS_CONTROL 20
+#define SKEL_FS_CONTROL 21
+#define SKEL_FSBR SKEL_FS_CONTROL
+#define SKEL_BULK 22
/*
* The UHCI controller and root hub
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 68e66b33e72..f4ebdb3e488 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -13,7 +13,7 @@
* (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
* support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
* (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu
+ * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
*/
@@ -45,15 +45,43 @@ static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
*/
static void uhci_fsbr_on(struct uhci_hcd *uhci)
{
+ struct uhci_qh *fsbr_qh, *lqh, *tqh;
+
uhci->fsbr_is_on = 1;
- uhci->skel_term_qh->link = cpu_to_le32(
- uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
+ lqh = list_entry(uhci->skel_async_qh->node.prev,
+ struct uhci_qh, node);
+
+ /* Find the first FSBR QH. Linear search through the list is
+ * acceptable because normally FSBR gets turned on as soon as
+ * one QH needs it. */
+ fsbr_qh = NULL;
+ list_for_each_entry_reverse(tqh, &uhci->skel_async_qh->node, node) {
+ if (tqh->skel < SKEL_FSBR)
+ break;
+ fsbr_qh = tqh;
+ }
+
+ /* No FSBR QH means we must insert the terminating skeleton QH */
+ if (!fsbr_qh) {
+ uhci->skel_term_qh->link = LINK_TO_QH(uhci->skel_term_qh);
+ wmb();
+ lqh->link = uhci->skel_term_qh->link;
+
+ /* Otherwise loop the last QH to the first FSBR QH */
+ } else
+ lqh->link = LINK_TO_QH(fsbr_qh);
}
static void uhci_fsbr_off(struct uhci_hcd *uhci)
{
+ struct uhci_qh *lqh;
+
uhci->fsbr_is_on = 0;
- uhci->skel_term_qh->link = UHCI_PTR_TERM;
+ lqh = list_entry(uhci->skel_async_qh->node.prev,
+ struct uhci_qh, node);
+
+ /* End the async list normally and unlink the terminating QH */
+ lqh->link = uhci->skel_term_qh->link = UHCI_PTR_TERM;
}
static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb)
@@ -158,11 +186,11 @@ static inline void uhci_insert_td_in_frame_list(struct uhci_hcd *uhci,
td->link = ltd->link;
wmb();
- ltd->link = cpu_to_le32(td->dma_handle);
+ ltd->link = LINK_TO_TD(td);
} else {
td->link = uhci->frame[framenum];
wmb();
- uhci->frame[framenum] = cpu_to_le32(td->dma_handle);
+ uhci->frame[framenum] = LINK_TO_TD(td);
uhci->frame_cpu[framenum] = td;
}
}
@@ -184,7 +212,7 @@ static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci,
struct uhci_td *ntd;
ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
- uhci->frame[td->frame] = cpu_to_le32(ntd->dma_handle);
+ uhci->frame[td->frame] = LINK_TO_TD(ntd);
uhci->frame_cpu[td->frame] = ntd;
}
} else {
@@ -405,12 +433,81 @@ static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first)
}
/*
- * Put a QH on the schedule in both hardware and software
+ * Link an Isochronous QH into its skeleton's list
*/
-static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+static inline void link_iso(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ list_add_tail(&qh->node, &uhci->skel_iso_qh->node);
+
+ /* Isochronous QHs aren't linked by the hardware */
+}
+
+/*
+ * Link a high-period interrupt QH into the schedule at the end of its
+ * skeleton's list
+ */
+static void link_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
{
struct uhci_qh *pqh;
+ list_add_tail(&qh->node, &uhci->skelqh[qh->skel]->node);
+
+ pqh = list_entry(qh->node.prev, struct uhci_qh, node);
+ qh->link = pqh->link;
+ wmb();
+ pqh->link = LINK_TO_QH(qh);
+}
+
+/*
+ * Link a period-1 interrupt or async QH into the schedule at the
+ * correct spot in the async skeleton's list, and update the FSBR link
+ */
+static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ struct uhci_qh *pqh, *lqh;
+ __le32 link_to_new_qh;
+ __le32 *extra_link = &link_to_new_qh;
+
+ /* Find the predecessor QH for our new one and insert it in the list.
+ * The list of QHs is expected to be short, so linear search won't
+ * take too long. */
+ list_for_each_entry_reverse(pqh, &uhci->skel_async_qh->node, node) {
+ if (pqh->skel <= qh->skel)
+ break;
+ }
+ list_add(&qh->node, &pqh->node);
+ qh->link = pqh->link;
+
+ link_to_new_qh = LINK_TO_QH(qh);
+
+ /* If this is now the first FSBR QH, take special action */
+ if (uhci->fsbr_is_on && pqh->skel < SKEL_FSBR &&
+ qh->skel >= SKEL_FSBR) {
+ lqh = list_entry(uhci->skel_async_qh->node.prev,
+ struct uhci_qh, node);
+
+ /* If the new QH is also the last one, we must unlink
+ * the terminating skeleton QH and make the new QH point
+ * back to itself. */
+ if (qh == lqh) {
+ qh->link = link_to_new_qh;
+ extra_link = &uhci->skel_term_qh->link;
+
+ /* Otherwise the last QH must point to the new QH */
+ } else
+ extra_link = &lqh->link;
+ }
+
+ /* Link it into the schedule */
+ wmb();
+ *extra_link = pqh->link = link_to_new_qh;
+}
+
+/*
+ * Put a QH on the schedule in both hardware and software
+ */
+static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
WARN_ON(list_empty(&qh->queue));
/* Set the element pointer if it isn't set already.
@@ -421,7 +518,7 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
struct uhci_td *td = list_entry(urbp->td_list.next,
struct uhci_td, list);
- qh->element = cpu_to_le32(td->dma_handle);
+ qh->element = LINK_TO_TD(td);
}
/* Treat the queue as if it has just advanced */
@@ -432,18 +529,64 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
return;
qh->state = QH_STATE_ACTIVE;
- /* Move the QH from its old list to the end of the appropriate
+ /* Move the QH from its old list to the correct spot in the appropriate
* skeleton's list */
if (qh == uhci->next_qh)
uhci->next_qh = list_entry(qh->node.next, struct uhci_qh,
node);
- list_move_tail(&qh->node, &qh->skel->node);
+ list_del(&qh->node);
+
+ if (qh->skel == SKEL_ISO)
+ link_iso(uhci, qh);
+ else if (qh->skel < SKEL_ASYNC)
+ link_interrupt(uhci, qh);
+ else
+ link_async(uhci, qh);
+}
+
+/*
+ * Unlink a high-period interrupt QH from the schedule
+ */
+static void unlink_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ struct uhci_qh *pqh;
- /* Link it into the schedule */
pqh = list_entry(qh->node.prev, struct uhci_qh, node);
- qh->link = pqh->link;
- wmb();
- pqh->link = UHCI_PTR_QH | cpu_to_le32(qh->dma_handle);
+ pqh->link = qh->link;
+ mb();
+}
+
+/*
+ * Unlink a period-1 interrupt or async QH from the schedule
+ */
+static void unlink_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ struct uhci_qh *pqh, *lqh;
+ __le32 link_to_next_qh = qh->link;
+
+ pqh = list_entry(qh->node.prev, struct uhci_qh, node);
+
+ /* If this is the first FSBQ QH, take special action */
+ if (uhci->fsbr_is_on && pqh->skel < SKEL_FSBR &&
+ qh->skel >= SKEL_FSBR) {
+ lqh = list_entry(uhci->skel_async_qh->node.prev,
+ struct uhci_qh, node);
+
+ /* If this QH is also the last one, we must link in
+ * the terminating skeleton QH. */
+ if (qh == lqh) {
+ link_to_next_qh = LINK_TO_QH(uhci->skel_term_qh);
+ uhci->skel_term_qh->link = link_to_next_qh;
+ wmb();
+ qh->link = link_to_next_qh;
+
+ /* Otherwise the last QH must point to the new first FSBR QH */
+ } else
+ lqh->link = link_to_next_qh;
+ }
+
+ pqh->link = link_to_next_qh;
+ mb();
}
/*
@@ -451,17 +594,18 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
*/
static void uhci_unlink_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
{
- struct uhci_qh *pqh;
-
if (qh->state == QH_STATE_UNLINKING)
return;
WARN_ON(qh->state != QH_STATE_ACTIVE || !qh->udev);
qh->state = QH_STATE_UNLINKING;
/* Unlink the QH from the schedule and record when we did it */
- pqh = list_entry(qh->node.prev, struct uhci_qh, node);
- pqh->link = qh->link;
- mb();
+ if (qh->skel == SKEL_ISO)
+ ;
+ else if (qh->skel < SKEL_ASYNC)
+ unlink_interrupt(uhci, qh);
+ else
+ unlink_async(uhci, qh);
uhci_get_current_frame_number(uhci);
qh->unlink_frame = uhci->frame_number;
@@ -697,6 +841,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
dma_addr_t data = urb->transfer_dma;
__le32 *plink;
struct urb_priv *urbp = urb->hcpriv;
+ int skel;
/* The "pipe" thing contains the destination in bits 8--18 */
destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
@@ -737,7 +882,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = cpu_to_le32(td->dma_handle);
+ *plink = LINK_TO_TD(td);
/* Alternate Data0/1 (start with Data1) */
destination ^= TD_TOKEN_TOGGLE;
@@ -757,7 +902,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = cpu_to_le32(td->dma_handle);
+ *plink = LINK_TO_TD(td);
/*
* It's IN if the pipe is an output pipe or we're not expecting
@@ -784,7 +929,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = cpu_to_le32(td->dma_handle);
+ *plink = LINK_TO_TD(td);
uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
wmb();
@@ -797,11 +942,13 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
* isn't in the CONFIGURED state. */
if (urb->dev->speed == USB_SPEED_LOW ||
urb->dev->state != USB_STATE_CONFIGURED)
- qh->skel = uhci->skel_ls_control_qh;
+ skel = SKEL_LS_CONTROL;
else {
- qh->skel = uhci->skel_fs_control_qh;
+ skel = SKEL_FS_CONTROL;
uhci_add_fsbr(uhci, urb);
}
+ if (qh->state != QH_STATE_ACTIVE)
+ qh->skel = skel;
urb->actual_length = -8; /* Account for the SETUP packet */
return 0;
@@ -860,7 +1007,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = cpu_to_le32(td->dma_handle);
+ *plink = LINK_TO_TD(td);
}
uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status,
@@ -888,7 +1035,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = cpu_to_le32(td->dma_handle);
+ *plink = LINK_TO_TD(td);
uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status,
@@ -914,7 +1061,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = cpu_to_le32(td->dma_handle);
+ *plink = LINK_TO_TD(td);
uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
wmb();
@@ -931,7 +1078,7 @@ nomem:
return -ENOMEM;
}
-static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
+static int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
struct uhci_qh *qh)
{
int ret;
@@ -940,7 +1087,8 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
if (urb->dev->speed == USB_SPEED_LOW)
return -EINVAL;
- qh->skel = uhci->skel_bulk_qh;
+ if (qh->state != QH_STATE_ACTIVE)
+ qh->skel = SKEL_BULK;
ret = uhci_submit_common(uhci, urb, qh);
if (ret == 0)
uhci_add_fsbr(uhci, urb);
@@ -968,7 +1116,7 @@ static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
if (exponent < 0)
return -EINVAL;
qh->period = 1 << exponent;
- qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)];
+ qh->skel = SKEL_INDEX(exponent);
/* For now, interrupt phase is fixed by the layout
* of the QH lists. */
@@ -1005,7 +1153,7 @@ static int uhci_fixup_short_transfer(struct uhci_hcd *uhci,
* the queue at the status stage transaction, which is
* the last TD. */
WARN_ON(list_empty(&urbp->td_list));
- qh->element = cpu_to_le32(td->dma_handle);
+ qh->element = LINK_TO_TD(td);
tmp = td->list.prev;
ret = -EINPROGRESS;
@@ -1216,7 +1364,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
qh->iso_status = 0;
}
- qh->skel = uhci->skel_iso_qh;
+ qh->skel = SKEL_ISO;
if (!qh->bandwidth_reserved)
uhci_reserve_bandwidth(uhci, qh);
return 0;
@@ -1566,8 +1714,7 @@ static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh)
if (time_after(jiffies, qh->advance_jiffies + QH_WAIT_TIMEOUT)) {
/* Detect the Intel bug and work around it */
- if (qh->post_td && qh_element(qh) ==
- cpu_to_le32(qh->post_td->dma_handle)) {
+ if (qh->post_td && qh_element(qh) == LINK_TO_TD(qh->post_td)) {
qh->element = qh->post_td->link;
qh->advance_jiffies = jiffies;
ret = 1;
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index ef09952f203..827a75a186b 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -4,7 +4,7 @@
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
- * Copyright (c) 2006 Jiri Kosina
+ * Copyright (c) 2006-2007 Jiri Kosina
*/
/*
@@ -27,9 +27,6 @@
#include <linux/input.h>
#include <linux/wait.h>
-#undef DEBUG
-#undef DEBUG_DATA
-
#include <linux/usb.h>
#include <linux/hid.h>
@@ -689,10 +686,8 @@ void usbhid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
#define USB_VENDOR_ID_CODEMERCS 0x07c0
-#define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500
-#define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501
-#define USB_DEVICE_ID_CODEMERCS_IOW48 0x1502
-#define USB_DEVICE_ID_CODEMERCS_IOW28 0x1503
+#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500
+#define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff
#define USB_VENDOR_ID_DELORME 0x1163
#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
@@ -758,6 +753,8 @@ void usbhid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_LOGITECH 0x046d
#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER 0xc101
+#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2 0xc517
+#define USB_DEVICE_ID_DINOVO_EDGE 0xc714
#define USB_VENDOR_ID_IMATION 0x0718
#define USB_DEVICE_ID_DISC_STAKKA 0xd000
@@ -778,6 +775,8 @@ static const struct hid_blacklist {
unsigned quirks;
} hid_blacklist[] = {
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
+
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE },
@@ -788,10 +787,6 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW48, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
@@ -944,6 +939,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2, HID_QUIRK_LOGITECH_S510_DESCRIPTOR },
{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
@@ -1041,6 +1037,22 @@ static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
kfree(buf);
}
+/*
+ * Logitech S510 keyboard sends in report #3 keys which are far
+ * above the logical maximum described in descriptor. This extends
+ * the original value of 0x28c of logical maximum to 0x104d
+ */
+static void hid_fixup_s510_descriptor(unsigned char *rdesc, int rsize)
+{
+ if (rsize >= 90 && rdesc[83] == 0x26
+ && rdesc[84] == 0x8c
+ && rdesc[85] == 0x02) {
+ info("Fixing up Logitech S510 report descriptor");
+ rdesc[84] = rdesc[89] = 0x4d;
+ rdesc[85] = rdesc[90] = 0x10;
+ }
+}
+
static struct hid_device *usb_hid_configure(struct usb_interface *intf)
{
struct usb_host_interface *interface = intf->cur_altsetting;
@@ -1052,9 +1064,14 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
int n, len, insize = 0;
struct usbhid_device *usbhid;
- /* Ignore all Wacom devices */
- if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_WACOM)
- return NULL;
+ /* Ignore all Wacom devices */
+ if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_WACOM)
+ return NULL;
+ /* ignore all Code Mercenaries IOWarrior devices */
+ if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_CODEMERCS)
+ if (le16_to_cpu(dev->descriptor.idProduct) >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST &&
+ le16_to_cpu(dev->descriptor.idProduct) <= USB_DEVICE_ID_CODEMERCS_IOW_LAST)
+ return NULL;
for (n = 0; hid_blacklist[n].idVendor; n++)
if ((hid_blacklist[n].idVendor == le16_to_cpu(dev->descriptor.idVendor)) &&
@@ -1109,7 +1126,10 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
if ((quirks & HID_QUIRK_CYMOTION))
hid_fixup_cymotion_descriptor(rdesc, rsize);
-#ifdef DEBUG_DATA
+ if (quirks & HID_QUIRK_LOGITECH_S510_DESCRIPTOR)
+ hid_fixup_s510_descriptor(rdesc, rsize);
+
+#ifdef CONFIG_HID_DEBUG
printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
for (n = 0; n < rsize; n++)
printk(" %02x", (unsigned char) rdesc[n]);
@@ -1225,8 +1245,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
le16_to_cpu(dev->descriptor.idProduct));
hid->bus = BUS_USB;
- hid->vendor = dev->descriptor.idVendor;
- hid->product = dev->descriptor.idProduct;
+ hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
+ hid->product = le16_to_cpu(dev->descriptor.idProduct);
usb_make_path(dev, hid->phys, sizeof(hid->phys));
strlcat(hid->phys, "/input", sizeof(hid->phys));
diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c
index 8505824848f..3749f4a235f 100644
--- a/drivers/usb/input/usbkbd.c
+++ b/drivers/usb/input/usbkbd.c
@@ -31,6 +31,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb/input.h>
+#include <linux/hid.h>
/*
* Version Information
@@ -330,7 +331,8 @@ static void usb_kbd_disconnect(struct usb_interface *intf)
}
static struct usb_device_id usb_kbd_id_table [] = {
- { USB_INTERFACE_INFO(3, 1, 1) },
+ { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
+ USB_INTERFACE_PROTOCOL_KEYBOARD) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c
index 64a33e420cf..692fd608777 100644
--- a/drivers/usb/input/usbmouse.c
+++ b/drivers/usb/input/usbmouse.c
@@ -31,6 +31,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb/input.h>
+#include <linux/hid.h>
/*
* Version Information
@@ -213,7 +214,8 @@ static void usb_mouse_disconnect(struct usb_interface *intf)
}
static struct usb_device_id usb_mouse_id_table [] = {
- { USB_INTERFACE_INFO(3, 1, 2) },
+ { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
+ USB_INTERFACE_PROTOCOL_MOUSE) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/input/wacom_wac.c b/drivers/usb/input/wacom_wac.c
index 4142e36730f..4f3e9bc7177 100644
--- a/drivers/usb/input/wacom_wac.c
+++ b/drivers/usb/input/wacom_wac.c
@@ -163,7 +163,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
}
id = STYLUS_DEVICE_ID;
- if (data[1] & 0x10) { /* in prox */
+ if (data[1] & 0x80) { /* in prox */
switch ((data[1] >> 5) & 3) {
@@ -196,9 +196,6 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
break;
}
- }
-
- if (data[1] & 0x90) {
x = wacom_le16_to_cpu(&data[2]);
y = wacom_le16_to_cpu(&data[4]);
wacom_report_abs(wcombo, ABS_X, x);
@@ -210,19 +207,28 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x04);
}
wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
- }
- else
- wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
-
- if (data[1] & 0x10) /* only report prox-in when in area */
wacom_report_key(wcombo, wacom->tool[0], 1);
- if (!(data[1] & 0x90)) /* report prox-out when physically out */
+ } else if (!(data[1] & 0x90)) {
+ wacom_report_abs(wcombo, ABS_X, 0);
+ wacom_report_abs(wcombo, ABS_Y, 0);
+ if (wacom->tool[0] == BTN_TOOL_MOUSE) {
+ wacom_report_key(wcombo, BTN_LEFT, 0);
+ wacom_report_key(wcombo, BTN_RIGHT, 0);
+ wacom_report_abs(wcombo, ABS_DISTANCE, 0);
+ } else {
+ wacom_report_abs(wcombo, ABS_PRESSURE, 0);
+ wacom_report_key(wcombo, BTN_TOUCH, 0);
+ wacom_report_key(wcombo, BTN_STYLUS, 0);
+ wacom_report_key(wcombo, BTN_STYLUS2, 0);
+ }
+ wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
wacom_report_key(wcombo, wacom->tool[0], 0);
- wacom_input_sync(wcombo);
+ }
/* send pad data */
if (wacom->features->type == WACOM_G4) {
- if ( (wacom->serial[1] & 0xc0) != (data[7] & 0xf8) ) {
+ if (data[7] & 0xf8) {
+ wacom_input_sync(wcombo); /* sync last event */
wacom->id[1] = 1;
wacom->serial[1] = (data[7] & 0xf8);
wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
@@ -230,10 +236,15 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
wacom_report_rel(wcombo, REL_WHEEL, rw);
wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0);
+ wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
} else if (wacom->id[1]) {
+ wacom_input_sync(wcombo); /* sync last event */
wacom->id[1] = 0;
+ wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
+ wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
wacom_report_key(wcombo, BTN_TOOL_FINGER, 0);
+ wacom_report_abs(wcombo, ABS_MISC, 0);
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
}
}
@@ -304,28 +315,35 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
default: /* Unknown tool */
wacom->tool[idx] = BTN_TOOL_PEN;
}
- /* only large I3 support Lens Cursor */
- if(!((wacom->tool[idx] == BTN_TOOL_LENS)
- && ((wacom->features->type == INTUOS3)
- || (wacom->features->type == INTUOS3S)))) {
- wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */
- wacom_report_key(wcombo, wacom->tool[idx], 1);
- wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
- return 2;
- }
return 1;
}
/* Exit report */
if ((data[1] & 0xfe) == 0x80) {
- if(!((wacom->tool[idx] == BTN_TOOL_LENS)
- && ((wacom->features->type == INTUOS3)
- || (wacom->features->type == INTUOS3S)))) {
- wacom_report_key(wcombo, wacom->tool[idx], 0);
- wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
- wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
- return 2;
+ wacom_report_abs(wcombo, ABS_X, 0);
+ wacom_report_abs(wcombo, ABS_Y, 0);
+ wacom_report_abs(wcombo, ABS_DISTANCE, 0);
+ if (wacom->tool[idx] >= BTN_TOOL_MOUSE) {
+ wacom_report_key(wcombo, BTN_LEFT, 0);
+ wacom_report_key(wcombo, BTN_MIDDLE, 0);
+ wacom_report_key(wcombo, BTN_RIGHT, 0);
+ wacom_report_key(wcombo, BTN_SIDE, 0);
+ wacom_report_key(wcombo, BTN_EXTRA, 0);
+ wacom_report_abs(wcombo, ABS_THROTTLE, 0);
+ wacom_report_abs(wcombo, ABS_RZ, 0);
+ } else {
+ wacom_report_abs(wcombo, ABS_PRESSURE, 0);
+ wacom_report_abs(wcombo, ABS_TILT_X, 0);
+ wacom_report_abs(wcombo, ABS_TILT_Y, 0);
+ wacom_report_key(wcombo, BTN_STYLUS, 0);
+ wacom_report_key(wcombo, BTN_STYLUS2, 0);
+ wacom_report_key(wcombo, BTN_TOUCH, 0);
+ wacom_report_abs(wcombo, ABS_WHEEL, 0);
}
+ wacom_report_key(wcombo, wacom->tool[idx], 0);
+ wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
+ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+ return 2;
}
return 0;
}
@@ -394,6 +412,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
wacom_report_key(wcombo, wacom->tool[1], 1);
else
wacom_report_key(wcombo, wacom->tool[1], 0);
+ wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xffffffff);
return 1;
}
@@ -403,6 +422,12 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
if (result)
return result-1;
+ /* Only large I3 and I1 & I2 support Lense Cursor */
+ if((wacom->tool[idx] == BTN_TOOL_LENS)
+ && ((wacom->features->type == INTUOS3)
+ || (wacom->features->type == INTUOS3S)))
+ return 0;
+
/* Cintiq doesn't send data when RDY bit isn't set */
if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
return 0;
@@ -554,11 +579,11 @@ static struct wacom_features wacom_features[] = {
{ "Wacom Volito2 4x5", 8, 5104, 3712, 511, 63, GRAPHIRE },
{ "Wacom Volito2 2x3", 8, 3248, 2320, 511, 63, GRAPHIRE },
{ "Wacom PenPartner2", 8, 3250, 2320, 255, 63, GRAPHIRE },
- { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 63, INTUOS },
- { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
- { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 63, INTUOS },
- { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 63, INTUOS },
- { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 63, INTUOS },
+ { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 31, INTUOS },
+ { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 31, INTUOS },
+ { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 31, INTUOS },
+ { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 31, INTUOS },
+ { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 31, INTUOS },
{ "Wacom PL400", 8, 5408, 4056, 255, 0, PL },
{ "Wacom PL500", 8, 6144, 4608, 255, 0, PL },
{ "Wacom PL600", 8, 6126, 4604, 255, 0, PL },
@@ -571,11 +596,11 @@ static struct wacom_features wacom_features[] = {
{ "Wacom DTF521", 8, 6282, 4762, 511, 0, PL },
{ "Wacom DTF720", 8, 6858, 5506, 511, 0, PL },
{ "Wacom Cintiq Partner",8, 20480, 15360, 511, 0, PTU },
- { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 63, INTUOS },
- { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
- { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 63, INTUOS },
- { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 63, INTUOS },
- { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 63, INTUOS },
+ { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 31, INTUOS },
+ { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 31, INTUOS },
+ { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 31, INTUOS },
+ { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 31, INTUOS },
+ { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 31, INTUOS },
{ "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 63, INTUOS3S },
{ "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 63, INTUOS3 },
{ "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 63, INTUOS3 },
@@ -584,7 +609,7 @@ static struct wacom_features wacom_features[] = {
{ "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 },
{ "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 63, INTUOS3S },
{ "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ },
- { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
+ { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 31, INTUOS },
{ }
};
diff --git a/drivers/usb/input/wacom_wac.h b/drivers/usb/input/wacom_wac.h
index a1d9ce00797..a2302228724 100644
--- a/drivers/usb/input/wacom_wac.h
+++ b/drivers/usb/input/wacom_wac.h
@@ -12,6 +12,7 @@
#define STYLUS_DEVICE_ID 0x02
#define CURSOR_DEVICE_ID 0x06
#define ERASER_DEVICE_ID 0x0A
+#define PAD_DEVICE_ID 0x0F
enum {
PENPARTNER = 0,
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index 4907e8b8007..9c7eb6144d0 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -244,6 +244,20 @@ config USB_TRANCEVIBRATOR
To compile this driver as a module, choose M here: the
module will be called trancevibrator.
+config USB_IOWARRIOR
+ tristate "IO Warrior driver support"
+ depends on USB
+ help
+ Say Y here if you want to support the IO Warrior devices from Code
+ Mercenaries. This includes support for the following devices:
+ IO Warrior 40
+ IO Warrior 24
+ IO Warrior 56
+ IO Warrior 24 Power Vampire
+
+ To compile this driver as a module, choose M here: the
+ module will be called iowarrior.
+
config USB_TEST
tristate "USB testing driver (DEVELOPMENT)"
depends on USB && USB_DEVICEFS && EXPERIMENTAL
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index dac2d5b7156..b68e6b774f1 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_USB_EMI26) += emi26.o
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_LCD) += usblcd.o
obj-$(CONFIG_USB_LD) += ldusb.o
obj-$(CONFIG_USB_LED) += usbled.o
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
new file mode 100644
index 00000000000..d69665c8de0
--- /dev/null
+++ b/drivers/usb/misc/iowarrior.c
@@ -0,0 +1,925 @@
+/*
+ * Native support for the I/O-Warrior USB devices
+ *
+ * Copyright (c) 2003-2005 Code Mercenaries GmbH
+ * written by Christian Lucht <lucht@codemercs.com>
+ *
+ * based on
+
+ * usb-skeleton.c by Greg Kroah-Hartman <greg@kroah.com>
+ * brlvger.c by Stephane Dalton <sdalton@videotron.ca>
+ * and St�hane Doyon <s.doyon@videotron.ca>
+ *
+ * Released under the GPLv2.
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/version.h>
+#include <linux/usb/iowarrior.h>
+
+/* Version Information */
+#define DRIVER_VERSION "v0.4.0"
+#define DRIVER_AUTHOR "Christian Lucht <lucht@codemercs.com>"
+#define DRIVER_DESC "USB IO-Warrior driver (Linux 2.6.x)"
+
+#define USB_VENDOR_ID_CODEMERCS 1984
+/* low speed iowarrior */
+#define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500
+#define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501
+#define USB_DEVICE_ID_CODEMERCS_IOWPV1 0x1511
+#define USB_DEVICE_ID_CODEMERCS_IOWPV2 0x1512
+/* full speed iowarrior */
+#define USB_DEVICE_ID_CODEMERCS_IOW56 0x1503
+
+/* Get a minor range for your devices from the usb maintainer */
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define IOWARRIOR_MINOR_BASE 0
+#else
+#define IOWARRIOR_MINOR_BASE 208 // SKELETON_MINOR_BASE 192 + 16, not offical yet
+#endif
+
+/* interrupt input queue size */
+#define MAX_INTERRUPT_BUFFER 16
+/*
+ maximum number of urbs that are submitted for writes at the same time,
+ this applies to the IOWarrior56 only!
+ IOWarrior24 and IOWarrior40 use synchronous usb_control_msg calls.
+*/
+#define MAX_WRITES_IN_FLIGHT 4
+
+/* Use our own dbg macro */
+#undef dbg
+#define dbg( format, arg... ) do { if( debug ) printk( KERN_DEBUG __FILE__ ": " format "\n" , ## arg ); } while ( 0 )
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/* Module parameters */
+static int debug = 0;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "debug=1 enables debugging messages");
+
+static struct usb_driver iowarrior_driver;
+
+/*--------------*/
+/* data */
+/*--------------*/
+
+/* Structure to hold all of our device specific stuff */
+struct iowarrior {
+ struct mutex mutex; /* locks this structure */
+ struct usb_device *udev; /* save off the usb device pointer */
+ struct usb_interface *interface; /* the interface for this device */
+ unsigned char minor; /* the starting minor number for this device */
+ struct usb_endpoint_descriptor *int_out_endpoint; /* endpoint for reading (needed for IOW56 only) */
+ struct usb_endpoint_descriptor *int_in_endpoint; /* endpoint for reading */
+ struct urb *int_in_urb; /* the urb for reading data */
+ unsigned char *int_in_buffer; /* buffer for data to be read */
+ unsigned char serial_number; /* to detect lost packages */
+ unsigned char *read_queue; /* size is MAX_INTERRUPT_BUFFER * packet size */
+ wait_queue_head_t read_wait;
+ wait_queue_head_t write_wait; /* wait-queue for writing to the device */
+ atomic_t write_busy; /* number of write-urbs submitted */
+ atomic_t read_idx;
+ atomic_t intr_idx;
+ spinlock_t intr_idx_lock; /* protects intr_idx */
+ atomic_t overflow_flag; /* signals an index 'rollover' */
+ int present; /* this is 1 as long as the device is connected */
+ int opened; /* this is 1 if the device is currently open */
+ char chip_serial[9]; /* the serial number string of the chip connected */
+ int report_size; /* number of bytes in a report */
+ u16 product_id;
+};
+
+/*--------------*/
+/* globals */
+/*--------------*/
+/* prevent races between open() and disconnect() */
+static DECLARE_MUTEX(disconnect_sem);
+
+/*
+ * USB spec identifies 5 second timeouts.
+ */
+#define GET_TIMEOUT 5
+#define USB_REQ_GET_REPORT 0x01
+//#if 0
+static int usb_get_report(struct usb_device *dev,
+ struct usb_host_interface *inter, unsigned char type,
+ unsigned char id, void *buf, int size)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_REPORT,
+ USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE, (type << 8) + id,
+ inter->desc.bInterfaceNumber, buf, size,
+ GET_TIMEOUT);
+}
+//#endif
+
+#define USB_REQ_SET_REPORT 0x09
+
+static int usb_set_report(struct usb_interface *intf, unsigned char type,
+ unsigned char id, void *buf, int size)
+{
+ return usb_control_msg(interface_to_usbdev(intf),
+ usb_sndctrlpipe(interface_to_usbdev(intf), 0),
+ USB_REQ_SET_REPORT,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ (type << 8) + id,
+ intf->cur_altsetting->desc.bInterfaceNumber, buf,
+ size, 1);
+}
+
+/*---------------------*/
+/* driver registration */
+/*---------------------*/
+/* table of devices that work with this driver */
+static struct usb_device_id iowarrior_ids[] = {
+ {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40)},
+ {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24)},
+ {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV1)},
+ {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV2)},
+ {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW56)},
+ {} /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, iowarrior_ids);
+
+/*
+ * USB callback handler for reading data
+ */
+static void iowarrior_callback(struct urb *urb)
+{
+ struct iowarrior *dev = (struct iowarrior *)urb->context;
+ int intr_idx;
+ int read_idx;
+ int aux_idx;
+ int offset;
+ int status;
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default:
+ goto exit;
+ }
+
+ spin_lock(&dev->intr_idx_lock);
+ intr_idx = atomic_read(&dev->intr_idx);
+ /* aux_idx become previous intr_idx */
+ aux_idx = (intr_idx == 0) ? (MAX_INTERRUPT_BUFFER - 1) : (intr_idx - 1);
+ read_idx = atomic_read(&dev->read_idx);
+
+ /* queue is not empty and it's interface 0 */
+ if ((intr_idx != read_idx)
+ && (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0)) {
+ /* + 1 for serial number */
+ offset = aux_idx * (dev->report_size + 1);
+ if (!memcmp
+ (dev->read_queue + offset, urb->transfer_buffer,
+ dev->report_size)) {
+ /* equal values on interface 0 will be ignored */
+ spin_unlock(&dev->intr_idx_lock);
+ goto exit;
+ }
+ }
+
+ /* aux_idx become next intr_idx */
+ aux_idx = (intr_idx == (MAX_INTERRUPT_BUFFER - 1)) ? 0 : (intr_idx + 1);
+ if (read_idx == aux_idx) {
+ /* queue full, dropping oldest input */
+ read_idx = (++read_idx == MAX_INTERRUPT_BUFFER) ? 0 : read_idx;
+ atomic_set(&dev->read_idx, read_idx);
+ atomic_set(&dev->overflow_flag, 1);
+ }
+
+ /* +1 for serial number */
+ offset = intr_idx * (dev->report_size + 1);
+ memcpy(dev->read_queue + offset, urb->transfer_buffer,
+ dev->report_size);
+ *(dev->read_queue + offset + (dev->report_size)) = dev->serial_number++;
+
+ atomic_set(&dev->intr_idx, aux_idx);
+ spin_unlock(&dev->intr_idx_lock);
+ /* tell the blocking read about the new data */
+ wake_up_interruptible(&dev->read_wait);
+
+exit:
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status)
+ dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d",
+ __FUNCTION__, status);
+
+}
+
+/*
+ * USB Callback handler for write-ops
+ */
+static void iowarrior_write_callback(struct urb *urb)
+{
+ struct iowarrior *dev;
+ dev = (struct iowarrior *)urb->context;
+ /* sync/async unlink faults aren't errors */
+ if (urb->status &&
+ !(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) {
+ dbg("%s - nonzero write bulk status received: %d",
+ __func__, urb->status);
+ }
+ /* free up our allocated buffer */
+ usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+ /* tell a waiting writer the interrupt-out-pipe is available again */
+ atomic_dec(&dev->write_busy);
+ wake_up_interruptible(&dev->write_wait);
+}
+
+/**
+ * iowarrior_delete
+ */
+static inline void iowarrior_delete(struct iowarrior *dev)
+{
+ dbg("%s - minor %d", __func__, dev->minor);
+ kfree(dev->int_in_buffer);
+ usb_free_urb(dev->int_in_urb);
+ kfree(dev->read_queue);
+ kfree(dev);
+}
+
+/*---------------------*/
+/* fops implementation */
+/*---------------------*/
+
+static int read_index(struct iowarrior *dev)
+{
+ int intr_idx, read_idx;
+
+ read_idx = atomic_read(&dev->read_idx);
+ intr_idx = atomic_read(&dev->intr_idx);
+
+ return (read_idx == intr_idx ? -1 : read_idx);
+}
+
+/**
+ * iowarrior_read
+ */
+static ssize_t iowarrior_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct iowarrior *dev;
+ int read_idx;
+ int offset;
+
+ dev = (struct iowarrior *)file->private_data;
+
+ /* verify that the device wasn't unplugged */
+ if (dev == NULL || !dev->present)
+ return -ENODEV;
+
+ dbg("%s - minor %d, count = %zd", __func__, dev->minor, count);
+
+ /* read count must be packet size (+ time stamp) */
+ if ((count != dev->report_size)
+ && (count != (dev->report_size + 1)))
+ return -EINVAL;
+
+ /* repeat until no buffer overrun in callback handler occur */
+ do {
+ atomic_set(&dev->overflow_flag, 0);
+ if ((read_idx = read_index(dev)) == -1) {
+ /* queue emty */
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ else {
+ //next line will return when there is either new data, or the device is unplugged
+ int r = wait_event_interruptible(dev->read_wait,
+ (!dev->present
+ || (read_idx =
+ read_index
+ (dev)) !=
+ -1));
+ if (r) {
+ //we were interrupted by a signal
+ return -ERESTART;
+ }
+ if (!dev->present) {
+ //The device was unplugged
+ return -ENODEV;
+ }
+ if (read_idx == -1) {
+ // Can this happen ???
+ return 0;
+ }
+ }
+ }
+
+ offset = read_idx * (dev->report_size + 1);
+ if (copy_to_user(buffer, dev->read_queue + offset, count)) {
+ return -EFAULT;
+ }
+ } while (atomic_read(&dev->overflow_flag));
+
+ read_idx = ++read_idx == MAX_INTERRUPT_BUFFER ? 0 : read_idx;
+ atomic_set(&dev->read_idx, read_idx);
+ return count;
+}
+
+/*
+ * iowarrior_write
+ */
+static ssize_t iowarrior_write(struct file *file,
+ const char __user *user_buffer,
+ size_t count, loff_t *ppos)
+{
+ struct iowarrior *dev;
+ int retval = 0;
+ char *buf = NULL; /* for IOW24 and IOW56 we need a buffer */
+ struct urb *int_out_urb = NULL;
+
+ dev = (struct iowarrior *)file->private_data;
+
+ mutex_lock(&dev->mutex);
+ /* verify that the device wasn't unplugged */
+ if (dev == NULL || !dev->present) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ dbg("%s - minor %d, count = %zd", __func__, dev->minor, count);
+ /* if count is 0 we're already done */
+ if (count == 0) {
+ retval = 0;
+ goto exit;
+ }
+ /* We only accept full reports */
+ if (count != dev->report_size) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ switch (dev->product_id) {
+ case USB_DEVICE_ID_CODEMERCS_IOW24:
+ case USB_DEVICE_ID_CODEMERCS_IOWPV1:
+ case USB_DEVICE_ID_CODEMERCS_IOWPV2:
+ case USB_DEVICE_ID_CODEMERCS_IOW40:
+ /* IOW24 and IOW40 use a synchronous call */
+ buf = kmalloc(8, GFP_KERNEL); /* 8 bytes are enough for both products */
+ if (!buf) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+ if (copy_from_user(buf, user_buffer, count)) {
+ retval = -EFAULT;
+ kfree(buf);
+ goto exit;
+ }
+ retval = usb_set_report(dev->interface, 2, 0, buf, count);
+ kfree(buf);
+ goto exit;
+ break;
+ case USB_DEVICE_ID_CODEMERCS_IOW56:
+ /* The IOW56 uses asynchronous IO and more urbs */
+ if (atomic_read(&dev->write_busy) == MAX_WRITES_IN_FLIGHT) {
+ /* Wait until we are below the limit for submitted urbs */
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ goto exit;
+ } else {
+ retval = wait_event_interruptible(dev->write_wait,
+ (!dev->present || (atomic_read (&dev-> write_busy) < MAX_WRITES_IN_FLIGHT)));
+ if (retval) {
+ /* we were interrupted by a signal */
+ retval = -ERESTART;
+ goto exit;
+ }
+ if (!dev->present) {
+ /* The device was unplugged */
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (!dev->opened) {
+ /* We were closed while waiting for an URB */
+ retval = -ENODEV;
+ goto exit;
+ }
+ }
+ }
+ atomic_inc(&dev->write_busy);
+ int_out_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!int_out_urb) {
+ retval = -ENOMEM;
+ dbg("%s Unable to allocate urb ", __func__);
+ goto error;
+ }
+ buf = usb_buffer_alloc(dev->udev, dev->report_size,
+ GFP_KERNEL, &int_out_urb->transfer_dma);
+ if (!buf) {
+ retval = -ENOMEM;
+ dbg("%s Unable to allocate buffer ", __func__);
+ goto error;
+ }
+ usb_fill_int_urb(int_out_urb, dev->udev,
+ usb_sndintpipe(dev->udev,
+ dev->int_out_endpoint->bEndpointAddress),
+ buf, dev->report_size,
+ iowarrior_write_callback, dev,
+ dev->int_out_endpoint->bInterval);
+ int_out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ if (copy_from_user(buf, user_buffer, count)) {
+ retval = -EFAULT;
+ goto error;
+ }
+ retval = usb_submit_urb(int_out_urb, GFP_KERNEL);
+ if (retval) {
+ dbg("%s submit error %d for urb nr.%d", __func__,
+ retval, atomic_read(&dev->write_busy));
+ goto error;
+ }
+ /* submit was ok */
+ retval = count;
+ usb_free_urb(int_out_urb);
+ goto exit;
+ break;
+ default:
+ /* what do we have here ? An unsupported Product-ID ? */
+ dev_err(&dev->interface->dev, "%s - not supported for product=0x%x",
+ __FUNCTION__, dev->product_id);
+ retval = -EFAULT;
+ goto exit;
+ break;
+ }
+error:
+ usb_buffer_free(dev->udev, dev->report_size, buf,
+ int_out_urb->transfer_dma);
+ usb_free_urb(int_out_urb);
+ atomic_dec(&dev->write_busy);
+ wake_up_interruptible(&dev->write_wait);
+exit:
+ mutex_unlock(&dev->mutex);
+ return retval;
+}
+
+/**
+ * iowarrior_ioctl
+ */
+static int iowarrior_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct iowarrior *dev = NULL;
+ __u8 *buffer;
+ __u8 __user *user_buffer;
+ int retval;
+ int io_res; /* checks for bytes read/written and copy_to/from_user results */
+
+ dev = (struct iowarrior *)file->private_data;
+ if (dev == NULL) {
+ return -ENODEV;
+ }
+
+ buffer = kzalloc(dev->report_size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ /* lock this object */
+ mutex_lock(&dev->mutex);
+
+ /* verify that the device wasn't unplugged */
+ if (!dev->present) {
+ mutex_unlock(&dev->mutex);
+ return -ENODEV;
+ }
+
+ dbg("%s - minor %d, cmd 0x%.4x, arg %ld", __func__, dev->minor, cmd,
+ arg);
+
+ retval = 0;
+ io_res = 0;
+ switch (cmd) {
+ case IOW_WRITE:
+ if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 ||
+ dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV1 ||
+ dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV2 ||
+ dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW40) {
+ user_buffer = (__u8 __user *)arg;
+ io_res = copy_from_user(buffer, user_buffer,
+ dev->report_size);
+ if (io_res) {
+ retval = -EFAULT;
+ } else {
+ io_res = usb_set_report(dev->interface, 2, 0,
+ buffer,
+ dev->report_size);
+ if (io_res < 0)
+ retval = io_res;
+ }
+ } else {
+ retval = -EINVAL;
+ dev_err(&dev->interface->dev,
+ "ioctl 'IOW_WRITE' is not supported for product=0x%x.",
+ dev->product_id);
+ }
+ break;
+ case IOW_READ:
+ user_buffer = (__u8 __user *)arg;
+ io_res = usb_get_report(dev->udev,
+ dev->interface->cur_altsetting, 1, 0,
+ buffer, dev->report_size);
+ if (io_res < 0)
+ retval = io_res;
+ else {
+ io_res = copy_to_user(user_buffer, buffer, dev->report_size);
+ if (io_res < 0)
+ retval = -EFAULT;
+ }
+ break;
+ case IOW_GETINFO:
+ {
+ /* Report available information for the device */
+ struct iowarrior_info info;
+ /* needed for power consumption */
+ struct usb_config_descriptor *cfg_descriptor = &dev->udev->actconfig->desc;
+
+ /* directly from the descriptor */
+ info.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+ info.product = dev->product_id;
+ info.revision = le16_to_cpu(dev->udev->descriptor.bcdDevice);
+
+ /* 0==UNKNOWN, 1==LOW(usb1.1) ,2=FULL(usb1.1), 3=HIGH(usb2.0) */
+ info.speed = le16_to_cpu(dev->udev->speed);
+ info.if_num = dev->interface->cur_altsetting->desc.bInterfaceNumber;
+ info.report_size = dev->report_size;
+
+ /* serial number string has been read earlier 8 chars or empty string */
+ memcpy(info.serial, dev->chip_serial,
+ sizeof(dev->chip_serial));
+ if (cfg_descriptor == NULL) {
+ info.power = -1; /* no information available */
+ } else {
+ /* the MaxPower is stored in units of 2mA to make it fit into a byte-value */
+ info.power = cfg_descriptor->bMaxPower * 2;
+ }
+ io_res = copy_to_user((struct iowarrior_info __user *)arg, &info,
+ sizeof(struct iowarrior_info));
+ if (io_res < 0)
+ retval = -EFAULT;
+ break;
+ }
+ default:
+ /* return that we did not understand this ioctl call */
+ retval = -ENOTTY;
+ break;
+ }
+
+ /* unlock the device */
+ mutex_unlock(&dev->mutex);
+ return retval;
+}
+
+/**
+ * iowarrior_open
+ */
+static int iowarrior_open(struct inode *inode, struct file *file)
+{
+ struct iowarrior *dev = NULL;
+ struct usb_interface *interface;
+ int subminor;
+ int retval = 0;
+
+ dbg("%s", __func__);
+
+ subminor = iminor(inode);
+
+ /* prevent disconnects */
+ down(&disconnect_sem);
+
+ interface = usb_find_interface(&iowarrior_driver, subminor);
+ if (!interface) {
+ err("%s - error, can't find device for minor %d", __FUNCTION__,
+ subminor);
+ retval = -ENODEV;
+ goto out;
+ }
+
+ dev = usb_get_intfdata(interface);
+ if (!dev) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ /* Only one process can open each device, no sharing. */
+ if (dev->opened) {
+ retval = -EBUSY;
+ goto out;
+ }
+
+ /* setup interrupt handler for receiving values */
+ if ((retval = usb_submit_urb(dev->int_in_urb, GFP_KERNEL)) < 0) {
+ dev_err(&interface->dev, "Error %d while submitting URB\n", retval);
+ retval = -EFAULT;
+ goto out;
+ }
+ /* increment our usage count for the driver */
+ ++dev->opened;
+ /* save our object in the file's private structure */
+ file->private_data = dev;
+ retval = 0;
+
+out:
+ up(&disconnect_sem);
+ return retval;
+}
+
+/**
+ * iowarrior_release
+ */
+static int iowarrior_release(struct inode *inode, struct file *file)
+{
+ struct iowarrior *dev;
+ int retval = 0;
+
+ dev = (struct iowarrior *)file->private_data;
+ if (dev == NULL) {
+ return -ENODEV;
+ }
+
+ dbg("%s - minor %d", __func__, dev->minor);
+
+ /* lock our device */
+ mutex_lock(&dev->mutex);
+
+ if (dev->opened <= 0) {
+ retval = -ENODEV; /* close called more than once */
+ mutex_unlock(&dev->mutex);
+ } else {
+ dev->opened = 0; /* we're closeing now */
+ retval = 0;
+ if (dev->present) {
+ /*
+ The device is still connected so we only shutdown
+ pending read-/write-ops.
+ */
+ usb_kill_urb(dev->int_in_urb);
+ wake_up_interruptible(&dev->read_wait);
+ wake_up_interruptible(&dev->write_wait);
+ mutex_unlock(&dev->mutex);
+ } else {
+ /* The device was unplugged, cleanup resources */
+ mutex_unlock(&dev->mutex);
+ iowarrior_delete(dev);
+ }
+ }
+ return retval;
+}
+
+static unsigned iowarrior_poll(struct file *file, poll_table * wait)
+{
+ struct iowarrior *dev = file->private_data;
+ unsigned int mask = 0;
+
+ if (!dev->present)
+ return POLLERR | POLLHUP;
+
+ poll_wait(file, &dev->read_wait, wait);
+ poll_wait(file, &dev->write_wait, wait);
+
+ if (!dev->present)
+ return POLLERR | POLLHUP;
+
+ if (read_index(dev) != -1)
+ mask |= POLLIN | POLLRDNORM;
+
+ if (atomic_read(&dev->write_busy) < MAX_WRITES_IN_FLIGHT)
+ mask |= POLLOUT | POLLWRNORM;
+ return mask;
+}
+
+/*
+ * File operations needed when we register this driver.
+ * This assumes that this driver NEEDS file operations,
+ * of course, which means that the driver is expected
+ * to have a node in the /dev directory. If the USB
+ * device were for a network interface then the driver
+ * would use "struct net_driver" instead, and a serial
+ * device would use "struct tty_driver".
+ */
+static struct file_operations iowarrior_fops = {
+ .owner = THIS_MODULE,
+ .write = iowarrior_write,
+ .read = iowarrior_read,
+ .ioctl = iowarrior_ioctl,
+ .open = iowarrior_open,
+ .release = iowarrior_release,
+ .poll = iowarrior_poll,
+};
+
+/*
+ * usb class driver info in order to get a minor number from the usb core,
+ * and to have the device registered with devfs and the driver core
+ */
+static struct usb_class_driver iowarrior_class = {
+ .name = "iowarrior%d",
+ .fops = &iowarrior_fops,
+ .minor_base = IOWARRIOR_MINOR_BASE,
+};
+
+/*---------------------------------*/
+/* probe and disconnect functions */
+/*---------------------------------*/
+/**
+ * iowarrior_probe
+ *
+ * Called by the usb core when a new device is connected that it thinks
+ * this driver might be interested in.
+ */
+static int iowarrior_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(interface);
+ struct iowarrior *dev = NULL;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int i;
+ int retval = -ENOMEM;
+ int idele = 0;
+
+ /* allocate memory for our device state and intialize it */
+ dev = kzalloc(sizeof(struct iowarrior), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "Out of memory");
+ return retval;
+ }
+
+ mutex_init(&dev->mutex);
+
+ atomic_set(&dev->intr_idx, 0);
+ atomic_set(&dev->read_idx, 0);
+ spin_lock_init(&dev->intr_idx_lock);
+ atomic_set(&dev->overflow_flag, 0);
+ init_waitqueue_head(&dev->read_wait);
+ atomic_set(&dev->write_busy, 0);
+ init_waitqueue_head(&dev->write_wait);
+
+ dev->udev = udev;
+ dev->interface = interface;
+
+ iface_desc = interface->cur_altsetting;
+ dev->product_id = le16_to_cpu(udev->descriptor.idProduct);
+
+ /* set up the endpoint information */
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ if (usb_endpoint_is_int_in(endpoint))
+ dev->int_in_endpoint = endpoint;
+ if (usb_endpoint_is_int_out(endpoint))
+ /* this one will match for the IOWarrior56 only */
+ dev->int_out_endpoint = endpoint;
+ }
+ /* we have to check the report_size often, so remember it in the endianess suitable for our machine */
+ dev->report_size = le16_to_cpu(dev->int_in_endpoint->wMaxPacketSize);
+ if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) &&
+ (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56))
+ /* IOWarrior56 has wMaxPacketSize different from report size */
+ dev->report_size = 7;
+
+ /* create the urb and buffer for reading */
+ dev->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->int_in_urb) {
+ dev_err(&interface->dev, "Couldn't allocate interrupt_in_urb\n");
+ goto error;
+ }
+ dev->int_in_buffer = kmalloc(dev->report_size, GFP_KERNEL);
+ if (!dev->int_in_buffer) {
+ dev_err(&interface->dev, "Couldn't allocate int_in_buffer\n");
+ goto error;
+ }
+ usb_fill_int_urb(dev->int_in_urb, dev->udev,
+ usb_rcvintpipe(dev->udev,
+ dev->int_in_endpoint->bEndpointAddress),
+ dev->int_in_buffer, dev->report_size,
+ iowarrior_callback, dev,
+ dev->int_in_endpoint->bInterval);
+ /* create an internal buffer for interrupt data from the device */
+ dev->read_queue =
+ kmalloc(((dev->report_size + 1) * MAX_INTERRUPT_BUFFER),
+ GFP_KERNEL);
+ if (!dev->read_queue) {
+ dev_err(&interface->dev, "Couldn't allocate read_queue\n");
+ goto error;
+ }
+ /* Get the serial-number of the chip */
+ memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial));
+ usb_string(udev, udev->descriptor.iSerialNumber, dev->chip_serial,
+ sizeof(dev->chip_serial));
+ if (strlen(dev->chip_serial) != 8)
+ memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial));
+
+ /* Set the idle timeout to 0, if this is interface 0 */
+ if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) {
+ idele = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ 0x0A,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
+ 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ dbg("idele = %d", idele);
+ }
+ /* allow device read and ioctl */
+ dev->present = 1;
+
+ /* we can register the device now, as it is ready */
+ usb_set_intfdata(interface, dev);
+
+ retval = usb_register_dev(interface, &iowarrior_class);
+ if (retval) {
+ /* something prevented us from registering this driver */
+ dev_err(&interface->dev, "Not able to get a minor for this device.\n");
+ usb_set_intfdata(interface, NULL);
+ goto error;
+ }
+
+ dev->minor = interface->minor;
+
+ /* let the user know what node this device is now attached to */
+ dev_info(&interface->dev, "IOWarrior product=0x%x, serial=%s interface=%d "
+ "now attached to iowarrior%d\n", dev->product_id, dev->chip_serial,
+ iface_desc->desc.bInterfaceNumber, dev->minor - IOWARRIOR_MINOR_BASE);
+ return retval;
+
+error:
+ iowarrior_delete(dev);
+ return retval;
+}
+
+/**
+ * iowarrior_disconnect
+ *
+ * Called by the usb core when the device is removed from the system.
+ */
+static void iowarrior_disconnect(struct usb_interface *interface)
+{
+ struct iowarrior *dev;
+ int minor;
+
+ /* prevent races with open() */
+ down(&disconnect_sem);
+
+ dev = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ mutex_lock(&dev->mutex);
+
+ minor = dev->minor;
+
+ /* give back our minor */
+ usb_deregister_dev(interface, &iowarrior_class);
+
+ /* prevent device read, write and ioctl */
+ dev->present = 0;
+
+ mutex_unlock(&dev->mutex);
+
+ if (dev->opened) {
+ /* There is a process that holds a filedescriptor to the device ,
+ so we only shutdown read-/write-ops going on.
+ Deleting the device is postponed until close() was called.
+ */
+ usb_kill_urb(dev->int_in_urb);
+ wake_up_interruptible(&dev->read_wait);
+ wake_up_interruptible(&dev->write_wait);
+ } else {
+ /* no process is using the device, cleanup now */
+ iowarrior_delete(dev);
+ }
+ up(&disconnect_sem);
+
+ dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n",
+ minor - IOWARRIOR_MINOR_BASE);
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver iowarrior_driver = {
+ .name = "iowarrior",
+ .probe = iowarrior_probe,
+ .disconnect = iowarrior_disconnect,
+ .id_table = iowarrior_ids,
+};
+
+static int __init iowarrior_init(void)
+{
+ return usb_register(&iowarrior_driver);
+}
+
+static void __exit iowarrior_exit(void)
+{
+ usb_deregister(&iowarrior_driver);
+}
+
+module_init(iowarrior_init);
+module_exit(iowarrior_exit);
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index c01dfe60367..b2bedd974ac 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -1165,7 +1165,7 @@ err_dev:
return rc;
}
-void __exit mon_bin_exit(void)
+void mon_bin_exit(void)
{
cdev_del(&mon_bin_cdev);
unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index d38a1279d9d..494ee3b9a22 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -520,7 +520,7 @@ int __init mon_text_init(void)
return 0;
}
-void __exit mon_text_exit(void)
+void mon_text_exit(void)
{
debugfs_remove(mon_dir);
}
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
index 4f949ce8a7f..efdfd8993d9 100644
--- a/drivers/usb/mon/usb_mon.h
+++ b/drivers/usb/mon/usb_mon.h
@@ -57,9 +57,9 @@ void mon_text_del(struct mon_bus *mbus);
// void mon_bin_add(struct mon_bus *);
int __init mon_text_init(void);
-void __exit mon_text_exit(void);
+void mon_text_exit(void);
int __init mon_bin_init(void);
-void __exit mon_bin_exit(void);
+void mon_bin_exit(void);
/*
* DMA interface.
diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig
index 0f3d7dbb537..3de564b2314 100644
--- a/drivers/usb/net/Kconfig
+++ b/drivers/usb/net/Kconfig
@@ -186,6 +186,15 @@ config USB_NET_CDCETHER
IEEE 802 "local assignment" bit is set in the address, a "usbX"
name is used instead.
+config USB_NET_DM9601
+ tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices"
+ depends on USB_USBNET
+ select CRC32
+ select USB_USBNET_MII
+ help
+ This option adds support for Davicom DM9601 based USB 1.1
+ 10/100 Ethernet adapters.
+
config USB_NET_GL620A
tristate "GeneSys GL620USB-A based cables"
depends on USB_USBNET
diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile
index 7b51964de17..595a539f838 100644
--- a/drivers/usb/net/Makefile
+++ b/drivers/usb/net/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_USB_PEGASUS) += pegasus.o
obj-$(CONFIG_USB_RTL8150) += rtl8150.o
obj-$(CONFIG_USB_NET_AX8817X) += asix.o
obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
+obj-$(CONFIG_USB_NET_DM9601) += dm9601.o
obj-$(CONFIG_USB_NET_GL620A) += gl620a.o
obj-$(CONFIG_USB_NET_NET1080) += net1080.o
obj-$(CONFIG_USB_NET_PLUSB) += plusb.o
diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c
index 7ef2e4b5e39..5808ea08245 100644
--- a/drivers/usb/net/asix.c
+++ b/drivers/usb/net/asix.c
@@ -1395,9 +1395,9 @@ static const struct usb_device_id products [] = {
USB_DEVICE (0x07b8, 0x420a),
.driver_info = (unsigned long) &hawking_uf200_info,
}, {
- // Billionton Systems, USB2AR
- USB_DEVICE (0x08dd, 0x90ff),
- .driver_info = (unsigned long) &ax8817x_info,
+ // Billionton Systems, USB2AR
+ USB_DEVICE (0x08dd, 0x90ff),
+ .driver_info = (unsigned long) &ax8817x_info,
}, {
// ATEN UC210T
USB_DEVICE (0x0557, 0x2009),
@@ -1423,9 +1423,13 @@ static const struct usb_device_id products [] = {
USB_DEVICE (0x1631, 0x6200),
.driver_info = (unsigned long) &ax8817x_info,
}, {
+ // JVC MP-PRX1 Port Replicator
+ USB_DEVICE (0x04f1, 0x3008),
+ .driver_info = (unsigned long) &ax8817x_info,
+}, {
// ASIX AX88772 10/100
- USB_DEVICE (0x0b95, 0x7720),
- .driver_info = (unsigned long) &ax88772_info,
+ USB_DEVICE (0x0b95, 0x7720),
+ .driver_info = (unsigned long) &ax88772_info,
}, {
// ASIX AX88178 10/100/1000
USB_DEVICE (0x0b95, 0x1780),
diff --git a/drivers/usb/net/dm9601.c b/drivers/usb/net/dm9601.c
new file mode 100644
index 00000000000..4a932e1cd93
--- /dev/null
+++ b/drivers/usb/net/dm9601.c
@@ -0,0 +1,606 @@
+/*
+ * Davicom DM9601 USB 1.1 10/100Mbps ethernet devices
+ *
+ * Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+//#define DEBUG
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+
+#include "usbnet.h"
+
+/* datasheet:
+ http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-P01-930914.pdf
+*/
+
+/* control requests */
+#define DM_READ_REGS 0x00
+#define DM_WRITE_REGS 0x01
+#define DM_READ_MEMS 0x02
+#define DM_WRITE_REG 0x03
+#define DM_WRITE_MEMS 0x05
+#define DM_WRITE_MEM 0x07
+
+/* registers */
+#define DM_NET_CTRL 0x00
+#define DM_RX_CTRL 0x05
+#define DM_SHARED_CTRL 0x0b
+#define DM_SHARED_ADDR 0x0c
+#define DM_SHARED_DATA 0x0d /* low + high */
+#define DM_PHY_ADDR 0x10 /* 6 bytes */
+#define DM_MCAST_ADDR 0x16 /* 8 bytes */
+#define DM_GPR_CTRL 0x1e
+#define DM_GPR_DATA 0x1f
+
+#define DM_MAX_MCAST 64
+#define DM_MCAST_SIZE 8
+#define DM_EEPROM_LEN 256
+#define DM_TX_OVERHEAD 2 /* 2 byte header */
+#define DM_RX_OVERHEAD 7 /* 3 byte header + 4 byte crc tail */
+#define DM_TIMEOUT 1000
+
+
+static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+ devdbg(dev, "dm_read() reg=0x%02x length=%d", reg, length);
+ return usb_control_msg(dev->udev,
+ usb_rcvctrlpipe(dev->udev, 0),
+ DM_READ_REGS,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, reg, data, length, USB_CTRL_SET_TIMEOUT);
+}
+
+static int dm_read_reg(struct usbnet *dev, u8 reg, u8 *value)
+{
+ return dm_read(dev, reg, 1, value);
+}
+
+static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+ devdbg(dev, "dm_write() reg=0x%02x, length=%d", reg, length);
+ return usb_control_msg(dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ DM_WRITE_REGS,
+ USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE,
+ 0, reg, data, length, USB_CTRL_SET_TIMEOUT);
+}
+
+static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value)
+{
+ devdbg(dev, "dm_write_reg() reg=0x%02x, value=0x%02x", reg, value);
+ return usb_control_msg(dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ DM_WRITE_REG,
+ USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE,
+ value, reg, 0, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+static void dm_write_async_callback(struct urb *urb)
+{
+ struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
+
+ if (urb->status < 0)
+ printk(KERN_DEBUG "dm_write_async_callback() failed with %d",
+ urb->status);
+
+ kfree(req);
+ usb_free_urb(urb);
+}
+
+static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+ struct usb_ctrlrequest *req;
+ struct urb *urb;
+ int status;
+
+ devdbg(dev, "dm_write_async() reg=0x%02x length=%d", reg, length);
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ deverr(dev, "Error allocating URB in dm_write_async!");
+ return;
+ }
+
+ req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
+ if (!req) {
+ deverr(dev, "Failed to allocate memory for control request");
+ usb_free_urb(urb);
+ return;
+ }
+
+ req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ req->bRequest = DM_WRITE_REGS;
+ req->wValue = 0;
+ req->wIndex = cpu_to_le16(reg);
+ req->wLength = cpu_to_le16(length);
+
+ usb_fill_control_urb(urb, dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ (void *)req, data, length,
+ dm_write_async_callback, req);
+
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status < 0) {
+ deverr(dev, "Error submitting the control message: status=%d",
+ status);
+ kfree(req);
+ usb_free_urb(urb);
+ }
+}
+
+static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
+{
+ struct usb_ctrlrequest *req;
+ struct urb *urb;
+ int status;
+
+ devdbg(dev, "dm_write_reg_async() reg=0x%02x value=0x%02x",
+ reg, value);
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ deverr(dev, "Error allocating URB in dm_write_async!");
+ return;
+ }
+
+ req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
+ if (!req) {
+ deverr(dev, "Failed to allocate memory for control request");
+ usb_free_urb(urb);
+ return;
+ }
+
+ req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ req->bRequest = DM_WRITE_REG;
+ req->wValue = cpu_to_le16(value);
+ req->wIndex = cpu_to_le16(reg);
+ req->wLength = 0;
+
+ usb_fill_control_urb(urb, dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ (void *)req, 0, 0, dm_write_async_callback, req);
+
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status < 0) {
+ deverr(dev, "Error submitting the control message: status=%d",
+ status);
+ kfree(req);
+ usb_free_urb(urb);
+ }
+}
+
+static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, u16 *value)
+{
+ int ret, i;
+
+ mutex_lock(&dev->phy_mutex);
+
+ dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg);
+ dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0xc : 0x4);
+
+ for (i = 0; i < DM_TIMEOUT; i++) {
+ u8 tmp;
+
+ udelay(1);
+ ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
+ if (ret < 0)
+ goto out;
+
+ /* ready */
+ if ((tmp & 1) == 0)
+ break;
+ }
+
+ if (i == DM_TIMEOUT) {
+ deverr(dev, "%s read timed out!", phy ? "phy" : "eeprom");
+ ret = -EIO;
+ goto out;
+ }
+
+ dm_write_reg(dev, DM_SHARED_CTRL, 0x0);
+ ret = dm_read(dev, DM_SHARED_DATA, 2, value);
+
+ devdbg(dev, "read shared %d 0x%02x returned 0x%04x, %d",
+ phy, reg, *value, ret);
+
+ out:
+ mutex_unlock(&dev->phy_mutex);
+ return ret;
+}
+
+static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, u16 value)
+{
+ int ret, i;
+
+ mutex_lock(&dev->phy_mutex);
+
+ ret = dm_write(dev, DM_SHARED_DATA, 2, &value);
+ if (ret < 0)
+ goto out;
+
+ dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg);
+ dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1c : 0x14);
+
+ for (i = 0; i < DM_TIMEOUT; i++) {
+ u8 tmp;
+
+ udelay(1);
+ ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
+ if (ret < 0)
+ goto out;
+
+ /* ready */
+ if ((tmp & 1) == 0)
+ break;
+ }
+
+ if (i == DM_TIMEOUT) {
+ deverr(dev, "%s write timed out!", phy ? "phy" : "eeprom");
+ ret = -EIO;
+ goto out;
+ }
+
+ dm_write_reg(dev, DM_SHARED_CTRL, 0x0);
+
+out:
+ mutex_unlock(&dev->phy_mutex);
+ return ret;
+}
+
+static int dm_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
+{
+ return dm_read_shared_word(dev, 0, offset, value);
+}
+
+
+
+static int dm9601_get_eeprom_len(struct net_device *dev)
+{
+ return DM_EEPROM_LEN;
+}
+
+static int dm9601_get_eeprom(struct net_device *net,
+ struct ethtool_eeprom *eeprom, u8 * data)
+{
+ struct usbnet *dev = netdev_priv(net);
+ u16 *ebuf = (u16 *) data;
+ int i;
+
+ /* access is 16bit */
+ if ((eeprom->offset % 2) || (eeprom->len % 2))
+ return -EINVAL;
+
+ for (i = 0; i < eeprom->len / 2; i++) {
+ if (dm_read_eeprom_word(dev, eeprom->offset / 2 + i,
+ &ebuf[i]) < 0)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dm9601_mdio_read(struct net_device *netdev, int phy_id, int loc)
+{
+ struct usbnet *dev = netdev_priv(netdev);
+
+ u16 res;
+
+ if (phy_id) {
+ devdbg(dev, "Only internal phy supported");
+ return 0;
+ }
+
+ dm_read_shared_word(dev, 1, loc, &res);
+
+ devdbg(dev,
+ "dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x",
+ phy_id, loc, le16_to_cpu(res));
+
+ return le16_to_cpu(res);
+}
+
+static void dm9601_mdio_write(struct net_device *netdev, int phy_id, int loc,
+ int val)
+{
+ struct usbnet *dev = netdev_priv(netdev);
+ u16 res = cpu_to_le16(val);
+
+ if (phy_id) {
+ devdbg(dev, "Only internal phy supported");
+ return;
+ }
+
+ devdbg(dev,"dm9601_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x",
+ phy_id, loc, val);
+
+ dm_write_shared_word(dev, 1, loc, res);
+}
+
+static void dm9601_get_drvinfo(struct net_device *net,
+ struct ethtool_drvinfo *info)
+{
+ /* Inherit standard device info */
+ usbnet_get_drvinfo(net, info);
+ info->eedump_len = DM_EEPROM_LEN;
+}
+
+static u32 dm9601_get_link(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ return mii_link_ok(&dev->mii);
+}
+
+static int dm9601_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static struct ethtool_ops dm9601_ethtool_ops = {
+ .get_drvinfo = dm9601_get_drvinfo,
+ .get_link = dm9601_get_link,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_eeprom_len = dm9601_get_eeprom_len,
+ .get_eeprom = dm9601_get_eeprom,
+ .get_settings = usbnet_get_settings,
+ .set_settings = usbnet_set_settings,
+ .nway_reset = usbnet_nway_reset,
+};
+
+static void dm9601_set_multicast(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+ /* We use the 20 byte dev->data for our 8 byte filter buffer
+ * to avoid allocating memory that is tricky to free later */
+ u8 *hashes = (u8 *) & dev->data;
+ u8 rx_ctl = 0x01;
+
+ memset(hashes, 0x00, DM_MCAST_SIZE);
+ hashes[DM_MCAST_SIZE - 1] |= 0x80; /* broadcast address */
+
+ if (net->flags & IFF_PROMISC) {
+ rx_ctl |= 0x02;
+ } else if (net->flags & IFF_ALLMULTI || net->mc_count > DM_MAX_MCAST) {
+ rx_ctl |= 0x04;
+ } else if (net->mc_count) {
+ struct dev_mc_list *mc_list = net->mc_list;
+ int i;
+
+ for (i = 0; i < net->mc_count; i++) {
+ u32 crc = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26;
+ hashes[crc >> 3] |= 1 << (crc & 0x7);
+ }
+ }
+
+ dm_write_async(dev, DM_MCAST_ADDR, DM_MCAST_SIZE, hashes);
+ dm_write_reg_async(dev, DM_RX_CTRL, rx_ctl);
+}
+
+static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+ int ret;
+
+ ret = usbnet_get_endpoints(dev, intf);
+ if (ret)
+ goto out;
+
+ dev->net->do_ioctl = dm9601_ioctl;
+ dev->net->set_multicast_list = dm9601_set_multicast;
+ dev->net->ethtool_ops = &dm9601_ethtool_ops;
+ dev->net->hard_header_len += DM_TX_OVERHEAD;
+ dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+ dev->rx_urb_size = dev->net->mtu + DM_RX_OVERHEAD;
+
+ dev->mii.dev = dev->net;
+ dev->mii.mdio_read = dm9601_mdio_read;
+ dev->mii.mdio_write = dm9601_mdio_write;
+ dev->mii.phy_id_mask = 0x1f;
+ dev->mii.reg_num_mask = 0x1f;
+
+ /* reset */
+ ret = dm_write_reg(dev, DM_NET_CTRL, 1);
+ udelay(20);
+
+ /* read MAC */
+ ret = dm_read(dev, DM_PHY_ADDR, ETH_ALEN, dev->net->dev_addr);
+ if (ret < 0) {
+ printk(KERN_ERR "Error reading MAC address\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+
+ /* power up phy */
+ dm_write_reg(dev, DM_GPR_CTRL, 1);
+ dm_write_reg(dev, DM_GPR_DATA, 0);
+
+ /* receive broadcast packets */
+ dm9601_set_multicast(dev->net);
+
+ dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+ dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+ mii_nway_restart(&dev->mii);
+
+out:
+ return ret;
+}
+
+static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+ u8 status;
+ int len;
+
+ /* format:
+ b0: rx status
+ b1: packet length (incl crc) low
+ b2: packet length (incl crc) high
+ b3..n-4: packet data
+ bn-3..bn: ethernet crc
+ */
+
+ if (unlikely(skb->len < DM_RX_OVERHEAD)) {
+ dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
+ return 0;
+ }
+
+ status = skb->data[0];
+ len = (skb->data[1] | (skb->data[2] << 8)) - 4;
+
+ if (unlikely(status & 0xbf)) {
+ if (status & 0x01) dev->stats.rx_fifo_errors++;
+ if (status & 0x02) dev->stats.rx_crc_errors++;
+ if (status & 0x04) dev->stats.rx_frame_errors++;
+ if (status & 0x20) dev->stats.rx_missed_errors++;
+ if (status & 0x90) dev->stats.rx_length_errors++;
+ return 0;
+ }
+
+ skb_pull(skb, 3);
+ skb_trim(skb, len);
+
+ return 1;
+}
+
+static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
+ gfp_t flags)
+{
+ int len;
+
+ /* format:
+ b0: packet length low
+ b1: packet length high
+ b3..n: packet data
+ */
+
+ if (skb_headroom(skb) < DM_TX_OVERHEAD) {
+ struct sk_buff *skb2;
+
+ skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, 0, flags);
+ dev_kfree_skb_any(skb);
+ skb = skb2;
+ if (!skb)
+ return NULL;
+ }
+
+ __skb_push(skb, DM_TX_OVERHEAD);
+
+ len = skb->len;
+ /* usbnet adds padding if length is a multiple of packet size
+ if so, adjust length value in header */
+ if ((len % dev->maxpacket) == 0)
+ len++;
+
+ skb->data[0] = len;
+ skb->data[1] = len >> 8;
+
+ return skb;
+}
+
+static void dm9601_status(struct usbnet *dev, struct urb *urb)
+{
+ int link;
+ u8 *buf;
+
+ /* format:
+ b0: net status
+ b1: tx status 1
+ b2: tx status 2
+ b3: rx status
+ b4: rx overflow
+ b5: rx count
+ b6: tx count
+ b7: gpr
+ */
+
+ if (urb->actual_length < 8)
+ return;
+
+ buf = urb->transfer_buffer;
+
+ link = !!(buf[0] & 0x40);
+ if (netif_carrier_ok(dev->net) != link) {
+ if (link) {
+ netif_carrier_on(dev->net);
+ usbnet_defer_kevent (dev, EVENT_LINK_RESET);
+ }
+ else
+ netif_carrier_off(dev->net);
+ devdbg(dev, "Link Status is: %d", link);
+ }
+}
+
+static int dm9601_link_reset(struct usbnet *dev)
+{
+ struct ethtool_cmd ecmd;
+
+ mii_check_media(&dev->mii, 1, 1);
+ mii_ethtool_gset(&dev->mii, &ecmd);
+
+ devdbg(dev, "link_reset() speed: %d duplex: %d",
+ ecmd.speed, ecmd.duplex);
+
+ return 0;
+}
+
+static const struct driver_info dm9601_info = {
+ .description = "Davicom DM9601 USB Ethernet",
+ .flags = FLAG_ETHER,
+ .bind = dm9601_bind,
+ .rx_fixup = dm9601_rx_fixup,
+ .tx_fixup = dm9601_tx_fixup,
+ .status = dm9601_status,
+ .link_reset = dm9601_link_reset,
+ .reset = dm9601_link_reset,
+};
+
+static const struct usb_device_id products[] = {
+ {
+ USB_DEVICE(0x0a46, 0x9601), /* Davicom USB-100 */
+ .driver_info = (unsigned long)&dm9601_info,
+ },
+ {}, // END
+};
+
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver dm9601_driver = {
+ .name = "dm9601",
+ .id_table = products,
+ .probe = usbnet_probe,
+ .disconnect = usbnet_disconnect,
+ .suspend = usbnet_suspend,
+ .resume = usbnet_resume,
+};
+
+static int __init dm9601_init(void)
+{
+ return usb_register(&dm9601_driver);
+}
+
+static void __exit dm9601_exit(void)
+{
+ usb_deregister(&dm9601_driver);
+}
+
+module_init(dm9601_init);
+module_exit(dm9601_exit);
+
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("Davicom DM9601 USB 1.1 ethernet devices");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 4695952b647..c525b42dadd 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -513,6 +513,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) },
{ USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) },
+ { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 7eff1c03ba8..1bdda935f7d 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -491,6 +491,12 @@
#define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */
#define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */
+/*
+ * Telldus Technologies
+ */
+#define TELLDUS_VID 0x1781 /* Vendor ID */
+#define TELLDUS_TELLSTICK_PID 0x0C30 /* RF control dongle 433 MHz using FT232RL */
+
/* Commands */
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 9963a8b7584..db92a7fb1f7 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -67,50 +67,95 @@ static int option_tiocmset(struct usb_serial_port *port, struct file *file,
static int option_send_setup(struct usb_serial_port *port);
/* Vendor and product IDs */
-#define OPTION_VENDOR_ID 0x0AF0
-#define HUAWEI_VENDOR_ID 0x12D1
-#define NOVATELWIRELESS_VENDOR_ID 0x1410
-#define ANYDATA_VENDOR_ID 0x16d5
-
-#define OPTION_PRODUCT_OLD 0x5000
-#define OPTION_PRODUCT_FUSION 0x6000
-#define OPTION_PRODUCT_FUSION2 0x6300
-#define OPTION_PRODUCT_COBRA 0x6500
-#define OPTION_PRODUCT_COBRA2 0x6600
-#define OPTION_PRODUCT_GTMAX36 0x6701
-#define HUAWEI_PRODUCT_E600 0x1001
-#define HUAWEI_PRODUCT_E220 0x1003
-#define NOVATELWIRELESS_PRODUCT_U740 0x1400
-#define ANYDATA_PRODUCT_ID 0x6501
+#define OPTION_VENDOR_ID 0x0AF0
+#define OPTION_PRODUCT_COLT 0x5000
+#define OPTION_PRODUCT_RICOLA 0x6000
+#define OPTION_PRODUCT_RICOLA_LIGHT 0x6100
+#define OPTION_PRODUCT_RICOLA_QUAD 0x6200
+#define OPTION_PRODUCT_RICOLA_QUAD_LIGHT 0x6300
+#define OPTION_PRODUCT_RICOLA_NDIS 0x6050
+#define OPTION_PRODUCT_RICOLA_NDIS_LIGHT 0x6150
+#define OPTION_PRODUCT_RICOLA_NDIS_QUAD 0x6250
+#define OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT 0x6350
+#define OPTION_PRODUCT_COBRA 0x6500
+#define OPTION_PRODUCT_COBRA_BUS 0x6501
+#define OPTION_PRODUCT_VIPER 0x6600
+#define OPTION_PRODUCT_VIPER_BUS 0x6601
+#define OPTION_PRODUCT_GT_MAX_READY 0x6701
+#define OPTION_PRODUCT_GT_MAX 0x6711
+#define OPTION_PRODUCT_FUJI_MODEM_LIGHT 0x6721
+#define OPTION_PRODUCT_FUJI_MODEM_GT 0x6741
+#define OPTION_PRODUCT_FUJI_MODEM_EX 0x6761
+#define OPTION_PRODUCT_FUJI_NETWORK_LIGHT 0x6731
+#define OPTION_PRODUCT_FUJI_NETWORK_GT 0x6751
+#define OPTION_PRODUCT_FUJI_NETWORK_EX 0x6771
+#define OPTION_PRODUCT_KOI_MODEM 0x6800
+#define OPTION_PRODUCT_KOI_NETWORK 0x6811
+#define OPTION_PRODUCT_SCORPION_MODEM 0x6901
+#define OPTION_PRODUCT_SCORPION_NETWORK 0x6911
+#define OPTION_PRODUCT_ETNA_MODEM 0x7001
+#define OPTION_PRODUCT_ETNA_NETWORK 0x7011
+#define OPTION_PRODUCT_ETNA_MODEM_LITE 0x7021
+#define OPTION_PRODUCT_ETNA_MODEM_GT 0x7041
+#define OPTION_PRODUCT_ETNA_MODEM_EX 0x7061
+#define OPTION_PRODUCT_ETNA_NETWORK_LITE 0x7031
+#define OPTION_PRODUCT_ETNA_NETWORK_GT 0x7051
+#define OPTION_PRODUCT_ETNA_NETWORK_EX 0x7071
+#define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100
+#define OPTION_PRODUCT_ETNA_KOI_NETWORK 0x7111
+
+#define HUAWEI_VENDOR_ID 0x12D1
+#define HUAWEI_PRODUCT_E600 0x1001
+#define HUAWEI_PRODUCT_E220 0x1003
+
+#define NOVATELWIRELESS_VENDOR_ID 0x1410
+#define NOVATELWIRELESS_PRODUCT_U740 0x1400
+
+#define ANYDATA_VENDOR_ID 0x16d5
+#define ANYDATA_PRODUCT_ID 0x6501
static struct usb_device_id option_ids[] = {
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD_LIGHT) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_LIGHT) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA_BUS) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER_BUS) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX_READY) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_LIGHT) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_GT) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_EX) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_LIGHT) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_GT) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_EX) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_MODEM) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_NETWORK) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_MODEM) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_NETWORK) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_LITE) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_GT) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_EX) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_LITE) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_GT) },
+ { 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(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
{ } /* Terminating entry */
};
-
-static struct usb_device_id option_ids1[] = {
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
- { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
- { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
- { } /* Terminating entry */
-};
-
MODULE_DEVICE_TABLE(usb, option_ids);
static struct usb_driver option_driver = {
@@ -132,7 +177,7 @@ static struct usb_serial_driver option_1port_device = {
},
.description = "GSM modem (1-port)",
.usb_driver = &option_driver,
- .id_table = option_ids1,
+ .id_table = option_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 7e7ec29782f..8e898e3d861 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -55,7 +55,7 @@
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
-#include <linux/utsrelease.h>
+#include <linux/utsname.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -547,7 +547,7 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id)
idesc->bInterfaceSubClass,
idesc->bInterfaceProtocol,
msgs[msg],
- UTS_RELEASE);
+ utsname()->release);
}
return 0;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index c1536d78555..7f5a5983681 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -677,8 +677,6 @@ config FB_S1D13XXX
config FB_NVIDIA
tristate "nVidia Framebuffer Support"
depends on FB && PCI
- select I2C_ALGOBIT if FB_NVIDIA_I2C
- select I2C if FB_NVIDIA_I2C
select FB_BACKLIGHT if FB_NVIDIA_BACKLIGHT
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
@@ -697,6 +695,7 @@ config FB_NVIDIA
config FB_NVIDIA_I2C
bool "Enable DDC Support"
depends on FB_NVIDIA
+ select FB_DDC
help
This enables I2C support for nVidia Chipsets. This is used
only for getting EDID information from the attached display
@@ -716,7 +715,6 @@ config FB_NVIDIA_BACKLIGHT
config FB_RIVA
tristate "nVidia Riva support"
depends on FB && PCI
- select FB_DDC if FB_RIVA_I2C
select FB_BACKLIGHT if FB_RIVA_BACKLIGHT
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
@@ -734,6 +732,7 @@ config FB_RIVA
config FB_RIVA_I2C
bool "Enable DDC Support"
depends on FB_RIVA
+ select FB_DDC
help
This enables I2C support for nVidia Chipsets. This is used
only for getting EDID information from the attached display
@@ -812,8 +811,6 @@ config FB_INTEL
depends on FB && EXPERIMENTAL && PCI && X86
select AGP
select AGP_INTEL
- select I2C_ALGOBIT if FB_INTEL_I2C
- select I2C if FB_INTEL_I2C
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -846,6 +843,7 @@ config FB_INTEL_DEBUG
config FB_INTEL_I2C
bool "DDC/I2C for Intel framebuffer support"
depends on FB_INTEL
+ select FB_DDC
default y
help
Say Y here if you want DDC/I2C support for your on-board Intel graphics.
@@ -924,8 +922,8 @@ config FB_MATROX_G
config FB_MATROX_I2C
tristate "Matrox I2C support"
- depends on FB_MATROX && I2C
- select I2C_ALGOBIT
+ depends on FB_MATROX
+ select FB_DDC
---help---
This drivers creates I2C buses which are needed for accessing the
DDC (I2C) bus present on all Matroxes, an I2C bus which
@@ -993,7 +991,6 @@ config FB_MATROX_MULTIHEAD
config FB_RADEON
tristate "ATI Radeon display support"
depends on FB && PCI
- select FB_DDC if FB_RADEON_I2C
select FB_BACKLIGHT if FB_RADEON_BACKLIGHT
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
@@ -1018,6 +1015,7 @@ config FB_RADEON
config FB_RADEON_I2C
bool "DDC/I2C for ATI Radeon support"
depends on FB_RADEON
+ select FB_DDC
default y
help
Say Y here if you want DDC/I2C support for your Radeon board.
@@ -1125,7 +1123,6 @@ config FB_S3
config FB_SAVAGE
tristate "S3 Savage support"
depends on FB && PCI && EXPERIMENTAL
- select FB_DDC if FB_SAVAGE_I2C
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -1142,6 +1139,7 @@ config FB_SAVAGE
config FB_SAVAGE_I2C
bool "Enable DDC2 Support"
depends on FB_SAVAGE
+ select FB_DDC
help
This enables I2C support for S3 Savage Chipsets. This is used
only for getting EDID information from the attached display
@@ -1618,8 +1616,7 @@ config FB_IBM_GXT4500
config FB_PS3
bool "PS3 GPU framebuffer driver"
- depends on FB && PPC_PS3
- select PS3_PS3AV
+ depends on FB && PS3_PS3AV
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 8726c366971..e86d7e0c982 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -357,6 +357,12 @@ static int default_lcd_on __devinitdata = 1;
static int mtrr = 1;
#endif
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int backlight __devinitdata = 1;
+#else
+static int backlight __devinitdata = 0;
+#endif
+
/* PLL constants */
struct aty128_constants {
u32 ref_clk;
@@ -1652,6 +1658,9 @@ static int __devinit aty128fb_setup(char *options)
} else if (!strncmp(this_opt, "crt:", 4)) {
default_crt_on = simple_strtoul(this_opt+4, NULL, 0);
continue;
+ } else if (!strncmp(this_opt, "backlight:", 10)) {
+ backlight = simple_strtoul(this_opt+10, NULL, 0);
+ continue;
}
#ifdef CONFIG_MTRR
if(!strncmp(this_opt, "nomtrr", 6)) {
@@ -1985,7 +1994,8 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i
par->lock_blank = 0;
#ifdef CONFIG_FB_ATY128_BACKLIGHT
- aty128_bl_init(par);
+ if (backlight)
+ aty128_bl_init(par);
#endif
if (register_framebuffer(info) < 0)
diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
index f72faff33c0..dc62f8e282b 100644
--- a/drivers/video/aty/atyfb.h
+++ b/drivers/video/aty/atyfb.h
@@ -284,7 +284,8 @@ static inline void aty_st_8(int regindex, u8 val, const struct atyfb_par *par)
#endif
}
-#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD)
+#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || \
+defined (CONFIG_FB_ATY_GENERIC_LCD) || defined (CONFIG_FB_ATY_BACKLIGHT)
extern void aty_st_lcd(int index, u32 val, const struct atyfb_par *par);
extern u32 aty_ld_lcd(int index, const struct atyfb_par *par);
#endif
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index a7e0062233f..d7627fc4f11 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -131,7 +131,8 @@
#define PRINTKI(fmt, args...) printk(KERN_INFO "atyfb: " fmt, ## args)
#define PRINTKE(fmt, args...) printk(KERN_ERR "atyfb: " fmt, ## args)
-#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD)
+#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || \
+defined (CONFIG_FB_ATY_GENERIC_LCD) || defined(CONFIG_FB_ATY_BACKLIGHT)
static const u32 lt_lcd_regs[] = {
CONFIG_PANEL_LG,
LCD_GEN_CNTL_LG,
@@ -308,6 +309,12 @@ static int xclk;
static int comp_sync __devinitdata = -1;
static char *mode;
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int backlight __devinitdata = 1;
+#else
+static int backlight __devinitdata = 0;
+#endif
+
#ifdef CONFIG_PPC
static int default_vmode __devinitdata = VMODE_CHOOSE;
static int default_cmode __devinitdata = CMODE_CHOOSE;
@@ -2575,7 +2582,7 @@ static int __devinit aty_init(struct fb_info *info)
| (USE_F32KHZ | TRISTATE_MEM_EN), par);
} else
#endif
- if (M64_HAS(MOBIL_BUS)) {
+ if (M64_HAS(MOBIL_BUS) && backlight) {
#ifdef CONFIG_FB_ATY_BACKLIGHT
aty_bl_init (par);
#endif
@@ -3757,6 +3764,8 @@ static int __init atyfb_setup(char *options)
xclk = simple_strtoul(this_opt+5, NULL, 0);
else if (!strncmp(this_opt, "comp_sync:", 10))
comp_sync = simple_strtoul(this_opt+10, NULL, 0);
+ else if (!strncmp(this_opt, "backlight:", 10))
+ backlight = simple_strtoul(this_opt+10, NULL, 0);
#ifdef CONFIG_PPC
else if (!strncmp(this_opt, "vmode:", 6)) {
unsigned int vmode =
diff --git a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c
index f3b487b8710..1fdcfdbf669 100644
--- a/drivers/video/aty/mach64_ct.c
+++ b/drivers/video/aty/mach64_ct.c
@@ -598,7 +598,6 @@ static void aty_resume_pll_ct(const struct fb_info *info,
struct atyfb_par *par = info->par;
if (par->mclk_per != par->xclk_per) {
- int i;
/*
* This disables the sclk, crashes the computer as reported:
* aty_st_pll_ct(SPLL_CNTL2, 3, info);
@@ -614,7 +613,7 @@ static void aty_resume_pll_ct(const struct fb_info *info,
* helps for Rage Mobilities that sometimes crash when
* we switch to sclk. (Daniel Mantione, 13-05-2003)
*/
- for (i=0;i<=0x1ffff;i++);
+ udelay(500);
}
aty_st_pll_ct(PLL_REF_DIV, pll->ct.pll_ref_div, par);
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 7e228aded4c..1bf6f42eb40 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -268,6 +268,11 @@ static int nomtrr = 0;
#endif
static int force_sleep;
static int ignore_devlist;
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int backlight = 1;
+#else
+static int backlight = 0;
+#endif
/*
* prototypes
@@ -1026,8 +1031,7 @@ int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch)
break;
}
- /* let fbcon do a soft blank for us */
- return (blank == FB_BLANK_NORMAL) ? -EINVAL : 0;
+ return 0;
}
static int radeonfb_blank (int blank, struct fb_info *info)
@@ -2349,7 +2353,8 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
MTRR_TYPE_WRCOMB, 1);
#endif
- radeonfb_bl_init(rinfo);
+ if (backlight)
+ radeonfb_bl_init(rinfo);
printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name);
@@ -2470,6 +2475,8 @@ static int __init radeonfb_setup (char *options)
force_dfp = 1;
} else if (!strncmp(this_opt, "panel_yres:", 11)) {
panel_yres = simple_strtoul((this_opt+11), NULL, 0);
+ } else if (!strncmp(this_opt, "backlight:", 10)) {
+ backlight = simple_strtoul(this_opt+10, NULL, 0);
#ifdef CONFIG_MTRR
} else if (!strncmp(this_opt, "nomtrr", 6)) {
nomtrr = 1;
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
index b7016e9b9e1..43f62d8ee41 100644
--- a/drivers/video/nvidia/nv_backlight.c
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -12,6 +12,11 @@
#include <linux/backlight.h>
#include <linux/fb.h>
#include <linux/pci.h>
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
#include "nv_local.h"
#include "nv_type.h"
#include "nv_proto.h"
@@ -23,8 +28,6 @@
#define MAX_LEVEL 0x534
#define LEVEL_STEP ((MAX_LEVEL - MIN_LEVEL) / FB_BACKLIGHT_MAX)
-static struct backlight_properties nvidia_bl_data;
-
static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
int level)
{
@@ -119,7 +122,7 @@ void nvidia_bl_init(struct nvidia_par *par)
0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
- bd->props.brightness = nvidia_bl_data.max_brightness;
+ bd->props.brightness = bd->props.max_brightness;
bd->props.power = FB_BLANK_UNBLANK;
backlight_update_status(bd);
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index c18e9557ca3..b97ec690126 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -83,6 +83,11 @@ static int bpp __devinitdata = 8;
#ifdef CONFIG_MTRR
static int nomtrr __devinitdata = 0;
#endif
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int backlight __devinitdata = 1;
+#else
+static int backlight __devinitdata = 0;
+#endif
static char *mode_option __devinitdata = NULL;
@@ -1311,7 +1316,10 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
nvidia_save_vga(par, &par->SavedReg);
pci_set_drvdata(pd, info);
- nvidia_bl_init(par);
+
+ if (backlight)
+ nvidia_bl_init(par);
+
if (register_framebuffer(info) < 0) {
printk(KERN_ERR PFX "error registering nVidia framebuffer\n");
goto err_out_iounmap_fb;
@@ -1408,6 +1416,8 @@ static int __devinit nvidiafb_setup(char *options)
paneltweak = simple_strtoul(this_opt+11, NULL, 0);
} else if (!strncmp(this_opt, "vram:", 5)) {
vram = simple_strtoul(this_opt+5, NULL, 0);
+ } else if (!strncmp(this_opt, "backlight:", 10)) {
+ backlight = simple_strtoul(this_opt+10, NULL, 0);
#ifdef CONFIG_MTRR
} else if (!strncmp(this_opt, "nomtrr", 6)) {
nomtrr = 1;
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index f8a3d608b20..1d1c7c624d7 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -215,6 +215,11 @@ static int noaccel __devinitdata = 0;
#ifdef CONFIG_MTRR
static int nomtrr __devinitdata = 0;
#endif
+#ifdef CONFIG_PMAC_BACKLIGHT
+static int backlight __devinitdata = 1;
+#else
+static int backlight __devinitdata = 0;
+#endif
static char *mode_option __devinitdata = NULL;
static int strictmode = 0;
@@ -2059,7 +2064,10 @@ static int __devinit rivafb_probe(struct pci_dev *pd,
info->monspecs.modedb = NULL;
pci_set_drvdata(pd, info);
- riva_bl_init(info->par);
+
+ if (backlight)
+ riva_bl_init(info->par);
+
ret = register_framebuffer(info);
if (ret < 0) {
printk(KERN_ERR PFX
@@ -2157,6 +2165,8 @@ static int __init rivafb_setup(char *options)
forceCRTC = -1;
} else if (!strncmp(this_opt, "flatpanel", 9)) {
flatpanel = 1;
+ } else if (!strncmp(this_opt, "backlight:", 10)) {
+ backlight = simple_strtoul(this_opt+10, NULL, 0);
#ifdef CONFIG_MTRR
} else if (!strncmp(this_opt, "nomtrr", 6)) {
nomtrr = 1;
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c
index 3162c37b144..98919a6975f 100644
--- a/drivers/video/s3fb.c
+++ b/drivers/video/s3fb.c
@@ -1134,11 +1134,11 @@ static int __init s3fb_setup(char *options)
if (!*opt)
continue;
#ifdef CONFIG_MTRR
- else if (!strcmp(opt, "mtrr:"))
+ else if (!strncmp(opt, "mtrr:", 5))
mtrr = simple_strtoul(opt + 5, NULL, 0);
#endif
- else if (!strcmp(opt, "fasttext:"))
- mtrr = simple_strtoul(opt + 9, NULL, 0);
+ else if (!strncmp(opt, "fasttext:", 9))
+ fasttext = simple_strtoul(opt + 9, NULL, 0);
else
mode = opt;
}
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
index 02b290ca01e..0a44c44672c 100644
--- a/drivers/video/sm501fb.c
+++ b/drivers/video/sm501fb.c
@@ -136,8 +136,8 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info)
#define SM501_MEMF_CRT (4)
#define SM501_MEMF_ACCEL (8)
-int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
- unsigned int why, size_t size)
+static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
+ unsigned int why, size_t size)
{
unsigned int ptr = 0;
@@ -926,7 +926,7 @@ static int sm501fb_blank_crt(int blank_mode, struct fb_info *info)
* set or change the hardware cursor parameters
*/
-int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
struct sm501fb_par *par = info->par;
struct sm501fb_info *fbi = par->info;
@@ -1074,9 +1074,9 @@ static ssize_t sm501fb_crtsrc_store(struct device *dev,
if (len < 1)
return -EINVAL;
- if (strnicmp(buf, "crt", sizeof("crt")) == 0)
+ if (strnicmp(buf, "crt", 3) == 0)
head = HEAD_CRT;
- else if (strnicmp(buf, "panel", sizeof("panel")) == 0)
+ else if (strnicmp(buf, "panel", 5) == 0)
head = HEAD_PANEL;
else
return -EINVAL;
@@ -1098,7 +1098,7 @@ static ssize_t sm501fb_crtsrc_store(struct device *dev,
writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
sm501fb_sync_regs(info);
- return (head == HEAD_CRT) ? 3 : 5;
+ return len;
}
/* Prepare the device_attr for registration with sysfs later */
@@ -1225,7 +1225,7 @@ static struct sm501fb_info *sm501fb_info_alloc(struct fb_info *fbinfo_crt,
* initialise hw cursor parameters
*/
-int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base)
+static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base)
{
struct sm501fb_par *par = fbi->par;
struct sm501fb_info *info = par->info;
@@ -1768,7 +1768,7 @@ static struct platform_driver sm501fb_driver = {
},
};
-int __devinit sm501fb_init(void)
+static int __devinit sm501fb_init(void)
{
return platform_driver_register(&sm501fb_driver);
}