aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/processor_idle.c37
-rw-r--r--drivers/block/amiflop.c1
-rw-r--r--drivers/block/floppy.c9
-rw-r--r--drivers/block/pktcdvd.c3
-rw-r--r--drivers/bluetooth/bpa10x.c4
-rw-r--r--drivers/bluetooth/hci_usb.c7
-rw-r--r--drivers/char/agp/backend.c9
-rw-r--r--drivers/char/agp/generic.c9
-rw-r--r--drivers/char/agp/i460-agp.c17
-rw-r--r--drivers/char/agp/intel-agp.c5
-rw-r--r--drivers/char/drm/ati_pcigart.c4
-rw-r--r--drivers/char/ip2.c1
-rw-r--r--drivers/char/mwave/tp3780i.c1
-rw-r--r--drivers/char/mxser.c1
-rw-r--r--drivers/char/specialix.c1
-rw-r--r--drivers/char/sysrq.c4
-rw-r--r--drivers/char/tpm/tpm.h1
-rw-r--r--drivers/char/viocons.c1
-rw-r--r--drivers/char/viotape.c1
-rw-r--r--drivers/cpufreq/cpufreq.c24
-rw-r--r--drivers/firmware/dell_rbu.c1
-rw-r--r--drivers/hwmon/w83627hf.c16
-rw-r--r--drivers/i2c/busses/i2c-viapro.c27
-rw-r--r--drivers/i2c/chips/ds1337.c4
-rw-r--r--drivers/ide/Kconfig9
-rw-r--r--drivers/ide/ide-floppy.c6
-rw-r--r--drivers/ide/ide-iops.c6
-rw-r--r--drivers/ide/ide-taskfile.c2
-rw-r--r--drivers/ide/ide.c1
-rw-r--r--drivers/ide/legacy/ide-cs.c7
-rw-r--r--drivers/ide/pci/Makefile1
-rw-r--r--drivers/ide/pci/amd74xx.c3
-rw-r--r--drivers/ide/pci/cs5535.c305
-rw-r--r--drivers/ide/pci/cy82c693.c2
-rw-r--r--drivers/ide/pci/siimage.c9
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c1
-rw-r--r--drivers/input/input.c2
-rw-r--r--drivers/isdn/divert/divert_init.c1
-rw-r--r--drivers/isdn/divert/divert_procfs.c1
-rw-r--r--drivers/isdn/divert/isdn_divert.c1
-rw-r--r--drivers/isdn/hisax/hisax_fcpcipnp.c1
-rw-r--r--drivers/isdn/hisax/st5481_init.c1
-rw-r--r--drivers/isdn/hysdn/hycapi.c1
-rw-r--r--drivers/isdn/hysdn/hysdn_init.c1
-rw-r--r--drivers/isdn/hysdn/hysdn_net.c1
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c1
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c1
-rw-r--r--drivers/isdn/i4l/isdn_common.c1
-rw-r--r--drivers/isdn/icn/icn.h1
-rw-r--r--drivers/isdn/isdnloop/isdnloop.h1
-rw-r--r--drivers/isdn/sc/includes.h1
-rw-r--r--drivers/md/bitmap.c34
-rw-r--r--drivers/md/md.c636
-rw-r--r--drivers/md/multipath.c31
-rw-r--r--drivers/md/raid1.c216
-rw-r--r--drivers/md/raid10.c63
-rw-r--r--drivers/md/raid5.c261
-rw-r--r--drivers/md/raid6main.c40
-rw-r--r--drivers/media/common/ir-common.c4
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c54
-rw-r--r--drivers/media/dvb/b2c2/flexcop-misc.c1
-rw-r--r--drivers/media/dvb/b2c2/flexcop-reg.h1
-rw-r--r--drivers/media/dvb/b2c2/flexcop.c1
-rw-r--r--drivers/media/dvb/bt8xx/Kconfig4
-rw-r--r--drivers/media/dvb/bt8xx/dst.c136
-rw-r--r--drivers/media/dvb/bt8xx/dst_ca.c123
-rw-r--r--drivers/media/dvb/bt8xx/dst_common.h5
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.c114
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.h1
-rw-r--r--drivers/media/dvb/dvb-core/demux.h5
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c2
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c118
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h3
-rw-r--r--drivers/media/dvb/dvb-usb/a800.c4
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mb.c59
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb.h4
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h5
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-urb.c4
-rw-r--r--drivers/media/dvb/frontends/Kconfig8
-rw-r--r--drivers/media/dvb/frontends/Makefile1
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c54
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h4
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.c26
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.h4
-rw-r--r--drivers/media/dvb/frontends/nxt200x.c1205
-rw-r--r--drivers/media/dvb/frontends/nxt200x.h61
-rw-r--r--drivers/media/dvb/frontends/or51132.c7
-rw-r--r--drivers/media/dvb/frontends/or51211.c8
-rw-r--r--drivers/media/dvb/frontends/stv0299.c100
-rw-r--r--drivers/media/dvb/frontends/stv0299.h3
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c21
-rw-r--r--drivers/media/dvb/pluto2/pluto2.c9
-rw-r--r--drivers/media/dvb/ttpci/av7110.c6
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c4
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c4
-rw-r--r--drivers/media/dvb/ttpci/budget-patch.c3
-rw-r--r--drivers/media/dvb/ttpci/budget.c120
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c5
-rw-r--r--drivers/media/video/Kconfig63
-rw-r--r--drivers/media/video/Makefile5
-rw-r--r--drivers/media/video/arv.c1
-rw-r--r--drivers/media/video/bt832.c89
-rw-r--r--drivers/media/video/bt832.h4
-rw-r--r--drivers/media/video/bttv-cards.c5307
-rw-r--r--drivers/media/video/bttv-driver.c379
-rw-r--r--drivers/media/video/bttv-gpio.c2
-rw-r--r--drivers/media/video/bttv-i2c.c61
-rw-r--r--drivers/media/video/bttv-if.c4
-rw-r--r--drivers/media/video/bttv-risc.c110
-rw-r--r--drivers/media/video/bttv.h282
-rw-r--r--drivers/media/video/bttvp.h14
-rw-r--r--drivers/media/video/cs53l32a.c240
-rw-r--r--drivers/media/video/cx88/Kconfig91
-rw-r--r--drivers/media/video/cx88/Makefile6
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c677
-rw-r--r--drivers/media/video/cx88/cx88-cards.c474
-rw-r--r--drivers/media/video/cx88/cx88-core.c55
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c59
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c22
-rw-r--r--drivers/media/video/cx88/cx88-input.c2
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c25
-rw-r--r--drivers/media/video/cx88/cx88-reg.h12
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c1184
-rw-r--r--drivers/media/video/cx88/cx88-video.c38
-rw-r--r--drivers/media/video/cx88/cx88.h55
-rw-r--r--drivers/media/video/em28xx/Kconfig12
-rw-r--r--drivers/media/video/em28xx/Makefile6
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c292
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c817
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c586
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c184
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c1933
-rw-r--r--drivers/media/video/em28xx/em28xx.h513
-rw-r--r--drivers/media/video/ir-kbd-gpio.c99
-rw-r--r--drivers/media/video/ir-kbd-i2c.c166
-rw-r--r--drivers/media/video/msp3400.c962
-rw-r--r--drivers/media/video/mt20xx.c206
-rw-r--r--drivers/media/video/saa6588.c11
-rw-r--r--drivers/media/video/saa711x.c593
-rw-r--r--drivers/media/video/saa7134/Kconfig68
-rw-r--r--drivers/media/video/saa7134/Makefile9
-rw-r--r--drivers/media/video/saa7134/saa6752hs.c187
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c1047
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c587
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c120
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c370
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c6
-rw-r--r--drivers/media/video/saa7134/saa7134-i2c.c28
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c403
-rw-r--r--drivers/media/video/saa7134/saa7134-oss.c375
-rw-r--r--drivers/media/video/saa7134/saa7134-reg.h27
-rw-r--r--drivers/media/video/saa7134/saa7134-ts.c29
-rw-r--r--drivers/media/video/saa7134/saa7134-tvaudio.c23
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c185
-rw-r--r--drivers/media/video/saa7134/saa7134.h62
-rw-r--r--drivers/media/video/tda7432.c17
-rw-r--r--drivers/media/video/tda8290.c681
-rw-r--r--drivers/media/video/tda9875.c57
-rw-r--r--drivers/media/video/tda9887.c163
-rw-r--r--drivers/media/video/tea5767.c8
-rw-r--r--drivers/media/video/tuner-core.c74
-rw-r--r--drivers/media/video/tuner-simple.c143
-rw-r--r--drivers/media/video/tvaudio.c23
-rw-r--r--drivers/media/video/tveeprom.c458
-rw-r--r--drivers/media/video/tvmixer.c54
-rw-r--r--drivers/media/video/tvp5150.c829
-rw-r--r--drivers/media/video/tvp5150_reg.h173
-rw-r--r--drivers/media/video/v4l1-compat.c6
-rw-r--r--drivers/media/video/video-buf.c18
-rw-r--r--drivers/media/video/wm8775.c254
-rw-r--r--drivers/media/video/zr36016.c1
-rw-r--r--drivers/media/video/zr36050.c1
-rw-r--r--drivers/media/video/zr36060.c1
-rw-r--r--drivers/message/fusion/mptbase.c7
-rw-r--r--drivers/message/fusion/mptbase.h3
-rw-r--r--drivers/message/fusion/mptctl.c1
-rw-r--r--drivers/message/fusion/mptctl.h1
-rw-r--r--drivers/message/fusion/mptlan.h1
-rw-r--r--drivers/misc/hdpuftrs/hdpu_cpustate.c1
-rw-r--r--drivers/misc/hdpuftrs/hdpu_nexus.c1
-rw-r--r--drivers/misc/ibmasm/ibmasm.h1
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0020.c1
-rw-r--r--drivers/mtd/devices/pmc551.c1
-rw-r--r--drivers/mtd/maps/ebony.c1
-rw-r--r--drivers/mtd/maps/ocotea.c1
-rw-r--r--drivers/mtd/maps/walnut.c1
-rw-r--r--drivers/mtd/nand/au1550nd.c1
-rw-r--r--drivers/mtd/nand/autcpu12.c1
-rw-r--r--drivers/mtd/onenand/onenand_base.c2
-rw-r--r--drivers/mtd/rfd_ftl.c1
-rw-r--r--drivers/net/Kconfig15
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/b44.c178
-rw-r--r--drivers/net/b44.h75
-rw-r--r--drivers/net/bonding/bond_main.c32
-rw-r--r--drivers/net/bonding/bonding.h7
-rw-r--r--drivers/net/cassini.c1
-rw-r--r--drivers/net/cris/eth_v10.c149
-rw-r--r--drivers/net/dgrs.c16
-rw-r--r--drivers/net/dm9000.c1
-rw-r--r--drivers/net/e100.c6
-rw-r--r--drivers/net/fs_enet/fs_enet.h1
-rw-r--r--drivers/net/gianfar.c1
-rw-r--r--drivers/net/gianfar.h1
-rw-r--r--drivers/net/gianfar_ethtool.c1
-rw-r--r--drivers/net/gianfar_mii.c1
-rw-r--r--drivers/net/hp100.c1
-rw-r--r--drivers/net/ibmveth.c1
-rw-r--r--drivers/net/ioc3-eth.c42
-rw-r--r--drivers/net/irda/donauboe.c14
-rw-r--r--drivers/net/iseries_veth.c1
-rw-r--r--drivers/net/mac8390.c1
-rw-r--r--drivers/net/mv643xx_eth.h1
-rw-r--r--drivers/net/ns83820.c13
-rw-r--r--drivers/net/ppp_async.c17
-rw-r--r--drivers/net/ppp_generic.c88
-rw-r--r--drivers/net/ppp_mppe.c724
-rw-r--r--drivers/net/ppp_mppe.h86
-rw-r--r--drivers/net/s2io.c44
-rw-r--r--drivers/net/sk98lin/h/skdrv1st.h3
-rw-r--r--drivers/net/sk_mca.c1
-rw-r--r--drivers/net/sk_mca.h2
-rw-r--r--drivers/net/skge.c267
-rw-r--r--drivers/net/skge.h2
-rw-r--r--drivers/net/starfire.c1
-rw-r--r--drivers/net/via-velocity.c1
-rw-r--r--drivers/net/wireless/airo.c36
-rw-r--r--drivers/net/wireless/airo_cs.c6
-rw-r--r--drivers/net/wireless/atmel.c2
-rw-r--r--drivers/net/wireless/atmel_cs.c6
-rw-r--r--drivers/net/wireless/hostap/hostap.c1
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c1
-rw-r--r--drivers/net/wireless/hostap/hostap_pci.c1
-rw-r--r--drivers/net/wireless/hostap/hostap_plx.c1
-rw-r--r--drivers/net/wireless/ipw2100.c2858
-rw-r--r--drivers/net/wireless/ipw2100.h170
-rw-r--r--drivers/net/wireless/ipw2200.c6610
-rw-r--r--drivers/net/wireless/ipw2200.h575
-rw-r--r--drivers/net/wireless/orinoco.h1
-rw-r--r--drivers/net/wireless/prism54/isl_38xx.c13
-rw-r--r--drivers/net/wireless/prism54/isl_38xx.h1
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c1
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c1
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.h1
-rw-r--r--drivers/net/wireless/prism54/islpci_eth.c11
-rw-r--r--drivers/net/wireless/prism54/islpci_hotplug.c1
-rw-r--r--drivers/net/wireless/wavelan_cs.c3
-rw-r--r--drivers/net/wireless/wl3501_cs.c3
-rw-r--r--drivers/pcmcia/au1000_pb1x00.c1
-rw-r--r--drivers/pcmcia/au1000_xxs1500.c1
-rw-r--r--drivers/pcmcia/pxa2xx_sharpsl.c140
-rw-r--r--drivers/s390/char/keyboard.h4
-rw-r--r--drivers/s390/cio/qdio.h8
-rw-r--r--drivers/s390/crypto/z90main.c1
-rw-r--r--drivers/s390/net/claw.c1
-rw-r--r--drivers/s390/net/fsm.h6
-rw-r--r--drivers/s390/s390mach.h2
-rw-r--r--drivers/sbus/char/cpwatchdog.c2
-rw-r--r--drivers/sbus/char/display7seg.c2
-rw-r--r--drivers/sbus/char/openprom.c3
-rw-r--r--drivers/sbus/char/rtc.c22
-rw-r--r--drivers/scsi/3w-xxxx.h1
-rw-r--r--drivers/scsi/a2091.c1
-rw-r--r--drivers/scsi/ahci.c2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h1
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.h1
-rw-r--r--drivers/scsi/amiga7xx.c1
-rw-r--r--drivers/scsi/ata_piix.c1
-rw-r--r--drivers/scsi/bvme6000.c1
-rw-r--r--drivers/scsi/gvp11.c1
-rw-r--r--drivers/scsi/ibmmca.c6
-rw-r--r--drivers/scsi/ips.h1
-rw-r--r--drivers/scsi/libata-core.c11
-rw-r--r--drivers/scsi/libata-scsi.c9
-rw-r--r--drivers/scsi/megaraid/mega_common.h1
-rw-r--r--drivers/scsi/megaraid/megaraid_mm.h1
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c1
-rw-r--r--drivers/scsi/mvme147.c1
-rw-r--r--drivers/scsi/mvme16x.c1
-rw-r--r--drivers/scsi/nsp32.h1
-rw-r--r--drivers/scsi/pci2000.h3
-rw-r--r--drivers/scsi/pdc_adma.c1
-rw-r--r--drivers/scsi/sata_mv.c2
-rw-r--r--drivers/scsi/sata_nv.c1
-rw-r--r--drivers/scsi/sata_promise.c2
-rw-r--r--drivers/scsi/sata_qstor.c1
-rw-r--r--drivers/scsi/sata_sil.c1
-rw-r--r--drivers/scsi/sata_sil24.c2
-rw-r--r--drivers/scsi/sata_sis.c1
-rw-r--r--drivers/scsi/sata_svw.c1
-rw-r--r--drivers/scsi/sata_sx4.c2
-rw-r--r--drivers/scsi/sata_uli.c1
-rw-r--r--drivers/scsi/sata_via.c1
-rw-r--r--drivers/scsi/sata_vsc.c1
-rw-r--r--drivers/scsi/scsi_debug.c4
-rw-r--r--drivers/scsi/sg.c4
-rw-r--r--drivers/scsi/sgiwd93.c1
-rw-r--r--drivers/scsi/wd33c93.c1
-rw-r--r--drivers/telephony/ixj.h1
-rw-r--r--drivers/usb/gadget/dummy_hcd.c1
-rw-r--r--drivers/usb/gadget/lh7a40x_udc.h1
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c1
-rw-r--r--drivers/usb/gadget/rndis.c1
-rw-r--r--drivers/usb/host/hc_crisv10.c1
-rw-r--r--drivers/usb/media/pwc/pwc-if.c1
-rw-r--r--drivers/usb/media/pwc/pwc.h2
-rw-r--r--drivers/usb/media/w9968cf.c1
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c1
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.h1
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_con.c1
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_init.c1
-rw-r--r--drivers/video/Kconfig32
-rw-r--r--drivers/video/amba-clcd.c2
-rw-r--r--drivers/video/backlight/backlight.c1
-rw-r--r--drivers/video/backlight/lcd.c1
-rw-r--r--drivers/video/cfbimgblt.c4
-rw-r--r--drivers/video/console/Kconfig10
-rw-r--r--drivers/video/console/Makefile4
-rw-r--r--drivers/video/console/bitblit.c46
-rw-r--r--drivers/video/console/fbcon.c375
-rw-r--r--drivers/video/console/fbcon.h62
-rw-r--r--drivers/video/console/fbcon_ccw.c428
-rw-r--r--drivers/video/console/fbcon_cw.c412
-rw-r--r--drivers/video/console/fbcon_rotate.c117
-rw-r--r--drivers/video/console/fbcon_rotate.h105
-rw-r--r--drivers/video/console/fbcon_ud.c454
-rw-r--r--drivers/video/console/tileblit.c13
-rw-r--r--drivers/video/fbmem.c299
-rw-r--r--drivers/video/fbsysfs.c67
-rw-r--r--drivers/video/intelfb/intelfbdrv.c1
-rw-r--r--drivers/video/intelfb/intelfbhw.c1
-rw-r--r--drivers/video/modedb.c4
-rw-r--r--drivers/video/savage/savagefb_driver.c10
-rw-r--r--drivers/video/vga16fb.c169
-rw-r--r--drivers/video/vgastate.c5
335 files changed, 31203 insertions, 10090 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 161db4acfb9..573b6a97bb1 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -167,6 +167,19 @@ acpi_processor_power_activate(struct acpi_processor *pr,
return;
}
+static void acpi_safe_halt(void)
+{
+ int polling = test_thread_flag(TIF_POLLING_NRFLAG);
+ if (polling) {
+ clear_thread_flag(TIF_POLLING_NRFLAG);
+ smp_mb__after_clear_bit();
+ }
+ if (!need_resched())
+ safe_halt();
+ if (polling)
+ set_thread_flag(TIF_POLLING_NRFLAG);
+}
+
static atomic_t c3_cpu_count;
static void acpi_processor_idle(void)
@@ -177,7 +190,7 @@ static void acpi_processor_idle(void)
int sleep_ticks = 0;
u32 t1, t2 = 0;
- pr = processors[raw_smp_processor_id()];
+ pr = processors[smp_processor_id()];
if (!pr)
return;
@@ -197,8 +210,13 @@ static void acpi_processor_idle(void)
}
cx = pr->power.state;
- if (!cx)
- goto easy_out;
+ if (!cx) {
+ if (pm_idle_save)
+ pm_idle_save();
+ else
+ acpi_safe_halt();
+ return;
+ }
/*
* Check BM Activity
@@ -278,7 +296,8 @@ static void acpi_processor_idle(void)
if (pm_idle_save)
pm_idle_save();
else
- safe_halt();
+ acpi_safe_halt();
+
/*
* TBD: Can't get time duration while in C1, as resumes
* go to an ISR rather than here. Need to instrument
@@ -414,16 +433,6 @@ static void acpi_processor_idle(void)
*/
if (next_state != pr->power.state)
acpi_processor_power_activate(pr, next_state);
-
- return;
-
- easy_out:
- /* do C1 instead of busy loop */
- if (pm_idle_save)
- pm_idle_save();
- else
- safe_halt();
- return;
}
static int acpi_processor_set_power_policy(struct acpi_processor *pr)
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 1468e8cf712..0acbfff8ad2 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -1816,7 +1816,6 @@ out_blkdev:
}
#ifdef MODULE
-#include <linux/version.h>
int init_module(void)
{
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 5eadbb9d4d7..28002de783b 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3714,6 +3714,12 @@ static int floppy_open(struct inode *inode, struct file *filp)
USETF(FD_VERIFY);
}
+ /* set underlying gendisk policy to reflect real ro/rw status */
+ if (UTESTF(FD_DISK_WRITABLE))
+ inode->i_bdev->bd_disk->policy = 0;
+ else
+ inode->i_bdev->bd_disk->policy = 1;
+
if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (filp->f_flags & O_EXCL)))
goto out2;
@@ -3770,8 +3776,7 @@ static int floppy_open(struct inode *inode, struct file *filp)
/* Allow ioctls if we have write-permissions even if read-only open.
* Needed so that programs such as fdrawcmd still can work on write
* protected disks */
- if (filp->f_mode & 2
- || permission(filp->f_dentry->d_inode, 2, NULL) == 0)
+ if ((filp->f_mode & FMODE_WRITE) || !file_permission(filp, MAY_WRITE))
filp->private_data = (void *)8;
if (UFDCS->rawcmd == 1)
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index a280e679b1c..59e5982a5db 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -511,14 +511,11 @@ static void pkt_queue_bio(struct pktcdvd_device *pd, struct bio *bio)
*/
static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
{
- request_queue_t *q;
if (atomic_read(&pd->iosched.attention) == 0)
return;
atomic_set(&pd->iosched.attention, 0);
- q = bdev_get_queue(pd->bdev);
-
for (;;) {
struct bio *bio;
int reads_queued, writes_queued;
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index ecbeb7eaba8..394796315ad 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -84,8 +84,8 @@ struct bpa10x_data {
struct hci_vendor_hdr {
__u8 type;
- __u16 snum;
- __u16 dlen;
+ __le16 snum;
+ __le16 dlen;
} __attribute__ ((packed));
static void bpa10x_recv_bulk(struct bpa10x_data *data, unsigned char *buf, int count)
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
index f510b25b2c5..057cb2b6e6d 100644
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -65,6 +65,7 @@
#endif
static int ignore = 0;
+static int ignore_dga = 0;
static int ignore_csr = 0;
static int ignore_sniffer = 0;
static int reset = 0;
@@ -841,6 +842,9 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id
if (ignore || id->driver_info & HCI_IGNORE)
return -ENODEV;
+ if (ignore_dga && id->driver_info & HCI_DIGIANSWER)
+ return -ENODEV;
+
if (ignore_csr && id->driver_info & HCI_CSR)
return -ENODEV;
@@ -1070,6 +1074,9 @@ module_exit(hci_usb_exit);
module_param(ignore, bool, 0644);
MODULE_PARM_DESC(ignore, "Ignore devices from the matching table");
+module_param(ignore_dga, bool, 0644);
+MODULE_PARM_DESC(ignore_dga, "Ignore devices with id 08fd:0001");
+
module_param(ignore_csr, bool, 0644);
MODULE_PARM_DESC(ignore_csr, "Ignore devices with id 0a12:0001");
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index 73f333f491b..27bca34b4a6 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -147,6 +147,7 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
printk(KERN_ERR PFX "unable to get memory for scratch page.\n");
return -ENOMEM;
}
+ flush_agp_mappings();
bridge->scratch_page_real = virt_to_gart(addr);
bridge->scratch_page =
@@ -187,9 +188,11 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
return 0;
err_out:
- if (bridge->driver->needs_scratch_page)
+ if (bridge->driver->needs_scratch_page) {
bridge->driver->agp_destroy_page(
gart_to_virt(bridge->scratch_page_real));
+ flush_agp_mappings();
+ }
if (got_gatt)
bridge->driver->free_gatt_table(bridge);
if (got_keylist) {
@@ -211,9 +214,11 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge)
bridge->key_list = NULL;
if (bridge->driver->agp_destroy_page &&
- bridge->driver->needs_scratch_page)
+ bridge->driver->needs_scratch_page) {
bridge->driver->agp_destroy_page(
gart_to_virt(bridge->scratch_page_real));
+ flush_agp_mappings();
+ }
}
/* When we remove the global variable agp_bridge from all drivers
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index c4a38715c6f..5567ce8d72b 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -57,7 +57,8 @@ int map_page_into_agp(struct page *page)
{
int i;
i = change_page_attr(page, 1, PAGE_KERNEL_NOCACHE);
- global_flush_tlb();
+ /* Caller's responsibility to call global_flush_tlb() for
+ * performance reasons */
return i;
}
EXPORT_SYMBOL_GPL(map_page_into_agp);
@@ -66,7 +67,8 @@ int unmap_page_from_agp(struct page *page)
{
int i;
i = change_page_attr(page, 1, PAGE_KERNEL);
- global_flush_tlb();
+ /* Caller's responsibility to call global_flush_tlb() for
+ * performance reasons */
return i;
}
EXPORT_SYMBOL_GPL(unmap_page_from_agp);
@@ -153,6 +155,7 @@ void agp_free_memory(struct agp_memory *curr)
for (i = 0; i < curr->page_count; i++) {
curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]));
}
+ flush_agp_mappings();
}
agp_free_key(curr->key);
vfree(curr->memory);
@@ -210,7 +213,7 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge,
new->memory[i] = virt_to_gart(addr);
new->page_count++;
}
- new->bridge = bridge;
+ new->bridge = bridge;
flush_agp_mappings();
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index 58944cd271e..34a444658ff 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -111,8 +111,10 @@ static int i460_fetch_size (void)
if (i460.io_page_shift != I460_IO_PAGE_SHIFT) {
printk(KERN_ERR PFX
- "I/O (GART) page-size %ZuKB doesn't match expected size %ZuKB\n",
- 1UL << (i460.io_page_shift - 10), 1UL << (I460_IO_PAGE_SHIFT));
+ "I/O (GART) page-size %luKB doesn't match expected "
+ "size %luKB\n",
+ 1UL << (i460.io_page_shift - 10),
+ 1UL << (I460_IO_PAGE_SHIFT));
return 0;
}
@@ -514,9 +516,10 @@ static void *i460_alloc_page (struct agp_bridge_data *bridge)
{
void *page;
- if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT)
+ if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) {
page = agp_generic_alloc_page(agp_bridge);
- else
+ global_flush_tlb();
+ } else
/* Returning NULL would cause problems */
/* AK: really dubious code. */
page = (void *)~0UL;
@@ -525,8 +528,10 @@ static void *i460_alloc_page (struct agp_bridge_data *bridge)
static void i460_destroy_page (void *page)
{
- if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT)
+ if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) {
agp_generic_destroy_page(page);
+ global_flush_tlb();
+ }
}
#endif /* I460_LARGE_IO_PAGES */
@@ -536,7 +541,7 @@ static unsigned long i460_mask_memory (struct agp_bridge_data *bridge,
{
/* Make sure the returned address is a valid GATT entry */
return bridge->driver->masks[0].mask
- | (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xffffff000) >> 12);
+ | (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xfffff000) >> 12);
}
struct agp_bridge_driver intel_i460_driver = {
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index bf4cc9ffd5b..027161ab88e 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -270,6 +270,7 @@ static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
switch (pg_count) {
case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge);
+ global_flush_tlb();
break;
case 4:
/* kludge to get 4 physical pages for ARGB cursor */
@@ -330,9 +331,11 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
if(curr->type == AGP_PHYS_MEMORY) {
if (curr->page_count == 4)
i8xx_destroy_pages(gart_to_virt(curr->memory[0]));
- else
+ else {
agp_bridge->driver->agp_destroy_page(
gart_to_virt(curr->memory[0]));
+ global_flush_tlb();
+ }
vfree(curr->memory);
}
kfree(curr);
diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c
index 6d3fec160bf..efff0eec618 100644
--- a/drivers/char/drm/ati_pcigart.c
+++ b/drivers/char/drm/ati_pcigart.c
@@ -203,10 +203,10 @@ int drm_ati_pcigart_init(drm_device_t * dev, drm_ati_pcigart_info * gart_info)
for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
if (gart_info->is_pcie)
- *pci_gart = (cpu_to_le32(page_base) >> 8) | 0xc;
+ *pci_gart = cpu_to_le32((page_base >> 8) | 0xc);
else
*pci_gart = cpu_to_le32(page_base);
- *pci_gart++;
+ pci_gart++;
page_base += ATI_PCIGART_PAGE_SIZE;
}
}
diff --git a/drivers/char/ip2.c b/drivers/char/ip2.c
index 6cd12f23aa5..7cadfc6ef35 100644
--- a/drivers/char/ip2.c
+++ b/drivers/char/ip2.c
@@ -7,7 +7,6 @@
//
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/wait.h>
diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c
index d6c72e0934e..cc3e54dd723 100644
--- a/drivers/char/mwave/tp3780i.c
+++ b/drivers/char/mwave/tp3780i.c
@@ -46,7 +46,6 @@
* First release to the public
*/
-#include <linux/version.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 3b965a651da..26448f17680 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -38,7 +38,6 @@
#include <linux/config.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/autoconf.h>
#include <linux/errno.h>
#include <linux/signal.h>
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 352547eabf7..0bbfce43031 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -90,7 +90,6 @@
#include <linux/fcntl.h>
#include <linux/major.h>
#include <linux/delay.h>
-#include <linux/version.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <asm/uaccess.h>
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index feb25158c8e..145275ebdd7 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -354,7 +354,7 @@ struct sysrq_key_op *__sysrq_get_key_op (int key) {
return op_p;
}
-void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) {
+static void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) {
int i;
i = sysrq_key_table_key2index(key);
@@ -419,7 +419,7 @@ void handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
__handle_sysrq(key, pt_regs, tty, 1);
}
-int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
+static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
struct sysrq_key_op *remove_op_p) {
int retval;
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 99a60496ecc..9293bcc4dc6 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -19,7 +19,6 @@
*
*/
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/fs.h>
diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c
index 98601c7d04a..4d75c261f98 100644
--- a/drivers/char/viocons.c
+++ b/drivers/char/viocons.c
@@ -26,7 +26,6 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/config.h>
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/errno.h>
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index 867cc4e418c..60aabdb4a04 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -32,7 +32,6 @@
* iseries/vio.h
*/
#include <linux/config.h>
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 25acf478c9e..23a63207d74 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -38,7 +38,6 @@ static struct cpufreq_driver *cpufreq_driver;
static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS];
static DEFINE_SPINLOCK(cpufreq_driver_lock);
-
/* internal prototypes */
static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
static void handle_update(void *data);
@@ -1115,24 +1114,21 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
int retval = -EINVAL;
/*
- * Converted the lock_cpu_hotplug to preempt_disable()
- * and preempt_enable(). This is a bit kludgy and relies on how cpu
- * hotplug works. All we need is a guarantee that cpu hotplug won't make
- * progress on any cpu. Once we do preempt_disable(), this would ensure
- * that hotplug threads don't get onto this cpu, thereby delaying
- * the cpu remove process.
- *
- * We removed the lock_cpu_hotplug since we need to call this function
- * via cpu hotplug callbacks, which result in locking the cpu hotplug
- * thread itself. Agree this is not very clean, cpufreq community
- * could improve this if required. - Ashok Raj <ashok.raj@intel.com>
+ * If we are already in context of hotplug thread, we dont need to
+ * acquire the hotplug lock. Otherwise acquire cpucontrol to prevent
+ * hotplug from removing this cpu that we are working on.
*/
- preempt_disable();
+ if (!current_in_cpu_hotplug())
+ lock_cpu_hotplug();
+
dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
target_freq, relation);
if (cpu_online(policy->cpu) && cpufreq_driver->target)
retval = cpufreq_driver->target(policy, target_freq, relation);
- preempt_enable();
+
+ if (!current_in_cpu_hotplug())
+ unlock_cpu_hotplug();
+
return retval;
}
EXPORT_SYMBOL_GPL(__cpufreq_driver_target);
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c
index ba17292eb29..6d83299e7c9 100644
--- a/drivers/firmware/dell_rbu.c
+++ b/drivers/firmware/dell_rbu.c
@@ -34,7 +34,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-#include <linux/version.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 70ef926c3bd..4e9a04e1f08 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -180,11 +180,10 @@ superio_exit(void)
#define W83781D_REG_BANK 0x4E
#define W83781D_REG_CONFIG 0x40
-#define W83781D_REG_ALARM1 0x41
-#define W83781D_REG_ALARM2 0x42
-#define W83781D_REG_ALARM3 0x450
+#define W83781D_REG_ALARM1 0x459
+#define W83781D_REG_ALARM2 0x45A
+#define W83781D_REG_ALARM3 0x45B
-#define W83781D_REG_IRQ 0x4C
#define W83781D_REG_BEEP_CONFIG 0x4D
#define W83781D_REG_BEEP_INTS1 0x56
#define W83781D_REG_BEEP_INTS2 0x57
@@ -1370,13 +1369,6 @@ static void w83627hf_init_client(struct i2c_client *client)
W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
}
}
-
- /* enable comparator mode for temp2 and temp3 so
- alarm indication will work correctly */
- i = w83627hf_read_value(client, W83781D_REG_IRQ);
- if (!(i & 0x40))
- w83627hf_write_value(client, W83781D_REG_IRQ,
- i | 0x40);
}
/* Start monitoring */
@@ -1400,7 +1392,7 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
/* skip missing sensors */
if (((data->type == w83697hf) && (i == 1)) ||
((data->type == w83627thf || data->type == w83637hf)
- && (i == 4 || i == 5)))
+ && (i == 5 || i == 6)))
continue;
data->in[i] =
w83627hf_read_value(client, W83781D_REG_IN(i));
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index c9366b50483..a2237d4b2cf 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -142,19 +142,18 @@ static int vt596_transaction(u8 size)
/* Make sure the SMBus host is ready to start transmitting */
if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
dev_dbg(&vt596_adapter.dev, "SMBus busy (0x%02x). "
- "Resetting... ", temp);
+ "Resetting...\n", temp);
outb_p(temp, SMBHSTSTS);
if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
- printk("Failed! (0x%02x)\n", temp);
+ dev_err(&vt596_adapter.dev, "SMBus reset failed! "
+ "(0x%02x)\n", temp);
return -1;
- } else {
- printk("Successful!\n");
}
}
/* Start the transaction by setting bit 6 */
- outb_p(0x40 | (size & 0x3C), SMBHSTCNT);
+ outb_p(0x40 | size, SMBHSTCNT);
/* We will always wait for a fraction of a second */
do {
@@ -171,7 +170,7 @@ static int vt596_transaction(u8 size)
if (temp & 0x10) {
result = -1;
dev_err(&vt596_adapter.dev, "Transaction failed (0x%02x)\n",
- inb_p(SMBHSTCNT) & 0x3C);
+ size);
}
if (temp & 0x08) {
@@ -180,11 +179,13 @@ static int vt596_transaction(u8 size)
}
if (temp & 0x04) {
+ int read = inb_p(SMBHSTADD) & 0x01;
result = -1;
- /* Quick commands are used to probe for chips, so
- errors are expected, and we don't want to frighten the
- user. */
- if ((inb_p(SMBHSTCNT) & 0x3C) != VT596_QUICK)
+ /* The quick and receive byte commands are used to probe
+ for chips, so errors are expected, and we don't want
+ to frighten the user. */
+ if (!((size == VT596_QUICK && !read) ||
+ (size == VT596_BYTE && read)))
dev_err(&vt596_adapter.dev, "Transaction error!\n");
}
@@ -462,9 +463,9 @@ static void __exit i2c_vt596_exit(void)
}
}
-MODULE_AUTHOR(
- "Frodo Looijaard <frodol@dds.nl> and "
- "Philip Edelbrock <phil@netroedge.com>");
+MODULE_AUTHOR("Kyosti Malkki <kmalkki@cc.hut.fi>, "
+ "Mark D. Studebaker <mdsxyz123@yahoo.com> and "
+ "Jean Delvare <khali@linux-fr.org>");
MODULE_DESCRIPTION("vt82c596 SMBus driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c
index 01b03700741..02682fb794c 100644
--- a/drivers/i2c/chips/ds1337.c
+++ b/drivers/i2c/chips/ds1337.c
@@ -164,9 +164,9 @@ static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt)
buf[1] = BIN2BCD(dt->tm_sec);
buf[2] = BIN2BCD(dt->tm_min);
buf[3] = BIN2BCD(dt->tm_hour);
- buf[4] = BIN2BCD(dt->tm_wday) + 1;
+ buf[4] = BIN2BCD(dt->tm_wday + 1);
buf[5] = BIN2BCD(dt->tm_mday);
- buf[6] = BIN2BCD(dt->tm_mon) + 1;
+ buf[6] = BIN2BCD(dt->tm_mon + 1);
val = dt->tm_year;
if (val >= 100) {
val -= 100;
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index a737886e39d..42e5b8175cb 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -539,6 +539,15 @@ config BLK_DEV_CS5530
It is safe to say Y to this question.
+config BLK_DEV_CS5535
+ tristate "AMD CS5535 chipset support"
+ depends on X86 && !X86_64
+ help
+ Include support for UDMA on the NSC/AMD CS5535 companion chipset.
+ This will automatically be detected and configured if found.
+
+ It is safe to say Y to this question.
+
config BLK_DEV_HPT34X
tristate "HPT34X chipset support"
help
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index e83f54d37f9..f615ab75996 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -2038,11 +2038,9 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file,
struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk);
ide_drive_t *drive = floppy->drive;
void __user *argp = (void __user *)arg;
- int err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
+ int err;
int prevent = (arg) ? 1 : 0;
idefloppy_pc_t pc;
- if (err != -EINVAL)
- return err;
switch (cmd) {
case CDROMEJECT:
@@ -2094,7 +2092,7 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file,
case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
return idefloppy_get_format_progress(drive, argp);
}
- return -EINVAL;
+ return generic_ide_ioctl(drive, file, bdev, cmd, arg);
}
static int idefloppy_media_changed(struct gendisk *disk)
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 0b0aa4f5162..af7af958ab3 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -104,8 +104,6 @@ void default_hwif_iops (ide_hwif_t *hwif)
hwif->INSL = ide_insl;
}
-EXPORT_SYMBOL(default_hwif_iops);
-
/*
* MMIO operations, typically used for SATA controllers
*/
@@ -329,8 +327,6 @@ void default_hwif_transport(ide_hwif_t *hwif)
hwif->atapi_output_bytes = atapi_output_bytes;
}
-EXPORT_SYMBOL(default_hwif_transport);
-
/*
* Beginning of Taskfile OPCODE Library and feature sets.
*/
@@ -529,8 +525,6 @@ int wait_for_ready (ide_drive_t *drive, int timeout)
return 0;
}
-EXPORT_SYMBOL(wait_for_ready);
-
/*
* This routine busy-waits for the drive status to be not "busy".
* It then checks the status for all of the "good" bits and none
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 7ec18fa3b5f..54f9639c2a8 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -161,8 +161,6 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
return ide_stopped;
}
-EXPORT_SYMBOL(do_rw_taskfile);
-
/*
* set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
*/
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 9fe19808d81..8af179b531c 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -803,6 +803,7 @@ found:
hwif->irq = hw->irq;
hwif->noprobe = 0;
hwif->chipset = hw->chipset;
+ hwif->gendev.parent = hw->dev;
if (!initializing) {
probe_hwif_init_with_fixup(hwif, fixup);
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index 1dafffa7e51..ef79805218e 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -182,13 +182,14 @@ static void ide_detach(dev_link_t *link)
} /* ide_detach */
-static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq)
+static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq, struct pcmcia_device *handle)
{
hw_regs_t hw;
memset(&hw, 0, sizeof(hw));
ide_init_hwif_ports(&hw, io, ctl, NULL);
hw.irq = irq;
hw.chipset = ide_pci;
+ hw.dev = &handle->dev;
return ide_register_hw_with_fixup(&hw, NULL, ide_undecoded_slave);
}
@@ -327,12 +328,12 @@ static void ide_config(dev_link_t *link)
/* retry registration in case device is still spinning up */
for (hd = -1, i = 0; i < 10; i++) {
- hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
+ hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, handle);
if (hd >= 0) break;
if (link->io.NumPorts1 == 0x20) {
outb(0x02, ctl_base + 0x10);
hd = idecs_register(io_base + 0x10, ctl_base + 0x10,
- link->irq.AssignedIRQ);
+ link->irq.AssignedIRQ, handle);
if (hd >= 0) {
io_base += 0x10;
ctl_base += 0x10;
diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
index af46226c179..f35d684edc2 100644
--- a/drivers/ide/pci/Makefile
+++ b/drivers/ide/pci/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_BLK_DEV_ATIIXP) += atiixp.o
obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o
obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o
obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o
+obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o
obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o
obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o
obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index 844a6c9fb94..21965e5ef25 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -74,6 +74,7 @@ static struct amd_ide_chip {
{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, 0x50, AMD_UDMA_133 },
+ { PCI_DEVICE_ID_AMD_CS5536_IDE, 0x40, AMD_UDMA_100 },
{ 0 }
};
@@ -491,6 +492,7 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
/* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"),
/* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"),
/* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"),
+ /* 17 */ DECLARE_AMD_DEV("AMD5536"),
};
static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
@@ -527,6 +529,7 @@ static struct pci_device_id amd74xx_pci_tbl[] = {
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c
new file mode 100644
index 00000000000..6eb305197f3
--- /dev/null
+++ b/drivers/ide/pci/cs5535.c
@@ -0,0 +1,305 @@
+/*
+ * linux/drivers/ide/pci/cs5535.c
+ *
+ * Copyright (C) 2004-2005 Advanced Micro Devices, Inc.
+ *
+ * History:
+ * 09/20/2005 - Jaya Kumar <jayakumar.ide@gmail.com>
+ * - Reworked tuneproc, set_drive, misc mods to prep for mainline
+ * - Work was sponsored by CIS (M) Sdn Bhd.
+ * Ported to Kernel 2.6.11 on June 26, 2005 by
+ * Wolfgang Zuleger <wolfgang.zuleger@gmx.de>
+ * Alexander Kiausch <alex.kiausch@t-online.de>
+ * Originally developed by AMD for 2.4/2.6
+ *
+ * Development of this chipset driver was funded
+ * by the nice folks at National Semiconductor/AMD.
+ *
+ * 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.
+ *
+ * Documentation:
+ * CS5535 documentation available from AMD
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include "ide-timing.h"
+
+#define MSR_ATAC_BASE 0x51300000
+#define ATAC_GLD_MSR_CAP (MSR_ATAC_BASE+0)
+#define ATAC_GLD_MSR_CONFIG (MSR_ATAC_BASE+0x01)
+#define ATAC_GLD_MSR_SMI (MSR_ATAC_BASE+0x02)
+#define ATAC_GLD_MSR_ERROR (MSR_ATAC_BASE+0x03)
+#define ATAC_GLD_MSR_PM (MSR_ATAC_BASE+0x04)
+#define ATAC_GLD_MSR_DIAG (MSR_ATAC_BASE+0x05)
+#define ATAC_IO_BAR (MSR_ATAC_BASE+0x08)
+#define ATAC_RESET (MSR_ATAC_BASE+0x10)
+#define ATAC_CH0D0_PIO (MSR_ATAC_BASE+0x20)
+#define ATAC_CH0D0_DMA (MSR_ATAC_BASE+0x21)
+#define ATAC_CH0D1_PIO (MSR_ATAC_BASE+0x22)
+#define ATAC_CH0D1_DMA (MSR_ATAC_BASE+0x23)
+#define ATAC_PCI_ABRTERR (MSR_ATAC_BASE+0x24)
+#define ATAC_BM0_CMD_PRIM 0x00
+#define ATAC_BM0_STS_PRIM 0x02
+#define ATAC_BM0_PRD 0x04
+#define CS5535_CABLE_DETECT 0x48
+
+/* Format I PIO settings. We seperate out cmd and data for safer timings */
+
+static unsigned int cs5535_pio_cmd_timings[5] =
+{ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131 };
+static unsigned int cs5535_pio_dta_timings[5] =
+{ 0xF7F4, 0xF173, 0x8141, 0x5131, 0x1131 };
+
+static unsigned int cs5535_mwdma_timings[3] =
+{ 0x7F0FFFF3, 0x7F035352, 0x7f024241 };
+
+static unsigned int cs5535_udma_timings[5] =
+{ 0x7F7436A1, 0x7F733481, 0x7F723261, 0x7F713161, 0x7F703061 };
+
+/* Macros to check if the register is the reset value - reset value is an
+ invalid timing and indicates the register has not been set previously */
+
+#define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL) == 0x00009172 )
+#define CS5535_BAD_DMA(timings) ( (timings & 0x000FFFFF) == 0x00077771 )
+
+/****
+ * cs5535_set_speed - Configure the chipset to the new speed
+ * @drive: Drive to set up
+ * @speed: desired speed
+ *
+ * cs5535_set_speed() configures the chipset to a new speed.
+ */
+static void cs5535_set_speed(ide_drive_t *drive, u8 speed)
+{
+
+ u32 reg = 0, dummy;
+ int unit = drive->select.b.unit;
+
+
+ /* Set the PIO timings */
+ if ((speed & XFER_MODE) == XFER_PIO) {
+ u8 pioa;
+ u8 piob;
+ u8 cmd;
+
+ pioa = speed - XFER_PIO_0;
+ piob = ide_get_best_pio_mode(&(drive->hwif->drives[!unit]),
+ 255, 4, NULL);
+ cmd = pioa < piob ? pioa : piob;
+
+ /* Write the speed of the current drive */
+ reg = (cs5535_pio_cmd_timings[cmd] << 16) |
+ cs5535_pio_dta_timings[pioa];
+ wrmsr(unit ? ATAC_CH0D1_PIO : ATAC_CH0D0_PIO, reg, 0);
+
+ /* And if nessesary - change the speed of the other drive */
+ rdmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, dummy);
+
+ if (((reg >> 16) & cs5535_pio_cmd_timings[cmd]) !=
+ cs5535_pio_cmd_timings[cmd]) {
+ reg &= 0x0000FFFF;
+ reg |= cs5535_pio_cmd_timings[cmd] << 16;
+ wrmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, 0);
+ }
+
+ /* Set bit 31 of the DMA register for PIO format 1 timings */
+ rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy);
+ wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA,
+ reg | 0x80000000UL, 0);
+ } else {
+ rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy);
+
+ reg &= 0x80000000UL; /* Preserve the PIO format bit */
+
+ if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_7)
+ reg |= cs5535_udma_timings[speed - XFER_UDMA_0];
+ else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
+ reg |= cs5535_mwdma_timings[speed - XFER_MW_DMA_0];
+ else
+ return;
+
+ wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, 0);
+ }
+}
+
+static u8 cs5535_ratemask(ide_drive_t *drive)
+{
+ /* eighty93 will return 1 if it's 80core and capable of
+ exceeding udma2, 0 otherwise. we need ratemask to set
+ the max speed and if we can > udma2 then we return 2
+ which selects speed_max as udma4 which is the 5535's max
+ speed, and 1 selects udma2 which is the max for 40c */
+ if (!eighty_ninty_three(drive))
+ return 1;
+
+ return 2;
+}
+
+
+/****
+ * cs5535_set_drive - Configure the drive to the new speed
+ * @drive: Drive to set up
+ * @speed: desired speed
+ *
+ * cs5535_set_drive() configures the drive and the chipset to a
+ * new speed. It also can be called by upper layers.
+ */
+static int cs5535_set_drive(ide_drive_t *drive, u8 speed)
+{
+ speed = ide_rate_filter(cs5535_ratemask(drive), speed);
+ ide_config_drive_speed(drive, speed);
+ cs5535_set_speed(drive, speed);
+
+ return 0;
+}
+
+/****
+ * cs5535_tuneproc - PIO setup
+ * @drive: drive to set up
+ * @pio: mode to use (255 for 'best possible')
+ *
+ * A callback from the upper layers for PIO-only tuning.
+ */
+static void cs5535_tuneproc(ide_drive_t *drive, u8 xferspeed)
+{
+ u8 modes[] = { XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3,
+ XFER_PIO_4 };
+
+ /* cs5535 max pio is pio 4, best_pio will check the blacklist.
+ i think we don't need to rate_filter the incoming xferspeed
+ since we know we're only going to choose pio */
+ xferspeed = ide_get_best_pio_mode(drive, xferspeed, 4, NULL);
+ ide_config_drive_speed(drive, modes[xferspeed]);
+ cs5535_set_speed(drive, xferspeed);
+}
+
+static int cs5535_config_drive_for_dma(ide_drive_t *drive)
+{
+ u8 speed;
+
+ speed = ide_dma_speed(drive, cs5535_ratemask(drive));
+
+ /* If no DMA speed was available then let dma_check hit pio */
+ if (!speed) {
+ return 0;
+ }
+
+ cs5535_set_drive(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+static int cs5535_dma_check(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct hd_driveid *id = drive->id;
+ u8 speed;
+
+ drive->init_speed = 0;
+
+ if ((id->capability & 1) && drive->autodma) {
+ if (ide_use_dma(drive)) {
+ if (cs5535_config_drive_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+
+ goto fast_ata_pio;
+
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ speed = ide_get_best_pio_mode(drive, 255, 4, NULL);
+ cs5535_set_drive(drive, speed);
+ return hwif->ide_dma_off_quietly(drive);
+ }
+ /* IORDY not supported */
+ return 0;
+}
+
+static u8 __devinit cs5535_cable_detect(struct pci_dev *dev)
+{
+ u8 bit;
+
+ /* if a 80 wire cable was detected */
+ pci_read_config_byte(dev, CS5535_CABLE_DETECT, &bit);
+ return (bit & 1);
+}
+
+/****
+ * init_hwif_cs5535 - Initialize one ide cannel
+ * @hwif: Channel descriptor
+ *
+ * This gets invoked by the IDE driver once for each channel. It
+ * performs channel-specific pre-initialization before drive probing.
+ *
+ */
+static void __devinit init_hwif_cs5535(ide_hwif_t *hwif)
+{
+ int i;
+
+ hwif->autodma = 0;
+
+ hwif->tuneproc = &cs5535_tuneproc;
+ hwif->speedproc = &cs5535_set_drive;
+ hwif->ide_dma_check = &cs5535_dma_check;
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x1F;
+ hwif->mwdma_mask = 0x07;
+
+
+ hwif->udma_four = cs5535_cable_detect(hwif->pci_dev);
+
+ if (!noautodma)
+ hwif->autodma = 1;
+
+ /* just setting autotune and not worrying about bios timings */
+ for (i = 0; i < 2; i++) {
+ hwif->drives[i].autotune = 1;
+ hwif->drives[i].autodma = hwif->autodma;
+ }
+}
+
+static ide_pci_device_t cs5535_chipset __devinitdata = {
+ .name = "CS5535",
+ .init_hwif = init_hwif_cs5535,
+ .channels = 1,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+};
+
+static int __devinit cs5535_init_one(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ return ide_setup_pci_device(dev, &cs5535_chipset);
+}
+
+static struct pci_device_id cs5535_pci_tbl[] =
+{
+ { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_IDE, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, cs5535_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "CS5535_IDE",
+ .id_table = cs5535_pci_tbl,
+ .probe = cs5535_init_one,
+};
+
+static int __init cs5535_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(cs5535_ide_init);
+
+MODULE_AUTHOR("AMD");
+MODULE_DESCRIPTION("PCI driver module for AMD/NS CS5535 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
index 5a33513f3dd..9f41ecd5633 100644
--- a/drivers/ide/pci/cy82c693.c
+++ b/drivers/ide/pci/cy82c693.c
@@ -469,7 +469,7 @@ static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif)
static __devinitdata ide_hwif_t *primary;
-void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
+static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
{
if (PCI_FUNC(hwif->pci_dev->devfn) == 1)
primary = hwif;
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 2b9961b8813..022d244f2eb 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -701,6 +701,7 @@ static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name)
unsigned long barsize = pci_resource_len(dev, 5);
u8 tmpbyte = 0;
void __iomem *ioaddr;
+ u32 tmp, irq_mask;
/*
* Drop back to PIO if we can't map the mmio. Some
@@ -726,6 +727,14 @@ static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name)
pci_set_drvdata(dev, (void *) ioaddr);
if (pdev_is_sata(dev)) {
+ /* make sure IDE0/1 interrupts are not masked */
+ irq_mask = (1 << 22) | (1 << 23);
+ tmp = readl(ioaddr + 0x48);
+ if (tmp & irq_mask) {
+ tmp &= ~irq_mask;
+ writel(tmp, ioaddr + 0x48);
+ readl(ioaddr + 0x48); /* flush */
+ }
writel(0, ioaddr + 0x148);
writel(0, ioaddr + 0x1C8);
}
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 2687e34aa5b..321a3a10e69 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -32,7 +32,6 @@
* $Id: ib_srp.c 3932 2005-11-01 17:19:29Z roland $
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 0879915b14d..c8ae2bb054e 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -669,7 +669,7 @@ static int input_dev_hotplug(struct class_device *cdev, char **envp,
INPUT_ADD_HOTPLUG_VAR("NAME=\"%s\"", dev->name);
if (dev->phys)
INPUT_ADD_HOTPLUG_VAR("PHYS=\"%s\"", dev->phys);
- if (dev->phys)
+ if (dev->uniq)
INPUT_ADD_HOTPLUG_VAR("UNIQ=\"%s\"", dev->uniq);
INPUT_ADD_HOTPLUG_BM_VAR("EV=", dev->evbit, EV_MAX);
diff --git a/drivers/isdn/divert/divert_init.c b/drivers/isdn/divert/divert_init.c
index 434e684f5db..2f7c9fc2e89 100644
--- a/drivers/isdn/divert/divert_init.c
+++ b/drivers/isdn/divert/divert_init.c
@@ -10,7 +10,6 @@
*/
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index 0b0ea26023e..1b37d86d5ee 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -11,7 +11,6 @@
#include <linux/config.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/poll.h>
#include <linux/smp_lock.h>
#ifdef CONFIG_PROC_FS
diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c
index 0bfd698726a..f1a1f9a9b88 100644
--- a/drivers/isdn/divert/isdn_divert.c
+++ b/drivers/isdn/divert/isdn_divert.c
@@ -9,7 +9,6 @@
*
*/
-#include <linux/version.h>
#include <linux/proc_fs.h>
#include "isdn_divert.h"
diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
index b4d795d4015..dc7ef957e89 100644
--- a/drivers/isdn/hisax/hisax_fcpcipnp.c
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.c
@@ -23,7 +23,6 @@
* o tx_skb at PH_DEACTIVATE time
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c
index 2cf5d1a6df6..8e192a3a349 100644
--- a/drivers/isdn/hisax/st5481_init.c
+++ b/drivers/isdn/hisax/st5481_init.c
@@ -25,7 +25,6 @@
*/
#include <linux/config.h>
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>
diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c
index 1fd3d4e5f28..acc1d3cceeb 100644
--- a/drivers/isdn/hysdn/hycapi.c
+++ b/drivers/isdn/hysdn/hycapi.c
@@ -11,7 +11,6 @@
*/
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/signal.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c
index 12c8137b516..cb791f8e793 100644
--- a/drivers/isdn/hysdn/hysdn_init.c
+++ b/drivers/isdn/hysdn/hysdn_init.c
@@ -13,7 +13,6 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/poll.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c
index babec8157ae..aa01628d74c 100644
--- a/drivers/isdn/hysdn/hysdn_net.c
+++ b/drivers/isdn/hysdn/hysdn_net.c
@@ -14,7 +14,6 @@
*/
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/signal.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index 87f59a0e2a9..40e56143c76 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -12,7 +12,6 @@
*/
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/pci.h>
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index 4d57011c573..6c26f1efabd 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -11,7 +11,6 @@
*/
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/pci.h>
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 8a7d54a5c97..4643df097bf 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -14,7 +14,6 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/poll.h>
#include <linux/vmalloc.h>
#include <linux/isdn.h>
diff --git a/drivers/isdn/icn/icn.h b/drivers/isdn/icn/icn.h
index 9028cc3b507..7d7245fb0b3 100644
--- a/drivers/isdn/icn/icn.h
+++ b/drivers/isdn/icn/icn.h
@@ -35,7 +35,6 @@ typedef struct icn_cdef {
#ifdef __KERNEL__
/* Kernel includes */
-#include <linux/version.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/major.h>
diff --git a/drivers/isdn/isdnloop/isdnloop.h b/drivers/isdn/isdnloop/isdnloop.h
index 8fb7bc1bfe0..d699fe53e1c 100644
--- a/drivers/isdn/isdnloop/isdnloop.h
+++ b/drivers/isdn/isdnloop/isdnloop.h
@@ -33,7 +33,6 @@ typedef struct isdnloop_sdef {
#ifdef __KERNEL__
/* Kernel includes */
-#include <linux/version.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/major.h>
diff --git a/drivers/isdn/sc/includes.h b/drivers/isdn/sc/includes.h
index 4611da6e923..5286e0c810a 100644
--- a/drivers/isdn/sc/includes.h
+++ b/drivers/isdn/sc/includes.h
@@ -4,7 +4,6 @@
*
*/
-#include <linux/version.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <linux/delay.h>
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 01654fcabc5..51315302a85 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -21,7 +21,6 @@
*/
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/init.h>
@@ -272,7 +271,8 @@ static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long inde
return ERR_PTR(-ENOMEM);
ITERATE_RDEV(mddev, rdev, tmp) {
- if (! rdev->in_sync || rdev->faulty)
+ if (! test_bit(In_sync, &rdev->flags)
+ || test_bit(Faulty, &rdev->flags))
continue;
target = (rdev->sb_offset << 1) + offset + index * (PAGE_SIZE/512);
@@ -292,7 +292,8 @@ static int write_sb_page(mddev_t *mddev, long offset, struct page *page, int wai
struct list_head *tmp;
ITERATE_RDEV(mddev, rdev, tmp)
- if (rdev->in_sync && !rdev->faulty)
+ if (test_bit(In_sync, &rdev->flags)
+ && !test_bit(Faulty, &rdev->flags))
md_super_write(mddev, rdev,
(rdev->sb_offset<<1) + offset
+ page->index * (PAGE_SIZE/512),
@@ -300,7 +301,7 @@ static int write_sb_page(mddev_t *mddev, long offset, struct page *page, int wai
page);
if (wait)
- wait_event(mddev->sb_wait, atomic_read(&mddev->pending_writes)==0);
+ md_super_wait(mddev);
return 0;
}
@@ -481,7 +482,8 @@ static int bitmap_read_sb(struct bitmap *bitmap)
/* verify that the bitmap-specific fields are valid */
if (sb->magic != cpu_to_le32(BITMAP_MAGIC))
reason = "bad magic";
- else if (sb->version != cpu_to_le32(BITMAP_MAJOR))
+ else if (le32_to_cpu(sb->version) < BITMAP_MAJOR_LO ||
+ le32_to_cpu(sb->version) > BITMAP_MAJOR_HI)
reason = "unrecognized superblock version";
else if (chunksize < 512 || chunksize > (1024 * 1024 * 4))
reason = "bitmap chunksize out of range (512B - 4MB)";
@@ -526,6 +528,8 @@ success:
bitmap->daemon_lastrun = jiffies;
bitmap->max_write_behind = write_behind;
bitmap->flags |= sb->state;
+ if (le32_to_cpu(sb->version) == BITMAP_MAJOR_HOSTENDIAN)
+ bitmap->flags |= BITMAP_HOSTENDIAN;
bitmap->events_cleared = le64_to_cpu(sb->events_cleared);
if (sb->state & BITMAP_STALE)
bitmap->events_cleared = bitmap->mddev->events;
@@ -763,7 +767,10 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
/* set the bit */
kaddr = kmap_atomic(page, KM_USER0);
- set_bit(bit, kaddr);
+ if (bitmap->flags & BITMAP_HOSTENDIAN)
+ set_bit(bit, kaddr);
+ else
+ ext2_set_bit(bit, kaddr);
kunmap_atomic(kaddr, KM_USER0);
PRINTK("set file bit %lu page %lu\n", bit, page->index);
@@ -821,8 +828,7 @@ int bitmap_unplug(struct bitmap *bitmap)
wake_up_process(bitmap->writeback_daemon->tsk));
spin_unlock_irq(&bitmap->write_lock);
} else
- wait_event(bitmap->mddev->sb_wait,
- atomic_read(&bitmap->mddev->pending_writes)==0);
+ md_super_wait(bitmap->mddev);
}
return 0;
}
@@ -890,6 +896,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
oldindex = ~0L;
for (i = 0; i < chunks; i++) {
+ int b;
index = file_page_index(i);
bit = file_page_offset(i);
if (index != oldindex) { /* this is a new page, read it in */
@@ -938,7 +945,11 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
bitmap->filemap[bitmap->file_pages++] = page;
}
- if (test_bit(bit, page_address(page))) {
+ if (bitmap->flags & BITMAP_HOSTENDIAN)
+ b = test_bit(bit, page_address(page));
+ else
+ b = ext2_test_bit(bit, page_address(page));
+ if (b) {
/* if the disk bit is set, set the memory bit */
bitmap_set_memory_bits(bitmap, i << CHUNK_BLOCK_SHIFT(bitmap),
((i+1) << (CHUNK_BLOCK_SHIFT(bitmap)) >= start)
@@ -1096,7 +1107,10 @@ int bitmap_daemon_work(struct bitmap *bitmap)
-1);
/* clear the bit */
- clear_bit(file_page_offset(j), page_address(page));
+ if (bitmap->flags & BITMAP_HOSTENDIAN)
+ clear_bit(file_page_offset(j), page_address(page));
+ else
+ ext2_clear_bit(file_page_offset(j), page_address(page));
}
}
spin_unlock_irqrestore(&bitmap->lock, flags);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 9ecf51ee596..adf960d8a7c 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -131,6 +131,8 @@ static ctl_table raid_root_table[] = {
static struct block_device_operations md_fops;
+static int start_readonly;
+
/*
* Enables to iterate over all existing md arrays
* all_mddevs_lock protects this list.
@@ -181,7 +183,7 @@ static void mddev_put(mddev_t *mddev)
if (!mddev->raid_disks && list_empty(&mddev->disks)) {
list_del(&mddev->all_mddevs);
blk_put_queue(mddev->queue);
- kfree(mddev);
+ kobject_unregister(&mddev->kobj);
}
spin_unlock(&all_mddevs_lock);
}
@@ -330,18 +332,46 @@ static void free_disk_sb(mdk_rdev_t * rdev)
static int super_written(struct bio *bio, unsigned int bytes_done, int error)
{
mdk_rdev_t *rdev = bio->bi_private;
+ mddev_t *mddev = rdev->mddev;
if (bio->bi_size)
return 1;
if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags))
- md_error(rdev->mddev, rdev);
+ md_error(mddev, rdev);
- if (atomic_dec_and_test(&rdev->mddev->pending_writes))
- wake_up(&rdev->mddev->sb_wait);
+ if (atomic_dec_and_test(&mddev->pending_writes))
+ wake_up(&mddev->sb_wait);
bio_put(bio);
return 0;
}
+static int super_written_barrier(struct bio *bio, unsigned int bytes_done, int error)
+{
+ struct bio *bio2 = bio->bi_private;
+ mdk_rdev_t *rdev = bio2->bi_private;
+ mddev_t *mddev = rdev->mddev;
+ if (bio->bi_size)
+ return 1;
+
+ if (!test_bit(BIO_UPTODATE, &bio->bi_flags) &&
+ error == -EOPNOTSUPP) {
+ unsigned long flags;
+ /* barriers don't appear to be supported :-( */
+ set_bit(BarriersNotsupp, &rdev->flags);
+ mddev->barriers_work = 0;
+ spin_lock_irqsave(&mddev->write_lock, flags);
+ bio2->bi_next = mddev->biolist;
+ mddev->biolist = bio2;
+ spin_unlock_irqrestore(&mddev->write_lock, flags);
+ wake_up(&mddev->sb_wait);
+ bio_put(bio);
+ return 0;
+ }
+ bio_put(bio2);
+ bio->bi_private = rdev;
+ return super_written(bio, bytes_done, error);
+}
+
void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
sector_t sector, int size, struct page *page)
{
@@ -350,16 +380,54 @@ void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
* and decrement it on completion, waking up sb_wait
* if zero is reached.
* If an error occurred, call md_error
+ *
+ * As we might need to resubmit the request if BIO_RW_BARRIER
+ * causes ENOTSUPP, we allocate a spare bio...
*/
struct bio *bio = bio_alloc(GFP_NOIO, 1);
+ int rw = (1<<BIO_RW) | (1<<BIO_RW_SYNC);
bio->bi_bdev = rdev->bdev;
bio->bi_sector = sector;
bio_add_page(bio, page, size, 0);
bio->bi_private = rdev;
bio->bi_end_io = super_written;
+ bio->bi_rw = rw;
+
atomic_inc(&mddev->pending_writes);
- submit_bio((1<<BIO_RW)|(1<<BIO_RW_SYNC), bio);
+ if (!test_bit(BarriersNotsupp, &rdev->flags)) {
+ struct bio *rbio;
+ rw |= (1<<BIO_RW_BARRIER);
+ rbio = bio_clone(bio, GFP_NOIO);
+ rbio->bi_private = bio;
+ rbio->bi_end_io = super_written_barrier;
+ submit_bio(rw, rbio);
+ } else
+ submit_bio(rw, bio);
+}
+
+void md_super_wait(mddev_t *mddev)
+{
+ /* wait for all superblock writes that were scheduled to complete.
+ * if any had to be retried (due to BARRIER problems), retry them
+ */
+ DEFINE_WAIT(wq);
+ for(;;) {
+ prepare_to_wait(&mddev->sb_wait, &wq, TASK_UNINTERRUPTIBLE);
+ if (atomic_read(&mddev->pending_writes)==0)
+ break;
+ while (mddev->biolist) {
+ struct bio *bio;
+ spin_lock_irq(&mddev->write_lock);
+ bio = mddev->biolist;
+ mddev->biolist = bio->bi_next ;
+ bio->bi_next = NULL;
+ spin_unlock_irq(&mddev->write_lock);
+ submit_bio(bio->bi_rw, bio);
+ }
+ schedule();
+ }
+ finish_wait(&mddev->sb_wait, &wq);
}
static int bi_complete(struct bio *bio, unsigned int bytes_done, int error)
@@ -610,7 +678,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
mdp_super_t *sb = (mdp_super_t *)page_address(rdev->sb_page);
rdev->raid_disk = -1;
- rdev->in_sync = 0;
+ rdev->flags = 0;
if (mddev->raid_disks == 0) {
mddev->major_version = 0;
mddev->minor_version = sb->minor_version;
@@ -671,21 +739,19 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
return 0;
if (mddev->level != LEVEL_MULTIPATH) {
- rdev->faulty = 0;
- rdev->flags = 0;
desc = sb->disks + rdev->desc_nr;
if (desc->state & (1<<MD_DISK_FAULTY))
- rdev->faulty = 1;
+ set_bit(Faulty, &rdev->flags);
else if (desc->state & (1<<MD_DISK_SYNC) &&
desc->raid_disk < mddev->raid_disks) {
- rdev->in_sync = 1;
+ set_bit(In_sync, &rdev->flags);
rdev->raid_disk = desc->raid_disk;
}
if (desc->state & (1<<MD_DISK_WRITEMOSTLY))
set_bit(WriteMostly, &rdev->flags);
} else /* MULTIPATH are always insync */
- rdev->in_sync = 1;
+ set_bit(In_sync, &rdev->flags);
return 0;
}
@@ -699,6 +765,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
mdk_rdev_t *rdev2;
int next_spare = mddev->raid_disks;
+
/* make rdev->sb match mddev data..
*
* 1/ zero out disks
@@ -758,23 +825,27 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
sb->disks[0].state = (1<<MD_DISK_REMOVED);
ITERATE_RDEV(mddev,rdev2,tmp) {
mdp_disk_t *d;
- if (rdev2->raid_disk >= 0 && rdev2->in_sync && !rdev2->faulty)
- rdev2->desc_nr = rdev2->raid_disk;
+ int desc_nr;
+ if (rdev2->raid_disk >= 0 && test_bit(In_sync, &rdev2->flags)
+ && !test_bit(Faulty, &rdev2->flags))
+ desc_nr = rdev2->raid_disk;
else
- rdev2->desc_nr = next_spare++;
+ desc_nr = next_spare++;
+ rdev2->desc_nr = desc_nr;
d = &sb->disks[rdev2->desc_nr];
nr_disks++;
d->number = rdev2->desc_nr;
d->major = MAJOR(rdev2->bdev->bd_dev);
d->minor = MINOR(rdev2->bdev->bd_dev);
- if (rdev2->raid_disk >= 0 && rdev->in_sync && !rdev2->faulty)
+ if (rdev2->raid_disk >= 0 && test_bit(In_sync, &rdev2->flags)
+ && !test_bit(Faulty, &rdev2->flags))
d->raid_disk = rdev2->raid_disk;
else
d->raid_disk = rdev2->desc_nr; /* compatibility */
- if (rdev2->faulty) {
+ if (test_bit(Faulty, &rdev2->flags)) {
d->state = (1<<MD_DISK_FAULTY);
failed++;
- } else if (rdev2->in_sync) {
+ } else if (test_bit(In_sync, &rdev2->flags)) {
d->state = (1<<MD_DISK_ACTIVE);
d->state |= (1<<MD_DISK_SYNC);
active++;
@@ -787,7 +858,6 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
if (test_bit(WriteMostly, &rdev2->flags))
d->state |= (1<<MD_DISK_WRITEMOSTLY);
}
-
/* now set the "removed" and "faulty" bits on any missing devices */
for (i=0 ; i < mddev->raid_disks ; i++) {
mdp_disk_t *d = &sb->disks[i];
@@ -944,7 +1014,7 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
struct mdp_superblock_1 *sb = (struct mdp_superblock_1*)page_address(rdev->sb_page);
rdev->raid_disk = -1;
- rdev->in_sync = 0;
+ rdev->flags = 0;
if (mddev->raid_disks == 0) {
mddev->major_version = 1;
mddev->patch_version = 0;
@@ -996,22 +1066,19 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
switch(role) {
case 0xffff: /* spare */
- rdev->faulty = 0;
break;
case 0xfffe: /* faulty */
- rdev->faulty = 1;
+ set_bit(Faulty, &rdev->flags);
break;
default:
- rdev->in_sync = 1;
- rdev->faulty = 0;
+ set_bit(In_sync, &rdev->flags);
rdev->raid_disk = role;
break;
}
- rdev->flags = 0;
if (sb->devflags & WriteMostly1)
set_bit(WriteMostly, &rdev->flags);
} else /* MULTIPATH are always insync */
- rdev->in_sync = 1;
+ set_bit(In_sync, &rdev->flags);
return 0;
}
@@ -1055,9 +1122,9 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
ITERATE_RDEV(mddev,rdev2,tmp) {
i = rdev2->desc_nr;
- if (rdev2->faulty)
+ if (test_bit(Faulty, &rdev2->flags))
sb->dev_roles[i] = cpu_to_le16(0xfffe);
- else if (rdev2->in_sync)
+ else if (test_bit(In_sync, &rdev2->flags))
sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk);
else
sb->dev_roles[i] = cpu_to_le16(0xffff);
@@ -1115,6 +1182,7 @@ 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];
+ struct kobject *ko;
if (rdev->mddev) {
MD_BUG();
@@ -1143,10 +1211,22 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
if (find_rdev_nr(mddev, rdev->desc_nr))
return -EBUSY;
}
+ bdevname(rdev->bdev,b);
+ if (kobject_set_name(&rdev->kobj, "dev-%s", b) < 0)
+ return -ENOMEM;
list_add(&rdev->same_set, &mddev->disks);
rdev->mddev = mddev;
- printk(KERN_INFO "md: bind<%s>\n", bdevname(rdev->bdev,b));
+ printk(KERN_INFO "md: bind<%s>\n", b);
+
+ rdev->kobj.parent = &mddev->kobj;
+ kobject_add(&rdev->kobj);
+
+ if (rdev->bdev->bd_part)
+ ko = &rdev->bdev->bd_part->kobj;
+ else
+ ko = &rdev->bdev->bd_disk->kobj;
+ sysfs_create_link(&rdev->kobj, ko, "block");
return 0;
}
@@ -1160,6 +1240,8 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
list_del_init(&rdev->same_set);
printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
rdev->mddev = NULL;
+ sysfs_remove_link(&rdev->kobj, "block");
+ kobject_del(&rdev->kobj);
}
/*
@@ -1215,7 +1297,7 @@ static void export_rdev(mdk_rdev_t * rdev)
md_autodetect_dev(rdev->bdev->bd_dev);
#endif
unlock_rdev(rdev);
- kfree(rdev);
+ kobject_put(&rdev->kobj);
}
static void kick_rdev_from_array(mdk_rdev_t * rdev)
@@ -1287,7 +1369,8 @@ static void print_rdev(mdk_rdev_t *rdev)
char b[BDEVNAME_SIZE];
printk(KERN_INFO "md: rdev %s, SZ:%08llu F:%d S:%d DN:%u\n",
bdevname(rdev->bdev,b), (unsigned long long)rdev->size,
- rdev->faulty, rdev->in_sync, rdev->desc_nr);
+ test_bit(Faulty, &rdev->flags), test_bit(In_sync, &rdev->flags),
+ rdev->desc_nr);
if (rdev->sb_loaded) {
printk(KERN_INFO "md: rdev superblock:\n");
print_sb((mdp_super_t*)page_address(rdev->sb_page));
@@ -1344,7 +1427,7 @@ static void md_update_sb(mddev_t * mddev)
int sync_req;
repeat:
- spin_lock(&mddev->write_lock);
+ spin_lock_irq(&mddev->write_lock);
sync_req = mddev->in_sync;
mddev->utime = get_seconds();
mddev->events ++;
@@ -1367,11 +1450,11 @@ repeat:
*/
if (!mddev->persistent) {
mddev->sb_dirty = 0;
- spin_unlock(&mddev->write_lock);
+ spin_unlock_irq(&mddev->write_lock);
wake_up(&mddev->sb_wait);
return;
}
- spin_unlock(&mddev->write_lock);
+ spin_unlock_irq(&mddev->write_lock);
dprintk(KERN_INFO
"md: updating %s RAID superblock on device (in sync %d)\n",
@@ -1381,11 +1464,11 @@ repeat:
ITERATE_RDEV(mddev,rdev,tmp) {
char b[BDEVNAME_SIZE];
dprintk(KERN_INFO "md: ");
- if (rdev->faulty)
+ if (test_bit(Faulty, &rdev->flags))
dprintk("(skipping faulty ");
dprintk("%s ", bdevname(rdev->bdev,b));
- if (!rdev->faulty) {
+ if (!test_bit(Faulty, &rdev->flags)) {
md_super_write(mddev,rdev,
rdev->sb_offset<<1, rdev->sb_size,
rdev->sb_page);
@@ -1399,21 +1482,106 @@ repeat:
/* only need to write one superblock... */
break;
}
- wait_event(mddev->sb_wait, atomic_read(&mddev->pending_writes)==0);
+ md_super_wait(mddev);
/* if there was a failure, sb_dirty was set to 1, and we re-write super */
- spin_lock(&mddev->write_lock);
+ spin_lock_irq(&mddev->write_lock);
if (mddev->in_sync != sync_req|| mddev->sb_dirty == 1) {
/* have to write it out again */
- spin_unlock(&mddev->write_lock);
+ spin_unlock_irq(&mddev->write_lock);
goto repeat;
}
mddev->sb_dirty = 0;
- spin_unlock(&mddev->write_lock);
+ spin_unlock_irq(&mddev->write_lock);
wake_up(&mddev->sb_wait);
}
+struct rdev_sysfs_entry {
+ struct attribute attr;
+ ssize_t (*show)(mdk_rdev_t *, char *);
+ ssize_t (*store)(mdk_rdev_t *, const char *, size_t);
+};
+
+static ssize_t
+state_show(mdk_rdev_t *rdev, char *page)
+{
+ char *sep = "";
+ int len=0;
+
+ if (test_bit(Faulty, &rdev->flags)) {
+ len+= sprintf(page+len, "%sfaulty",sep);
+ sep = ",";
+ }
+ if (test_bit(In_sync, &rdev->flags)) {
+ len += sprintf(page+len, "%sin_sync",sep);
+ sep = ",";
+ }
+ if (!test_bit(Faulty, &rdev->flags) &&
+ !test_bit(In_sync, &rdev->flags)) {
+ len += sprintf(page+len, "%sspare", sep);
+ sep = ",";
+ }
+ return len+sprintf(page+len, "\n");
+}
+
+static struct rdev_sysfs_entry
+rdev_state = __ATTR_RO(state);
+
+static ssize_t
+super_show(mdk_rdev_t *rdev, char *page)
+{
+ if (rdev->sb_loaded && rdev->sb_size) {
+ memcpy(page, page_address(rdev->sb_page), rdev->sb_size);
+ return rdev->sb_size;
+ } else
+ return 0;
+}
+static struct rdev_sysfs_entry rdev_super = __ATTR_RO(super);
+
+static struct attribute *rdev_default_attrs[] = {
+ &rdev_state.attr,
+ &rdev_super.attr,
+ NULL,
+};
+static ssize_t
+rdev_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
+{
+ struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
+ mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj);
+
+ if (!entry->show)
+ return -EIO;
+ return entry->show(rdev, page);
+}
+
+static ssize_t
+rdev_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *page, size_t length)
+{
+ struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
+ mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj);
+
+ if (!entry->store)
+ return -EIO;
+ return entry->store(rdev, page, length);
+}
+
+static void rdev_free(struct kobject *ko)
+{
+ mdk_rdev_t *rdev = container_of(ko, mdk_rdev_t, kobj);
+ kfree(rdev);
+}
+static struct sysfs_ops rdev_sysfs_ops = {
+ .show = rdev_attr_show,
+ .store = rdev_attr_store,
+};
+static struct kobj_type rdev_ktype = {
+ .release = rdev_free,
+ .sysfs_ops = &rdev_sysfs_ops,
+ .default_attrs = rdev_default_attrs,
+};
+
/*
* Import a device. If 'super_format' >= 0, then sanity check the superblock
*
@@ -1445,11 +1613,15 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
if (err)
goto abort_free;
+ rdev->kobj.parent = NULL;
+ rdev->kobj.ktype = &rdev_ktype;
+ kobject_init(&rdev->kobj);
+
rdev->desc_nr = -1;
- rdev->faulty = 0;
- rdev->in_sync = 0;
+ rdev->flags = 0;
rdev->data_offset = 0;
atomic_set(&rdev->nr_pending, 0);
+ atomic_set(&rdev->read_errors, 0);
size = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
if (!size) {
@@ -1537,7 +1709,7 @@ static void analyze_sbs(mddev_t * mddev)
if (mddev->level == LEVEL_MULTIPATH) {
rdev->desc_nr = i++;
rdev->raid_disk = rdev->desc_nr;
- rdev->in_sync = 1;
+ set_bit(In_sync, &rdev->flags);
}
}
@@ -1551,6 +1723,162 @@ static void analyze_sbs(mddev_t * mddev)
}
+static ssize_t
+level_show(mddev_t *mddev, char *page)
+{
+ mdk_personality_t *p = mddev->pers;
+ if (p == NULL && mddev->raid_disks == 0)
+ return 0;
+ if (mddev->level >= 0)
+ return sprintf(page, "RAID-%d\n", mddev->level);
+ else
+ return sprintf(page, "%s\n", p->name);
+}
+
+static struct md_sysfs_entry md_level = __ATTR_RO(level);
+
+static ssize_t
+raid_disks_show(mddev_t *mddev, char *page)
+{
+ if (mddev->raid_disks == 0)
+ return 0;
+ return sprintf(page, "%d\n", mddev->raid_disks);
+}
+
+static struct md_sysfs_entry md_raid_disks = __ATTR_RO(raid_disks);
+
+static ssize_t
+action_show(mddev_t *mddev, char *page)
+{
+ char *type = "idle";
+ if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
+ test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) {
+ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
+ if (!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
+ type = "resync";
+ else if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
+ type = "check";
+ else
+ type = "repair";
+ } else
+ type = "recover";
+ }
+ return sprintf(page, "%s\n", type);
+}
+
+static ssize_t
+action_store(mddev_t *mddev, const char *page, size_t len)
+{
+ if (!mddev->pers || !mddev->pers->sync_request)
+ return -EINVAL;
+
+ if (strcmp(page, "idle")==0 || strcmp(page, "idle\n")==0) {
+ if (mddev->sync_thread) {
+ set_bit(MD_RECOVERY_INTR, &mddev->recovery);
+ md_unregister_thread(mddev->sync_thread);
+ mddev->sync_thread = NULL;
+ mddev->recovery = 0;
+ }
+ return len;
+ }
+
+ if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
+ test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
+ return -EBUSY;
+ if (strcmp(page, "resync")==0 || strcmp(page, "resync\n")==0 ||
+ strcmp(page, "recover")==0 || strcmp(page, "recover\n")==0)
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ else {
+ if (strcmp(page, "check")==0 || strcmp(page, "check\n")==0)
+ set_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+ else if (strcmp(page, "repair")!=0 && strcmp(page, "repair\n")!=0)
+ return -EINVAL;
+ set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
+ set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ }
+ md_wakeup_thread(mddev->thread);
+ return len;
+}
+
+static ssize_t
+mismatch_cnt_show(mddev_t *mddev, char *page)
+{
+ return sprintf(page, "%llu\n",
+ (unsigned long long) mddev->resync_mismatches);
+}
+
+static struct md_sysfs_entry
+md_scan_mode = __ATTR(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);
+
+
+static struct md_sysfs_entry
+md_mismatches = __ATTR_RO(mismatch_cnt);
+
+static struct attribute *md_default_attrs[] = {
+ &md_level.attr,
+ &md_raid_disks.attr,
+ NULL,
+};
+
+static struct attribute *md_redundancy_attrs[] = {
+ &md_scan_mode.attr,
+ &md_mismatches.attr,
+ NULL,
+};
+static struct attribute_group md_redundancy_group = {
+ .name = NULL,
+ .attrs = md_redundancy_attrs,
+};
+
+
+static ssize_t
+md_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
+{
+ struct md_sysfs_entry *entry = container_of(attr, struct md_sysfs_entry, attr);
+ mddev_t *mddev = container_of(kobj, struct mddev_s, kobj);
+ ssize_t rv;
+
+ if (!entry->show)
+ return -EIO;
+ mddev_lock(mddev);
+ rv = entry->show(mddev, page);
+ mddev_unlock(mddev);
+ return rv;
+}
+
+static ssize_t
+md_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *page, size_t length)
+{
+ struct md_sysfs_entry *entry = container_of(attr, struct md_sysfs_entry, attr);
+ mddev_t *mddev = container_of(kobj, struct mddev_s, kobj);
+ ssize_t rv;
+
+ if (!entry->store)
+ return -EIO;
+ mddev_lock(mddev);
+ rv = entry->store(mddev, page, length);
+ mddev_unlock(mddev);
+ return rv;
+}
+
+static void md_free(struct kobject *ko)
+{
+ mddev_t *mddev = container_of(ko, mddev_t, kobj);
+ kfree(mddev);
+}
+
+static struct sysfs_ops md_sysfs_ops = {
+ .show = md_attr_show,
+ .store = md_attr_store,
+};
+static struct kobj_type md_ktype = {
+ .release = md_free,
+ .sysfs_ops = &md_sysfs_ops,
+ .default_attrs = md_default_attrs,
+};
+
int mdp_major = 0;
static struct kobject *md_probe(dev_t dev, int *part, void *data)
@@ -1592,6 +1920,11 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
add_disk(disk);
mddev->gendisk = disk;
up(&disks_sem);
+ mddev->kobj.parent = &disk->kobj;
+ mddev->kobj.k_name = NULL;
+ snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md");
+ mddev->kobj.ktype = &md_ktype;
+ kobject_register(&mddev->kobj);
return NULL;
}
@@ -1663,7 +1996,7 @@ static int do_md_run(mddev_t * mddev)
/* devices must have minimum size of one chunk */
ITERATE_RDEV(mddev,rdev,tmp) {
- if (rdev->faulty)
+ if (test_bit(Faulty, &rdev->flags))
continue;
if (rdev->size < chunk_size / 1024) {
printk(KERN_WARNING
@@ -1691,7 +2024,7 @@ static int do_md_run(mddev_t * mddev)
* Also find largest hardsector size
*/
ITERATE_RDEV(mddev,rdev,tmp) {
- if (rdev->faulty)
+ if (test_bit(Faulty, &rdev->flags))
continue;
sync_blockdev(rdev->bdev);
invalidate_bdev(rdev->bdev, 0);
@@ -1715,6 +2048,10 @@ static int do_md_run(mddev_t * mddev)
mddev->recovery = 0;
mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */
+ mddev->barriers_work = 1;
+
+ if (start_readonly)
+ mddev->ro = 2; /* read-only, but switch on first write */
/* before we start the array running, initialise the bitmap */
err = bitmap_create(mddev);
@@ -1730,12 +2067,24 @@ static int do_md_run(mddev_t * mddev)
bitmap_destroy(mddev);
return err;
}
+ if (mddev->pers->sync_request)
+ sysfs_create_group(&mddev->kobj, &md_redundancy_group);
+ else if (mddev->ro == 2) /* auto-readonly not meaningful */
+ mddev->ro = 0;
+
atomic_set(&mddev->writes_pending,0);
mddev->safemode = 0;
mddev->safemode_timer.function = md_safemode_timeout;
mddev->safemode_timer.data = (unsigned long) mddev;
mddev->safemode_delay = (20 * HZ)/1000 +1; /* 20 msec delay */
mddev->in_sync = 1;
+
+ ITERATE_RDEV(mddev,rdev,tmp)
+ if (rdev->raid_disk >= 0) {
+ char nm[20];
+ sprintf(nm, "rd%d", rdev->raid_disk);
+ sysfs_create_link(&mddev->kobj, &rdev->kobj, nm);
+ }
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
md_wakeup_thread(mddev->thread);
@@ -1821,16 +2170,19 @@ static int do_md_stop(mddev_t * mddev, int ro)
if (ro) {
err = -ENXIO;
- if (mddev->ro)
+ if (mddev->ro==1)
goto out;
mddev->ro = 1;
} else {
bitmap_flush(mddev);
- wait_event(mddev->sb_wait, atomic_read(&mddev->pending_writes)==0);
+ md_super_wait(mddev);
if (mddev->ro)
set_disk_ro(disk, 0);
blk_queue_make_request(mddev->queue, md_fail_request);
mddev->pers->stop(mddev);
+ if (mddev->pers->sync_request)
+ sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
+
module_put(mddev->pers->owner);
mddev->pers = NULL;
if (mddev->ro)
@@ -1857,9 +2209,18 @@ static int do_md_stop(mddev_t * mddev, int ro)
* Free resources if final stop
*/
if (!ro) {
+ mdk_rdev_t *rdev;
+ struct list_head *tmp;
struct gendisk *disk;
printk(KERN_INFO "md: %s stopped.\n", mdname(mddev));
+ ITERATE_RDEV(mddev,rdev,tmp)
+ if (rdev->raid_disk >= 0) {
+ char nm[20];
+ sprintf(nm, "rd%d", rdev->raid_disk);
+ sysfs_remove_link(&mddev->kobj, nm);
+ }
+
export_array(mddev);
mddev->array_size = 0;
@@ -2012,7 +2373,7 @@ static int autostart_array(dev_t startdev)
return err;
}
- if (start_rdev->faulty) {
+ if (test_bit(Faulty, &start_rdev->flags)) {
printk(KERN_WARNING
"md: can not autostart based on faulty %s!\n",
bdevname(start_rdev->bdev,b));
@@ -2071,11 +2432,11 @@ static int get_array_info(mddev_t * mddev, void __user * arg)
nr=working=active=failed=spare=0;
ITERATE_RDEV(mddev,rdev,tmp) {
nr++;
- if (rdev->faulty)
+ if (test_bit(Faulty, &rdev->flags))
failed++;
else {
working++;
- if (rdev->in_sync)
+ if (test_bit(In_sync, &rdev->flags))
active++;
else
spare++;
@@ -2166,9 +2527,9 @@ static int get_disk_info(mddev_t * mddev, void __user * arg)
info.minor = MINOR(rdev->bdev->bd_dev);
info.raid_disk = rdev->raid_disk;
info.state = 0;
- if (rdev->faulty)
+ if (test_bit(Faulty, &rdev->flags))
info.state |= (1<<MD_DISK_FAULTY);
- else if (rdev->in_sync) {
+ else if (test_bit(In_sync, &rdev->flags)) {
info.state |= (1<<MD_DISK_ACTIVE);
info.state |= (1<<MD_DISK_SYNC);
}
@@ -2261,7 +2622,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
validate_super(mddev, rdev);
rdev->saved_raid_disk = rdev->raid_disk;
- rdev->in_sync = 0; /* just to be sure */
+ clear_bit(In_sync, &rdev->flags); /* just to be sure */
if (info->state & (1<<MD_DISK_WRITEMOSTLY))
set_bit(WriteMostly, &rdev->flags);
@@ -2299,11 +2660,11 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
else
rdev->raid_disk = -1;
- rdev->faulty = 0;
+ rdev->flags = 0;
+
if (rdev->raid_disk < mddev->raid_disks)
- rdev->in_sync = (info->state & (1<<MD_DISK_SYNC));
- else
- rdev->in_sync = 0;
+ if (info->state & (1<<MD_DISK_SYNC))
+ set_bit(In_sync, &rdev->flags);
if (info->state & (1<<MD_DISK_WRITEMOSTLY))
set_bit(WriteMostly, &rdev->flags);
@@ -2402,14 +2763,14 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
goto abort_export;
}
- if (rdev->faulty) {
+ if (test_bit(Faulty, &rdev->flags)) {
printk(KERN_WARNING
"md: can not hot-add faulty %s disk to %s!\n",
bdevname(rdev->bdev,b), mdname(mddev));
err = -EINVAL;
goto abort_export;
}
- rdev->in_sync = 0;
+ clear_bit(In_sync, &rdev->flags);
rdev->desc_nr = -1;
bind_rdev_to_array(rdev, mddev);
@@ -2929,12 +3290,22 @@ static int md_ioctl(struct inode *inode, struct file *file,
/*
* The remaining ioctls are changing the state of the
- * superblock, so we do not allow read-only arrays
- * here:
+ * superblock, so we do not allow them on read-only arrays.
+ * However non-MD ioctls (e.g. get-size) will still come through
+ * here and hit the 'default' below, so only disallow
+ * 'md' ioctls, and switch to rw mode if started auto-readonly.
*/
- if (mddev->ro) {
- err = -EROFS;
- goto abort_unlock;
+ if (_IOC_TYPE(cmd) == MD_MAJOR &&
+ mddev->ro && mddev->pers) {
+ if (mddev->ro == 2) {
+ mddev->ro = 0;
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ md_wakeup_thread(mddev->thread);
+
+ } else {
+ err = -EROFS;
+ goto abort_unlock;
+ }
}
switch (cmd)
@@ -3064,21 +3435,17 @@ static int md_thread(void * arg)
*/
allow_signal(SIGKILL);
- complete(thread->event);
while (!kthread_should_stop()) {
- void (*run)(mddev_t *);
- wait_event_interruptible_timeout(thread->wqueue,
- test_bit(THREAD_WAKEUP, &thread->flags)
- || kthread_should_stop(),
- thread->timeout);
+ wait_event_timeout(thread->wqueue,
+ test_bit(THREAD_WAKEUP, &thread->flags)
+ || kthread_should_stop(),
+ thread->timeout);
try_to_freeze();
clear_bit(THREAD_WAKEUP, &thread->flags);
- run = thread->run;
- if (run)
- run(thread->mddev);
+ thread->run(thread->mddev);
}
return 0;
@@ -3097,7 +3464,6 @@ mdk_thread_t *md_register_thread(void (*run) (mddev_t *), mddev_t *mddev,
const char *name)
{
mdk_thread_t *thread;
- struct completion event;
thread = kmalloc(sizeof(mdk_thread_t), GFP_KERNEL);
if (!thread)
@@ -3106,18 +3472,14 @@ mdk_thread_t *md_register_thread(void (*run) (mddev_t *), mddev_t *mddev,
memset(thread, 0, sizeof(mdk_thread_t));
init_waitqueue_head(&thread->wqueue);
- init_completion(&event);
- thread->event = &event;
thread->run = run;
thread->mddev = mddev;
- thread->name = name;
thread->timeout = MAX_SCHEDULE_TIMEOUT;
thread->tsk = kthread_run(md_thread, thread, name, mdname(thread->mddev));
if (IS_ERR(thread->tsk)) {
kfree(thread);
return NULL;
}
- wait_for_completion(&event);
return thread;
}
@@ -3136,7 +3498,7 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev)
return;
}
- if (!rdev || rdev->faulty)
+ if (!rdev || test_bit(Faulty, &rdev->flags))
return;
/*
dprintk("md_error dev:%s, rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",
@@ -3322,8 +3684,10 @@ static int md_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "%s : %sactive", mdname(mddev),
mddev->pers ? "" : "in");
if (mddev->pers) {
- if (mddev->ro)
+ if (mddev->ro==1)
seq_printf(seq, " (read-only)");
+ if (mddev->ro==2)
+ seq_printf(seq, "(auto-read-only)");
seq_printf(seq, " %s", mddev->pers->name);
}
@@ -3334,7 +3698,7 @@ static int md_seq_show(struct seq_file *seq, void *v)
bdevname(rdev->bdev,b), rdev->desc_nr);
if (test_bit(WriteMostly, &rdev->flags))
seq_printf(seq, "(W)");
- if (rdev->faulty) {
+ if (test_bit(Faulty, &rdev->flags)) {
seq_printf(seq, "(F)");
continue;
} else if (rdev->raid_disk < 0)
@@ -3363,11 +3727,15 @@ static int md_seq_show(struct seq_file *seq, void *v)
if (mddev->pers) {
mddev->pers->status (seq, mddev);
seq_printf(seq, "\n ");
- if (mddev->curr_resync > 2) {
- status_resync (seq, mddev);
- seq_printf(seq, "\n ");
- } else if (mddev->curr_resync == 1 || mddev->curr_resync == 2)
- seq_printf(seq, " resync=DELAYED\n ");
+ if (mddev->pers->sync_request) {
+ if (mddev->curr_resync > 2) {
+ status_resync (seq, mddev);
+ seq_printf(seq, "\n ");
+ } else if (mddev->curr_resync == 1 || mddev->curr_resync == 2)
+ seq_printf(seq, "\tresync=DELAYED\n ");
+ else if (mddev->recovery_cp < MaxSector)
+ seq_printf(seq, "\tresync=PENDING\n ");
+ }
} else
seq_printf(seq, "\n ");
@@ -3504,15 +3872,22 @@ void md_write_start(mddev_t *mddev, struct bio *bi)
if (bio_data_dir(bi) != WRITE)
return;
+ BUG_ON(mddev->ro == 1);
+ if (mddev->ro == 2) {
+ /* need to switch to read/write */
+ mddev->ro = 0;
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ md_wakeup_thread(mddev->thread);
+ }
atomic_inc(&mddev->writes_pending);
if (mddev->in_sync) {
- spin_lock(&mddev->write_lock);
+ spin_lock_irq(&mddev->write_lock);
if (mddev->in_sync) {
mddev->in_sync = 0;
mddev->sb_dirty = 1;
md_wakeup_thread(mddev->thread);
}
- spin_unlock(&mddev->write_lock);
+ spin_unlock_irq(&mddev->write_lock);
}
wait_event(mddev->sb_wait, mddev->sb_dirty==0);
}
@@ -3568,9 +3943,7 @@ static void md_do_sync(mddev_t *mddev)
mddev->curr_resync = 2;
try_again:
- if (signal_pending(current) ||
- kthread_should_stop()) {
- flush_signals(current);
+ if (kthread_should_stop()) {
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
goto skip;
}
@@ -3590,9 +3963,8 @@ static void md_do_sync(mddev_t *mddev)
* time 'round when curr_resync == 2
*/
continue;
- prepare_to_wait(&resync_wait, &wq, TASK_INTERRUPTIBLE);
- if (!signal_pending(current) &&
- !kthread_should_stop() &&
+ prepare_to_wait(&resync_wait, &wq, TASK_UNINTERRUPTIBLE);
+ if (!kthread_should_stop() &&
mddev2->curr_resync >= mddev->curr_resync) {
printk(KERN_INFO "md: delaying resync of %s"
" until %s has finished resync (they"
@@ -3608,12 +3980,13 @@ static void md_do_sync(mddev_t *mddev)
}
} while (mddev->curr_resync < 2);
- if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
/* resync follows the size requested by the personality,
* which defaults to physical size, but can be virtual size
*/
max_sectors = mddev->resync_max_sectors;
- else
+ mddev->resync_mismatches = 0;
+ } else
/* recovery follows the physical size of devices */
max_sectors = mddev->size << 1;
@@ -3626,7 +3999,8 @@ static void md_do_sync(mddev_t *mddev)
is_mddev_idle(mddev); /* this also initializes IO event counters */
/* we don't use the checkpoint if there's a bitmap */
- if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && !mddev->bitmap)
+ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && !mddev->bitmap
+ && ! test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
j = mddev->recovery_cp;
else
j = 0;
@@ -3699,13 +4073,12 @@ static void md_do_sync(mddev_t *mddev)
}
- if (signal_pending(current) || kthread_should_stop()) {
+ if (kthread_should_stop()) {
/*
* got a signal, exit.
*/
printk(KERN_INFO
"md: md_do_sync() got signal ... exiting\n");
- flush_signals(current);
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
goto out;
}
@@ -3727,7 +4100,7 @@ static void md_do_sync(mddev_t *mddev)
if (currspeed > sysctl_speed_limit_min) {
if ((currspeed > sysctl_speed_limit_max) ||
!is_mddev_idle(mddev)) {
- msleep_interruptible(250);
+ msleep(250);
goto repeat;
}
}
@@ -3820,7 +4193,7 @@ void md_check_recovery(mddev_t *mddev)
if (mddev_trylock(mddev)==0) {
int spares =0;
- spin_lock(&mddev->write_lock);
+ spin_lock_irq(&mddev->write_lock);
if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
!mddev->in_sync && mddev->recovery_cp == MaxSector) {
mddev->in_sync = 1;
@@ -3828,7 +4201,7 @@ void md_check_recovery(mddev_t *mddev)
}
if (mddev->safemode == 1)
mddev->safemode = 0;
- spin_unlock(&mddev->write_lock);
+ spin_unlock_irq(&mddev->write_lock);
if (mddev->sb_dirty)
md_update_sb(mddev);
@@ -3864,9 +4237,13 @@ void md_check_recovery(mddev_t *mddev)
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
goto unlock;
}
- if (mddev->recovery)
- /* probably just the RECOVERY_NEEDED flag */
- mddev->recovery = 0;
+ /* Clear some bits that don't mean anything, but
+ * might be left set
+ */
+ clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ clear_bit(MD_RECOVERY_ERR, &mddev->recovery);
+ clear_bit(MD_RECOVERY_INTR, &mddev->recovery);
+ clear_bit(MD_RECOVERY_DONE, &mddev->recovery);
/* no recovery is running.
* remove any failed drives, then
@@ -3876,31 +4253,41 @@ void md_check_recovery(mddev_t *mddev)
*/
ITERATE_RDEV(mddev,rdev,rtmp)
if (rdev->raid_disk >= 0 &&
- (rdev->faulty || ! rdev->in_sync) &&
+ (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)
+ 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
- && !rdev->faulty) {
- if (mddev->pers->hot_add_disk(mddev,rdev))
+ && !test_bit(Faulty, &rdev->flags)) {
+ 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++;
- else
+ } else
break;
}
}
- if (!spares && (mddev->recovery_cp == MaxSector )) {
- /* nothing we can do ... */
+ if (spares) {
+ clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+ clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+ } else if (mddev->recovery_cp < MaxSector) {
+ set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+ } else if (!test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+ /* nothing to be done ... */
goto unlock;
- }
+
if (mddev->pers->sync_request) {
set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
- if (!spares)
- set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
if (spares && mddev->bitmap && ! mddev->bitmap->file) {
/* We are adding a device or devices to an array
* which has the bitmap stored on all devices.
@@ -3975,7 +4362,7 @@ static int __init md_init(void)
" MD_SB_DISKS=%d\n",
MD_MAJOR_VERSION, MD_MINOR_VERSION,
MD_PATCHLEVEL_VERSION, MAX_MD_DEVS, MD_SB_DISKS);
- printk(KERN_INFO "md: bitmap version %d.%d\n", BITMAP_MAJOR,
+ printk(KERN_INFO "md: bitmap version %d.%d\n", BITMAP_MAJOR_HI,
BITMAP_MINOR);
if (register_blkdev(MAJOR_NR, "md"))
@@ -4039,7 +4426,7 @@ static void autostart_arrays(int part)
if (IS_ERR(rdev))
continue;
- if (rdev->faulty) {
+ if (test_bit(Faulty, &rdev->flags)) {
MD_BUG();
continue;
}
@@ -4086,6 +4473,23 @@ static __exit void md_exit(void)
module_init(md_init)
module_exit(md_exit)
+static int get_ro(char *buffer, struct kernel_param *kp)
+{
+ return sprintf(buffer, "%d", start_readonly);
+}
+static int set_ro(const char *val, struct kernel_param *kp)
+{
+ char *e;
+ int num = simple_strtoul(val, &e, 10);
+ if (*val && (*e == '\0' || *e == '\n')) {
+ start_readonly = num;
+ return 0;;
+ }
+ return -EINVAL;
+}
+
+module_param_call(start_ro, set_ro, get_ro, NULL, 0600);
+
EXPORT_SYMBOL(register_md_personality);
EXPORT_SYMBOL(unregister_md_personality);
EXPORT_SYMBOL(md_error);
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index c06f4474192..145cdc5ad00 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -63,8 +63,8 @@ static int multipath_map (multipath_conf_t *conf)
rcu_read_lock();
for (i = 0; i < disks; i++) {
- mdk_rdev_t *rdev = conf->multipaths[i].rdev;
- if (rdev && rdev->in_sync) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
+ if (rdev && test_bit(In_sync, &rdev->flags)) {
atomic_inc(&rdev->nr_pending);
rcu_read_unlock();
return i;
@@ -139,8 +139,9 @@ static void unplug_slaves(mddev_t *mddev)
rcu_read_lock();
for (i=0; i<mddev->raid_disks; i++) {
- mdk_rdev_t *rdev = conf->multipaths[i].rdev;
- if (rdev && !rdev->faulty && atomic_read(&rdev->nr_pending)) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
+ if (rdev && !test_bit(Faulty, &rdev->flags)
+ && atomic_read(&rdev->nr_pending)) {
request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
atomic_inc(&rdev->nr_pending);
@@ -211,7 +212,7 @@ static void multipath_status (struct seq_file *seq, mddev_t *mddev)
for (i = 0; i < conf->raid_disks; i++)
seq_printf (seq, "%s",
conf->multipaths[i].rdev &&
- conf->multipaths[i].rdev->in_sync ? "U" : "_");
+ test_bit(In_sync, &conf->multipaths[i].rdev->flags) ? "U" : "_");
seq_printf (seq, "]");
}
@@ -224,8 +225,8 @@ static int multipath_issue_flush(request_queue_t *q, struct gendisk *disk,
rcu_read_lock();
for (i=0; i<mddev->raid_disks && ret == 0; i++) {
- mdk_rdev_t *rdev = conf->multipaths[i].rdev;
- if (rdev && !rdev->faulty) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
+ if (rdev && !test_bit(Faulty, &rdev->flags)) {
struct block_device *bdev = rdev->bdev;
request_queue_t *r_queue = bdev_get_queue(bdev);
@@ -265,10 +266,10 @@ static void multipath_error (mddev_t *mddev, mdk_rdev_t *rdev)
/*
* Mark disk as unusable
*/
- if (!rdev->faulty) {
+ if (!test_bit(Faulty, &rdev->flags)) {
char b[BDEVNAME_SIZE];
- rdev->in_sync = 0;
- rdev->faulty = 1;
+ clear_bit(In_sync, &rdev->flags);
+ set_bit(Faulty, &rdev->flags);
mddev->sb_dirty = 1;
conf->working_disks--;
printk(KERN_ALERT "multipath: IO failure on %s,"
@@ -298,7 +299,7 @@ static void print_multipath_conf (multipath_conf_t *conf)
tmp = conf->multipaths + i;
if (tmp->rdev)
printk(" disk%d, o:%d, dev:%s\n",
- i,!tmp->rdev->faulty,
+ i,!test_bit(Faulty, &tmp->rdev->flags),
bdevname(tmp->rdev->bdev,b));
}
}
@@ -330,8 +331,8 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
conf->working_disks++;
rdev->raid_disk = path;
- rdev->in_sync = 1;
- p->rdev = rdev;
+ set_bit(In_sync, &rdev->flags);
+ rcu_assign_pointer(p->rdev, rdev);
found = 1;
}
@@ -350,7 +351,7 @@ static int multipath_remove_disk(mddev_t *mddev, int number)
rdev = p->rdev;
if (rdev) {
- if (rdev->in_sync ||
+ if (test_bit(In_sync, &rdev->flags) ||
atomic_read(&rdev->nr_pending)) {
printk(KERN_ERR "hot-remove-disk, slot %d is identified" " but is still operational!\n", number);
err = -EBUSY;
@@ -482,7 +483,7 @@ static int multipath_run (mddev_t *mddev)
mddev->queue->max_sectors > (PAGE_SIZE>>9))
blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
- if (!rdev->faulty)
+ if (!test_bit(Faulty, &rdev->flags))
conf->working_disks++;
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index e16f473bcf4..2da9d3ba902 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -301,7 +301,7 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
- int mirror, behind;
+ int mirror, behind = test_bit(R1BIO_BehindIO, &r1_bio->state);
conf_t *conf = mddev_to_conf(r1_bio->mddev);
if (bio->bi_size)
@@ -311,47 +311,54 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
if (r1_bio->bios[mirror] == bio)
break;
- /*
- * this branch is our 'one mirror IO has finished' event handler:
- */
- if (!uptodate) {
- md_error(r1_bio->mddev, conf->mirrors[mirror].rdev);
- /* an I/O failed, we can't clear the bitmap */
- set_bit(R1BIO_Degraded, &r1_bio->state);
- } else
+ if (error == -ENOTSUPP && test_bit(R1BIO_Barrier, &r1_bio->state)) {
+ set_bit(BarriersNotsupp, &conf->mirrors[mirror].rdev->flags);
+ set_bit(R1BIO_BarrierRetry, &r1_bio->state);
+ r1_bio->mddev->barriers_work = 0;
+ } else {
/*
- * Set R1BIO_Uptodate in our master bio, so that
- * we will return a good error code for to the higher
- * levels even if IO on some other mirrored buffer fails.
- *
- * The 'master' represents the composite IO operation to
- * user-side. So if something waits for IO, then it will
- * wait for the 'master' bio.
+ * this branch is our 'one mirror IO has finished' event handler:
*/
- set_bit(R1BIO_Uptodate, &r1_bio->state);
-
- update_head_pos(mirror, r1_bio);
-
- behind = test_bit(R1BIO_BehindIO, &r1_bio->state);
- if (behind) {
- if (test_bit(WriteMostly, &conf->mirrors[mirror].rdev->flags))
- atomic_dec(&r1_bio->behind_remaining);
-
- /* In behind mode, we ACK the master bio once the I/O has safely
- * reached all non-writemostly disks. Setting the Returned bit
- * ensures that this gets done only once -- we don't ever want to
- * return -EIO here, instead we'll wait */
-
- if (atomic_read(&r1_bio->behind_remaining) >= (atomic_read(&r1_bio->remaining)-1) &&
- test_bit(R1BIO_Uptodate, &r1_bio->state)) {
- /* Maybe we can return now */
- if (!test_and_set_bit(R1BIO_Returned, &r1_bio->state)) {
- struct bio *mbio = r1_bio->master_bio;
- PRINTK(KERN_DEBUG "raid1: behind end write sectors %llu-%llu\n",
- (unsigned long long) mbio->bi_sector,
- (unsigned long long) mbio->bi_sector +
- (mbio->bi_size >> 9) - 1);
- bio_endio(mbio, mbio->bi_size, 0);
+ r1_bio->bios[mirror] = NULL;
+ bio_put(bio);
+ if (!uptodate) {
+ md_error(r1_bio->mddev, conf->mirrors[mirror].rdev);
+ /* an I/O failed, we can't clear the bitmap */
+ set_bit(R1BIO_Degraded, &r1_bio->state);
+ } else
+ /*
+ * Set R1BIO_Uptodate in our master bio, so that
+ * we will return a good error code for to the higher
+ * levels even if IO on some other mirrored buffer fails.
+ *
+ * The 'master' represents the composite IO operation to
+ * user-side. So if something waits for IO, then it will
+ * wait for the 'master' bio.
+ */
+ set_bit(R1BIO_Uptodate, &r1_bio->state);
+
+ update_head_pos(mirror, r1_bio);
+
+ if (behind) {
+ if (test_bit(WriteMostly, &conf->mirrors[mirror].rdev->flags))
+ atomic_dec(&r1_bio->behind_remaining);
+
+ /* In behind mode, we ACK the master bio once the I/O has safely
+ * reached all non-writemostly disks. Setting the Returned bit
+ * ensures that this gets done only once -- we don't ever want to
+ * return -EIO here, instead we'll wait */
+
+ if (atomic_read(&r1_bio->behind_remaining) >= (atomic_read(&r1_bio->remaining)-1) &&
+ test_bit(R1BIO_Uptodate, &r1_bio->state)) {
+ /* Maybe we can return now */
+ if (!test_and_set_bit(R1BIO_Returned, &r1_bio->state)) {
+ struct bio *mbio = r1_bio->master_bio;
+ PRINTK(KERN_DEBUG "raid1: behind end write sectors %llu-%llu\n",
+ (unsigned long long) mbio->bi_sector,
+ (unsigned long long) mbio->bi_sector +
+ (mbio->bi_size >> 9) - 1);
+ bio_endio(mbio, mbio->bi_size, 0);
+ }
}
}
}
@@ -361,8 +368,16 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
* already.
*/
if (atomic_dec_and_test(&r1_bio->remaining)) {
+ if (test_bit(R1BIO_BarrierRetry, &r1_bio->state)) {
+ reschedule_retry(r1_bio);
+ /* Don't dec_pending yet, we want to hold
+ * the reference over the retry
+ */
+ return 0;
+ }
if (test_bit(R1BIO_BehindIO, &r1_bio->state)) {
/* free extra copy of the data pages */
+/* FIXME bio has been freed!!! */
int i = bio->bi_vcnt;
while (i--)
__free_page(bio->bi_io_vec[i].bv_page);
@@ -416,12 +431,12 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
/* Choose the first operation device, for consistancy */
new_disk = 0;
- for (rdev = conf->mirrors[new_disk].rdev;
- !rdev || !rdev->in_sync
+ for (rdev = rcu_dereference(conf->mirrors[new_disk].rdev);
+ !rdev || !test_bit(In_sync, &rdev->flags)
|| test_bit(WriteMostly, &rdev->flags);
- rdev = conf->mirrors[++new_disk].rdev) {
+ rdev = rcu_dereference(conf->mirrors[++new_disk].rdev)) {
- if (rdev && rdev->in_sync)
+ if (rdev && test_bit(In_sync, &rdev->flags))
wonly_disk = new_disk;
if (new_disk == conf->raid_disks - 1) {
@@ -434,12 +449,12 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
/* make sure the disk is operational */
- for (rdev = conf->mirrors[new_disk].rdev;
- !rdev || !rdev->in_sync ||
+ for (rdev = rcu_dereference(conf->mirrors[new_disk].rdev);
+ !rdev || !test_bit(In_sync, &rdev->flags) ||
test_bit(WriteMostly, &rdev->flags);
- rdev = conf->mirrors[new_disk].rdev) {
+ rdev = rcu_dereference(conf->mirrors[new_disk].rdev)) {
- if (rdev && rdev->in_sync)
+ if (rdev && test_bit(In_sync, &rdev->flags))
wonly_disk = new_disk;
if (new_disk <= 0)
@@ -474,10 +489,10 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
disk = conf->raid_disks;
disk--;
- rdev = conf->mirrors[disk].rdev;
+ rdev = rcu_dereference(conf->mirrors[disk].rdev);
if (!rdev ||
- !rdev->in_sync ||
+ !test_bit(In_sync, &rdev->flags) ||
test_bit(WriteMostly, &rdev->flags))
continue;
@@ -496,11 +511,11 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
if (new_disk >= 0) {
- rdev = conf->mirrors[new_disk].rdev;
+ rdev = rcu_dereference(conf->mirrors[new_disk].rdev);
if (!rdev)
goto retry;
atomic_inc(&rdev->nr_pending);
- if (!rdev->in_sync) {
+ if (!test_bit(In_sync, &rdev->flags)) {
/* cannot risk returning a device that failed
* before we inc'ed nr_pending
*/
@@ -522,8 +537,8 @@ static void unplug_slaves(mddev_t *mddev)
rcu_read_lock();
for (i=0; i<mddev->raid_disks; i++) {
- mdk_rdev_t *rdev = conf->mirrors[i].rdev;
- if (rdev && !rdev->faulty && atomic_read(&rdev->nr_pending)) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+ if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
atomic_inc(&rdev->nr_pending);
@@ -556,8 +571,8 @@ static int raid1_issue_flush(request_queue_t *q, struct gendisk *disk,
rcu_read_lock();
for (i=0; i<mddev->raid_disks && ret == 0; i++) {
- mdk_rdev_t *rdev = conf->mirrors[i].rdev;
- if (rdev && !rdev->faulty) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+ if (rdev && !test_bit(Faulty, &rdev->flags)) {
struct block_device *bdev = rdev->bdev;
request_queue_t *r_queue = bdev_get_queue(bdev);
@@ -648,8 +663,9 @@ static int make_request(request_queue_t *q, struct bio * bio)
struct bio_list bl;
struct page **behind_pages = NULL;
const int rw = bio_data_dir(bio);
+ int do_barriers;
- if (unlikely(bio_barrier(bio))) {
+ if (unlikely(!mddev->barriers_work && bio_barrier(bio))) {
bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
return 0;
}
@@ -728,10 +744,10 @@ static int make_request(request_queue_t *q, struct bio * bio)
#endif
rcu_read_lock();
for (i = 0; i < disks; i++) {
- if ((rdev=conf->mirrors[i].rdev) != NULL &&
- !rdev->faulty) {
+ if ((rdev=rcu_dereference(conf->mirrors[i].rdev)) != NULL &&
+ !test_bit(Faulty, &rdev->flags)) {
atomic_inc(&rdev->nr_pending);
- if (rdev->faulty) {
+ if (test_bit(Faulty, &rdev->flags)) {
atomic_dec(&rdev->nr_pending);
r1_bio->bios[i] = NULL;
} else
@@ -759,6 +775,10 @@ static int make_request(request_queue_t *q, struct bio * bio)
atomic_set(&r1_bio->remaining, 0);
atomic_set(&r1_bio->behind_remaining, 0);
+ do_barriers = bio->bi_rw & BIO_RW_BARRIER;
+ if (do_barriers)
+ set_bit(R1BIO_Barrier, &r1_bio->state);
+
bio_list_init(&bl);
for (i = 0; i < disks; i++) {
struct bio *mbio;
@@ -771,7 +791,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
mbio->bi_sector = r1_bio->sector + conf->mirrors[i].rdev->data_offset;
mbio->bi_bdev = conf->mirrors[i].rdev->bdev;
mbio->bi_end_io = raid1_end_write_request;
- mbio->bi_rw = WRITE;
+ mbio->bi_rw = WRITE | do_barriers;
mbio->bi_private = r1_bio;
if (behind_pages) {
@@ -824,7 +844,7 @@ static void status(struct seq_file *seq, mddev_t *mddev)
for (i = 0; i < conf->raid_disks; i++)
seq_printf(seq, "%s",
conf->mirrors[i].rdev &&
- conf->mirrors[i].rdev->in_sync ? "U" : "_");
+ test_bit(In_sync, &conf->mirrors[i].rdev->flags) ? "U" : "_");
seq_printf(seq, "]");
}
@@ -840,14 +860,14 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
* next level up know.
* else mark the drive as failed
*/
- if (rdev->in_sync
+ if (test_bit(In_sync, &rdev->flags)
&& conf->working_disks == 1)
/*
* Don't fail the drive, act as though we were just a
* normal single drive
*/
return;
- if (rdev->in_sync) {
+ if (test_bit(In_sync, &rdev->flags)) {
mddev->degraded++;
conf->working_disks--;
/*
@@ -855,8 +875,8 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
*/
set_bit(MD_RECOVERY_ERR, &mddev->recovery);
}
- rdev->in_sync = 0;
- rdev->faulty = 1;
+ clear_bit(In_sync, &rdev->flags);
+ set_bit(Faulty, &rdev->flags);
mddev->sb_dirty = 1;
printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n"
" Operation continuing on %d devices\n",
@@ -881,7 +901,7 @@ static void print_conf(conf_t *conf)
tmp = conf->mirrors + i;
if (tmp->rdev)
printk(" disk %d, wo:%d, o:%d, dev:%s\n",
- i, !tmp->rdev->in_sync, !tmp->rdev->faulty,
+ i, !test_bit(In_sync, &tmp->rdev->flags), !test_bit(Faulty, &tmp->rdev->flags),
bdevname(tmp->rdev->bdev,b));
}
}
@@ -913,11 +933,11 @@ static int raid1_spare_active(mddev_t *mddev)
for (i = 0; i < conf->raid_disks; i++) {
tmp = conf->mirrors + i;
if (tmp->rdev
- && !tmp->rdev->faulty
- && !tmp->rdev->in_sync) {
+ && !test_bit(Faulty, &tmp->rdev->flags)
+ && !test_bit(In_sync, &tmp->rdev->flags)) {
conf->working_disks++;
mddev->degraded--;
- tmp->rdev->in_sync = 1;
+ set_bit(In_sync, &tmp->rdev->flags);
}
}
@@ -954,7 +974,7 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
found = 1;
if (rdev->saved_raid_disk != mirror)
conf->fullsync = 1;
- p->rdev = rdev;
+ rcu_assign_pointer(p->rdev, rdev);
break;
}
@@ -972,7 +992,7 @@ static int raid1_remove_disk(mddev_t *mddev, int number)
print_conf(conf);
rdev = p->rdev;
if (rdev) {
- if (rdev->in_sync ||
+ if (test_bit(In_sync, &rdev->flags) ||
atomic_read(&rdev->nr_pending)) {
err = -EBUSY;
goto abort;
@@ -1153,6 +1173,36 @@ static void raid1d(mddev_t *mddev)
if (test_bit(R1BIO_IsSync, &r1_bio->state)) {
sync_request_write(mddev, r1_bio);
unplug = 1;
+ } else if (test_bit(R1BIO_BarrierRetry, &r1_bio->state)) {
+ /* some requests in the r1bio were BIO_RW_BARRIER
+ * requests which failed with -ENOTSUPP. Hohumm..
+ * Better resubmit without the barrier.
+ * We know which devices to resubmit for, because
+ * all others have had their bios[] entry cleared.
+ */
+ int i;
+ clear_bit(R1BIO_BarrierRetry, &r1_bio->state);
+ clear_bit(R1BIO_Barrier, &r1_bio->state);
+ for (i=0; i < conf->raid_disks; i++)
+ if (r1_bio->bios[i]) {
+ struct bio_vec *bvec;
+ int j;
+
+ bio = bio_clone(r1_bio->master_bio, GFP_NOIO);
+ /* copy pages from the failed bio, as
+ * this might be a write-behind device */
+ __bio_for_each_segment(bvec, bio, j, 0)
+ bvec->bv_page = bio_iovec_idx(r1_bio->bios[i], j)->bv_page;
+ bio_put(r1_bio->bios[i]);
+ bio->bi_sector = r1_bio->sector +
+ conf->mirrors[i].rdev->data_offset;
+ bio->bi_bdev = conf->mirrors[i].rdev->bdev;
+ bio->bi_end_io = raid1_end_write_request;
+ bio->bi_rw = WRITE;
+ bio->bi_private = r1_bio;
+ r1_bio->bios[i] = bio;
+ generic_make_request(bio);
+ }
} else {
int disk;
bio = r1_bio->bios[r1_bio->read_disk];
@@ -1260,7 +1310,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
* This call the bitmap_start_sync doesn't actually record anything
*/
if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) &&
- !conf->fullsync) {
+ !conf->fullsync && !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
/* We can skip this block, and probably several more */
*skipped = 1;
return sync_blocks;
@@ -1282,11 +1332,11 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
/* make sure disk is operational */
wonly = disk;
while (conf->mirrors[disk].rdev == NULL ||
- !conf->mirrors[disk].rdev->in_sync ||
+ !test_bit(In_sync, &conf->mirrors[disk].rdev->flags) ||
test_bit(WriteMostly, &conf->mirrors[disk].rdev->flags)
) {
if (conf->mirrors[disk].rdev &&
- conf->mirrors[disk].rdev->in_sync)
+ test_bit(In_sync, &conf->mirrors[disk].rdev->flags))
wonly = disk;
if (disk <= 0)
disk = conf->raid_disks;
@@ -1333,11 +1383,12 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
bio->bi_rw = READ;
bio->bi_end_io = end_sync_read;
} else if (conf->mirrors[i].rdev == NULL ||
- conf->mirrors[i].rdev->faulty) {
+ test_bit(Faulty, &conf->mirrors[i].rdev->flags)) {
still_degraded = 1;
continue;
- } else if (!conf->mirrors[i].rdev->in_sync ||
- sector_nr + RESYNC_SECTORS > mddev->recovery_cp) {
+ } else if (!test_bit(In_sync, &conf->mirrors[i].rdev->flags) ||
+ sector_nr + RESYNC_SECTORS > mddev->recovery_cp ||
+ test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
bio->bi_rw = WRITE;
bio->bi_end_io = end_sync_write;
write_targets ++;
@@ -1371,8 +1422,9 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
break;
if (sync_blocks == 0) {
if (!bitmap_start_sync(mddev->bitmap, sector_nr,
- &sync_blocks, still_degraded) &&
- !conf->fullsync)
+ &sync_blocks, still_degraded) &&
+ !conf->fullsync &&
+ !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
break;
if (sync_blocks < (PAGE_SIZE>>9))
BUG();
@@ -1478,7 +1530,7 @@ static int run(mddev_t *mddev)
blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
disk->head_position = 0;
- if (!rdev->faulty && rdev->in_sync)
+ if (!test_bit(Faulty, &rdev->flags) && test_bit(In_sync, &rdev->flags))
conf->working_disks++;
}
conf->raid_disks = mddev->raid_disks;
@@ -1518,7 +1570,7 @@ static int run(mddev_t *mddev)
*/
for (j = 0; j < conf->raid_disks &&
(!conf->mirrors[j].rdev ||
- !conf->mirrors[j].rdev->in_sync) ; j++)
+ !test_bit(In_sync, &conf->mirrors[j].rdev->flags)) ; j++)
/* nothing */;
conf->last_used = j;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index bbe40e9cf92..867f06ae33d 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -496,6 +496,7 @@ static int read_balance(conf_t *conf, r10bio_t *r10_bio)
int disk, slot, nslot;
const int sectors = r10_bio->sectors;
sector_t new_distance, current_distance;
+ mdk_rdev_t *rdev;
raid10_find_phys(conf, r10_bio);
rcu_read_lock();
@@ -510,8 +511,8 @@ static int read_balance(conf_t *conf, r10bio_t *r10_bio)
slot = 0;
disk = r10_bio->devs[slot].devnum;
- while (!conf->mirrors[disk].rdev ||
- !conf->mirrors[disk].rdev->in_sync) {
+ while ((rdev = rcu_dereference(conf->mirrors[disk].rdev)) == NULL ||
+ !test_bit(In_sync, &rdev->flags)) {
slot++;
if (slot == conf->copies) {
slot = 0;
@@ -527,8 +528,8 @@ static int read_balance(conf_t *conf, r10bio_t *r10_bio)
/* make sure the disk is operational */
slot = 0;
disk = r10_bio->devs[slot].devnum;
- while (!conf->mirrors[disk].rdev ||
- !conf->mirrors[disk].rdev->in_sync) {
+ while ((rdev=rcu_dereference(conf->mirrors[disk].rdev)) == NULL ||
+ !test_bit(In_sync, &rdev->flags)) {
slot ++;
if (slot == conf->copies) {
disk = -1;
@@ -547,11 +548,11 @@ static int read_balance(conf_t *conf, r10bio_t *r10_bio)
int ndisk = r10_bio->devs[nslot].devnum;
- if (!conf->mirrors[ndisk].rdev ||
- !conf->mirrors[ndisk].rdev->in_sync)
+ if ((rdev=rcu_dereference(conf->mirrors[ndisk].rdev)) == NULL ||
+ !test_bit(In_sync, &rdev->flags))
continue;
- if (!atomic_read(&conf->mirrors[ndisk].rdev->nr_pending)) {
+ if (!atomic_read(&rdev->nr_pending)) {
disk = ndisk;
slot = nslot;
break;
@@ -569,7 +570,7 @@ rb_out:
r10_bio->read_slot = slot;
/* conf->next_seq_sect = this_sector + sectors;*/
- if (disk >= 0 && conf->mirrors[disk].rdev)
+ if (disk >= 0 && (rdev=rcu_dereference(conf->mirrors[disk].rdev))!= NULL)
atomic_inc(&conf->mirrors[disk].rdev->nr_pending);
rcu_read_unlock();
@@ -583,8 +584,8 @@ static void unplug_slaves(mddev_t *mddev)
rcu_read_lock();
for (i=0; i<mddev->raid_disks; i++) {
- mdk_rdev_t *rdev = conf->mirrors[i].rdev;
- if (rdev && !rdev->faulty && atomic_read(&rdev->nr_pending)) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+ if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
atomic_inc(&rdev->nr_pending);
@@ -614,8 +615,8 @@ static int raid10_issue_flush(request_queue_t *q, struct gendisk *disk,
rcu_read_lock();
for (i=0; i<mddev->raid_disks && ret == 0; i++) {
- mdk_rdev_t *rdev = conf->mirrors[i].rdev;
- if (rdev && !rdev->faulty) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+ if (rdev && !test_bit(Faulty, &rdev->flags)) {
struct block_device *bdev = rdev->bdev;
request_queue_t *r_queue = bdev_get_queue(bdev);
@@ -768,9 +769,10 @@ static int make_request(request_queue_t *q, struct bio * bio)
rcu_read_lock();
for (i = 0; i < conf->copies; i++) {
int d = r10_bio->devs[i].devnum;
- if (conf->mirrors[d].rdev &&
- !conf->mirrors[d].rdev->faulty) {
- atomic_inc(&conf->mirrors[d].rdev->nr_pending);
+ mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[d].rdev);
+ if (rdev &&
+ !test_bit(Faulty, &rdev->flags)) {
+ atomic_inc(&rdev->nr_pending);
r10_bio->devs[i].bio = bio;
} else
r10_bio->devs[i].bio = NULL;
@@ -824,7 +826,7 @@ static void status(struct seq_file *seq, mddev_t *mddev)
for (i = 0; i < conf->raid_disks; i++)
seq_printf(seq, "%s",
conf->mirrors[i].rdev &&
- conf->mirrors[i].rdev->in_sync ? "U" : "_");
+ test_bit(In_sync, &conf->mirrors[i].rdev->flags) ? "U" : "_");
seq_printf(seq, "]");
}
@@ -839,7 +841,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
* next level up know.
* else mark the drive as failed
*/
- if (rdev->in_sync
+ if (test_bit(In_sync, &rdev->flags)
&& conf->working_disks == 1)
/*
* Don't fail the drive, just return an IO error.
@@ -849,7 +851,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
* really dead" tests...
*/
return;
- if (rdev->in_sync) {
+ if (test_bit(In_sync, &rdev->flags)) {
mddev->degraded++;
conf->working_disks--;
/*
@@ -857,8 +859,8 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
*/
set_bit(MD_RECOVERY_ERR, &mddev->recovery);
}
- rdev->in_sync = 0;
- rdev->faulty = 1;
+ clear_bit(In_sync, &rdev->flags);
+ set_bit(Faulty, &rdev->flags);
mddev->sb_dirty = 1;
printk(KERN_ALERT "raid10: Disk failure on %s, disabling device. \n"
" Operation continuing on %d devices\n",
@@ -883,7 +885,8 @@ static void print_conf(conf_t *conf)
tmp = conf->mirrors + i;
if (tmp->rdev)
printk(" disk %d, wo:%d, o:%d, dev:%s\n",
- i, !tmp->rdev->in_sync, !tmp->rdev->faulty,
+ i, !test_bit(In_sync, &tmp->rdev->flags),
+ !test_bit(Faulty, &tmp->rdev->flags),
bdevname(tmp->rdev->bdev,b));
}
}
@@ -936,11 +939,11 @@ static int raid10_spare_active(mddev_t *mddev)
for (i = 0; i < conf->raid_disks; i++) {
tmp = conf->mirrors + i;
if (tmp->rdev
- && !tmp->rdev->faulty
- && !tmp->rdev->in_sync) {
+ && !test_bit(Faulty, &tmp->rdev->flags)
+ && !test_bit(In_sync, &tmp->rdev->flags)) {
conf->working_disks++;
mddev->degraded--;
- tmp->rdev->in_sync = 1;
+ set_bit(In_sync, &tmp->rdev->flags);
}
}
@@ -980,7 +983,7 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
p->head_position = 0;
rdev->raid_disk = mirror;
found = 1;
- p->rdev = rdev;
+ rcu_assign_pointer(p->rdev, rdev);
break;
}
@@ -998,7 +1001,7 @@ static int raid10_remove_disk(mddev_t *mddev, int number)
print_conf(conf);
rdev = p->rdev;
if (rdev) {
- if (rdev->in_sync ||
+ if (test_bit(In_sync, &rdev->flags) ||
atomic_read(&rdev->nr_pending)) {
err = -EBUSY;
goto abort;
@@ -1414,7 +1417,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
for (i=0 ; i<conf->raid_disks; i++)
if (conf->mirrors[i].rdev &&
- !conf->mirrors[i].rdev->in_sync) {
+ !test_bit(In_sync, &conf->mirrors[i].rdev->flags)) {
/* want to reconstruct this device */
r10bio_t *rb2 = r10_bio;
@@ -1435,7 +1438,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
for (j=0; j<conf->copies;j++) {
int d = r10_bio->devs[j].devnum;
if (conf->mirrors[d].rdev &&
- conf->mirrors[d].rdev->in_sync) {
+ test_bit(In_sync, &conf->mirrors[d].rdev->flags)) {
/* This is where we read from */
bio = r10_bio->devs[0].bio;
bio->bi_next = biolist;
@@ -1511,7 +1514,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
bio = r10_bio->devs[i].bio;
bio->bi_end_io = NULL;
if (conf->mirrors[d].rdev == NULL ||
- conf->mirrors[d].rdev->faulty)
+ test_bit(Faulty, &conf->mirrors[d].rdev->flags))
continue;
atomic_inc(&conf->mirrors[d].rdev->nr_pending);
atomic_inc(&r10_bio->remaining);
@@ -1697,7 +1700,7 @@ static int run(mddev_t *mddev)
mddev->queue->max_sectors = (PAGE_SIZE>>9);
disk->head_position = 0;
- if (!rdev->faulty && rdev->in_sync)
+ if (!test_bit(Faulty, &rdev->flags) && test_bit(In_sync, &rdev->flags))
conf->working_disks++;
}
conf->raid_disks = mddev->raid_disks;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 1223e98ecd7..e2a40283e32 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -293,9 +293,31 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector
return sh;
}
-static int grow_stripes(raid5_conf_t *conf, int num)
+static int grow_one_stripe(raid5_conf_t *conf)
{
struct stripe_head *sh;
+ sh = kmem_cache_alloc(conf->slab_cache, GFP_KERNEL);
+ if (!sh)
+ return 0;
+ memset(sh, 0, sizeof(*sh) + (conf->raid_disks-1)*sizeof(struct r5dev));
+ sh->raid_conf = conf;
+ spin_lock_init(&sh->lock);
+
+ if (grow_buffers(sh, conf->raid_disks)) {
+ shrink_buffers(sh, conf->raid_disks);
+ kmem_cache_free(conf->slab_cache, sh);
+ return 0;
+ }
+ /* we just created an active stripe so... */
+ atomic_set(&sh->count, 1);
+ atomic_inc(&conf->active_stripes);
+ INIT_LIST_HEAD(&sh->lru);
+ release_stripe(sh);
+ return 1;
+}
+
+static int grow_stripes(raid5_conf_t *conf, int num)
+{
kmem_cache_t *sc;
int devs = conf->raid_disks;
@@ -308,48 +330,39 @@ static int grow_stripes(raid5_conf_t *conf, int num)
return 1;
conf->slab_cache = sc;
while (num--) {
- sh = kmem_cache_alloc(sc, GFP_KERNEL);
- if (!sh)
- return 1;
- memset(sh, 0, sizeof(*sh) + (devs-1)*sizeof(struct r5dev));
- sh->raid_conf = conf;
- spin_lock_init(&sh->lock);
-
- if (grow_buffers(sh, conf->raid_disks)) {
- shrink_buffers(sh, conf->raid_disks);
- kmem_cache_free(sc, sh);
+ if (!grow_one_stripe(conf))
return 1;
- }
- /* we just created an active stripe so... */
- atomic_set(&sh->count, 1);
- atomic_inc(&conf->active_stripes);
- INIT_LIST_HEAD(&sh->lru);
- release_stripe(sh);
}
return 0;
}
-static void shrink_stripes(raid5_conf_t *conf)
+static int drop_one_stripe(raid5_conf_t *conf)
{
struct stripe_head *sh;
- while (1) {
- spin_lock_irq(&conf->device_lock);
- sh = get_free_stripe(conf);
- spin_unlock_irq(&conf->device_lock);
- if (!sh)
- break;
- if (atomic_read(&sh->count))
- BUG();
- shrink_buffers(sh, conf->raid_disks);
- kmem_cache_free(conf->slab_cache, sh);
- atomic_dec(&conf->active_stripes);
- }
+ spin_lock_irq(&conf->device_lock);
+ sh = get_free_stripe(conf);
+ spin_unlock_irq(&conf->device_lock);
+ if (!sh)
+ return 0;
+ if (atomic_read(&sh->count))
+ BUG();
+ shrink_buffers(sh, conf->raid_disks);
+ kmem_cache_free(conf->slab_cache, sh);
+ atomic_dec(&conf->active_stripes);
+ return 1;
+}
+
+static void shrink_stripes(raid5_conf_t *conf)
+{
+ while (drop_one_stripe(conf))
+ ;
+
kmem_cache_destroy(conf->slab_cache);
conf->slab_cache = NULL;
}
-static int raid5_end_read_request (struct bio * bi, unsigned int bytes_done,
+static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
int error)
{
struct stripe_head *sh = bi->bi_private;
@@ -401,10 +414,35 @@ static int raid5_end_read_request (struct bio * bi, unsigned int bytes_done,
}
#else
set_bit(R5_UPTODATE, &sh->dev[i].flags);
-#endif
+#endif
+ if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
+ printk("R5: read error corrected!!\n");
+ clear_bit(R5_ReadError, &sh->dev[i].flags);
+ clear_bit(R5_ReWrite, &sh->dev[i].flags);
+ }
+ if (atomic_read(&conf->disks[i].rdev->read_errors))
+ atomic_set(&conf->disks[i].rdev->read_errors, 0);
} else {
- md_error(conf->mddev, conf->disks[i].rdev);
+ int retry = 0;
clear_bit(R5_UPTODATE, &sh->dev[i].flags);
+ atomic_inc(&conf->disks[i].rdev->read_errors);
+ if (conf->mddev->degraded)
+ printk("R5: read error not correctable.\n");
+ else if (test_bit(R5_ReWrite, &sh->dev[i].flags))
+ /* Oh, no!!! */
+ printk("R5: read error NOT corrected!!\n");
+ else if (atomic_read(&conf->disks[i].rdev->read_errors)
+ > conf->max_nr_stripes)
+ printk("raid5: Too many read errors, failing device.\n");
+ else
+ retry = 1;
+ if (retry)
+ set_bit(R5_ReadError, &sh->dev[i].flags);
+ else {
+ clear_bit(R5_ReadError, &sh->dev[i].flags);
+ clear_bit(R5_ReWrite, &sh->dev[i].flags);
+ md_error(conf->mddev, conf->disks[i].rdev);
+ }
}
rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
#if 0
@@ -487,19 +525,19 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
PRINTK("raid5: error called\n");
- if (!rdev->faulty) {
+ if (!test_bit(Faulty, &rdev->flags)) {
mddev->sb_dirty = 1;
- if (rdev->in_sync) {
+ if (test_bit(In_sync, &rdev->flags)) {
conf->working_disks--;
mddev->degraded++;
conf->failed_disks++;
- rdev->in_sync = 0;
+ clear_bit(In_sync, &rdev->flags);
/*
* if recovery was running, make sure it aborts.
*/
set_bit(MD_RECOVERY_ERR, &mddev->recovery);
}
- rdev->faulty = 1;
+ set_bit(Faulty, &rdev->flags);
printk (KERN_ALERT
"raid5: Disk failure on %s, disabling device."
" Operation continuing on %d devices\n",
@@ -965,7 +1003,13 @@ static void handle_stripe(struct stripe_head *sh)
}
if (dev->written) written++;
rdev = conf->disks[i].rdev; /* FIXME, should I be looking rdev */
- if (!rdev || !rdev->in_sync) {
+ if (!rdev || !test_bit(In_sync, &rdev->flags)) {
+ /* The ReadError flag wil just be confusing now */
+ clear_bit(R5_ReadError, &dev->flags);
+ clear_bit(R5_ReWrite, &dev->flags);
+ }
+ if (!rdev || !test_bit(In_sync, &rdev->flags)
+ || test_bit(R5_ReadError, &dev->flags)) {
failed++;
failed_num = i;
} else
@@ -980,6 +1024,14 @@ static void handle_stripe(struct stripe_head *sh)
if (failed > 1 && to_read+to_write+written) {
for (i=disks; i--; ) {
int bitmap_end = 0;
+
+ if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
+ mdk_rdev_t *rdev = conf->disks[i].rdev;
+ if (rdev && test_bit(In_sync, &rdev->flags))
+ /* multiple read failures in one stripe */
+ md_error(conf->mddev, rdev);
+ }
+
spin_lock_irq(&conf->device_lock);
/* fail all writes first */
bi = sh->dev[i].towrite;
@@ -1015,7 +1067,8 @@ static void handle_stripe(struct stripe_head *sh)
}
/* fail any reads if this device is non-operational */
- if (!test_bit(R5_Insync, &sh->dev[i].flags)) {
+ if (!test_bit(R5_Insync, &sh->dev[i].flags) ||
+ test_bit(R5_ReadError, &sh->dev[i].flags)) {
bi = sh->dev[i].toread;
sh->dev[i].toread = NULL;
if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
@@ -1247,6 +1300,11 @@ static void handle_stripe(struct stripe_head *sh)
!memcmp(pagea, pagea+4, STRIPE_SIZE-4)) {
/* parity is correct (on disc, not in buffer any more) */
set_bit(STRIPE_INSYNC, &sh->state);
+ } else {
+ conf->mddev->resync_mismatches += STRIPE_SECTORS;
+ if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery))
+ /* don't try to repair!! */
+ set_bit(STRIPE_INSYNC, &sh->state);
}
}
if (!test_bit(STRIPE_INSYNC, &sh->state)) {
@@ -1274,7 +1332,27 @@ static void handle_stripe(struct stripe_head *sh)
md_done_sync(conf->mddev, STRIPE_SECTORS,1);
clear_bit(STRIPE_SYNCING, &sh->state);
}
-
+
+ /* If the failed drive is just a ReadError, then we might need to progress
+ * the repair/check process
+ */
+ if (failed == 1 && ! conf->mddev->ro &&
+ test_bit(R5_ReadError, &sh->dev[failed_num].flags)
+ && !test_bit(R5_LOCKED, &sh->dev[failed_num].flags)
+ && test_bit(R5_UPTODATE, &sh->dev[failed_num].flags)
+ ) {
+ dev = &sh->dev[failed_num];
+ if (!test_bit(R5_ReWrite, &dev->flags)) {
+ set_bit(R5_Wantwrite, &dev->flags);
+ set_bit(R5_ReWrite, &dev->flags);
+ set_bit(R5_LOCKED, &dev->flags);
+ } else {
+ /* let's read it back */
+ set_bit(R5_Wantread, &dev->flags);
+ set_bit(R5_LOCKED, &dev->flags);
+ }
+ }
+
spin_unlock(&sh->lock);
while ((bi=return_bi)) {
@@ -1305,8 +1383,8 @@ static void handle_stripe(struct stripe_head *sh)
bi->bi_end_io = raid5_end_read_request;
rcu_read_lock();
- rdev = conf->disks[i].rdev;
- if (rdev && rdev->faulty)
+ rdev = rcu_dereference(conf->disks[i].rdev);
+ if (rdev && test_bit(Faulty, &rdev->flags))
rdev = NULL;
if (rdev)
atomic_inc(&rdev->nr_pending);
@@ -1379,8 +1457,8 @@ static void unplug_slaves(mddev_t *mddev)
rcu_read_lock();
for (i=0; i<mddev->raid_disks; i++) {
- mdk_rdev_t *rdev = conf->disks[i].rdev;
- if (rdev && !rdev->faulty && atomic_read(&rdev->nr_pending)) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
+ if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
atomic_inc(&rdev->nr_pending);
@@ -1424,8 +1502,8 @@ static int raid5_issue_flush(request_queue_t *q, struct gendisk *disk,
rcu_read_lock();
for (i=0; i<mddev->raid_disks && ret == 0; i++) {
- mdk_rdev_t *rdev = conf->disks[i].rdev;
- if (rdev && !rdev->faulty) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
+ if (rdev && !test_bit(Faulty, &rdev->flags)) {
struct block_device *bdev = rdev->bdev;
request_queue_t *r_queue = bdev_get_queue(bdev);
@@ -1567,6 +1645,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
return rv;
}
if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) &&
+ !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) &&
!conf->fullsync && sync_blocks >= STRIPE_SECTORS) {
/* we can skip this block, and probably more */
sync_blocks /= STRIPE_SECTORS;
@@ -1663,6 +1742,74 @@ static void raid5d (mddev_t *mddev)
PRINTK("--- raid5d inactive\n");
}
+static ssize_t
+raid5_show_stripe_cache_size(mddev_t *mddev, char *page)
+{
+ raid5_conf_t *conf = mddev_to_conf(mddev);
+ if (conf)
+ return sprintf(page, "%d\n", conf->max_nr_stripes);
+ else
+ return 0;
+}
+
+static ssize_t
+raid5_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len)
+{
+ raid5_conf_t *conf = mddev_to_conf(mddev);
+ char *end;
+ int new;
+ if (len >= PAGE_SIZE)
+ return -EINVAL;
+ if (!conf)
+ return -ENODEV;
+
+ new = simple_strtoul(page, &end, 10);
+ if (!*page || (*end && *end != '\n') )
+ return -EINVAL;
+ if (new <= 16 || new > 32768)
+ return -EINVAL;
+ while (new < conf->max_nr_stripes) {
+ if (drop_one_stripe(conf))
+ conf->max_nr_stripes--;
+ else
+ break;
+ }
+ while (new > conf->max_nr_stripes) {
+ if (grow_one_stripe(conf))
+ conf->max_nr_stripes++;
+ else break;
+ }
+ return len;
+}
+
+static struct md_sysfs_entry
+raid5_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR,
+ raid5_show_stripe_cache_size,
+ raid5_store_stripe_cache_size);
+
+static ssize_t
+stripe_cache_active_show(mddev_t *mddev, char *page)
+{
+ raid5_conf_t *conf = mddev_to_conf(mddev);
+ if (conf)
+ return sprintf(page, "%d\n", atomic_read(&conf->active_stripes));
+ else
+ return 0;
+}
+
+static struct md_sysfs_entry
+raid5_stripecache_active = __ATTR_RO(stripe_cache_active);
+
+static struct attribute *raid5_attrs[] = {
+ &raid5_stripecache_size.attr,
+ &raid5_stripecache_active.attr,
+ NULL,
+};
+static struct attribute_group raid5_attrs_group = {
+ .name = NULL,
+ .attrs = raid5_attrs,
+};
+
static int run(mddev_t *mddev)
{
raid5_conf_t *conf;
@@ -1709,7 +1856,7 @@ static int run(mddev_t *mddev)
disk->rdev = rdev;
- if (rdev->in_sync) {
+ if (test_bit(In_sync, &rdev->flags)) {
char b[BDEVNAME_SIZE];
printk(KERN_INFO "raid5: device %s operational as raid"
" disk %d\n", bdevname(rdev->bdev,b),
@@ -1804,6 +1951,7 @@ memory = conf->max_nr_stripes * (sizeof(struct stripe_head) +
}
/* Ok, everything is just fine now */
+ sysfs_create_group(&mddev->kobj, &raid5_attrs_group);
if (mddev->bitmap)
mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ;
@@ -1828,7 +1976,7 @@ abort:
-static int stop (mddev_t *mddev)
+static int stop(mddev_t *mddev)
{
raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
@@ -1837,6 +1985,7 @@ static int stop (mddev_t *mddev)
shrink_stripes(conf);
free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
+ sysfs_remove_group(&mddev->kobj, &raid5_attrs_group);
kfree(conf);
mddev->private = NULL;
return 0;
@@ -1887,7 +2036,7 @@ static void status (struct seq_file *seq, mddev_t *mddev)
for (i = 0; i < conf->raid_disks; i++)
seq_printf (seq, "%s",
conf->disks[i].rdev &&
- conf->disks[i].rdev->in_sync ? "U" : "_");
+ test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_");
seq_printf (seq, "]");
#if RAID5_DEBUG
#define D(x) \
@@ -1914,7 +2063,7 @@ static void print_raid5_conf (raid5_conf_t *conf)
tmp = conf->disks + i;
if (tmp->rdev)
printk(" disk %d, o:%d, dev:%s\n",
- i, !tmp->rdev->faulty,
+ i, !test_bit(Faulty, &tmp->rdev->flags),
bdevname(tmp->rdev->bdev,b));
}
}
@@ -1928,12 +2077,12 @@ static int raid5_spare_active(mddev_t *mddev)
for (i = 0; i < conf->raid_disks; i++) {
tmp = conf->disks + i;
if (tmp->rdev
- && !tmp->rdev->faulty
- && !tmp->rdev->in_sync) {
+ && !test_bit(Faulty, &tmp->rdev->flags)
+ && !test_bit(In_sync, &tmp->rdev->flags)) {
mddev->degraded--;
conf->failed_disks--;
conf->working_disks++;
- tmp->rdev->in_sync = 1;
+ set_bit(In_sync, &tmp->rdev->flags);
}
}
print_raid5_conf(conf);
@@ -1950,7 +2099,7 @@ static int raid5_remove_disk(mddev_t *mddev, int number)
print_raid5_conf(conf);
rdev = p->rdev;
if (rdev) {
- if (rdev->in_sync ||
+ if (test_bit(In_sync, &rdev->flags) ||
atomic_read(&rdev->nr_pending)) {
err = -EBUSY;
goto abort;
@@ -1985,12 +2134,12 @@ static int raid5_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
*/
for (disk=0; disk < mddev->raid_disks; disk++)
if ((p=conf->disks + disk)->rdev == NULL) {
- rdev->in_sync = 0;
+ clear_bit(In_sync, &rdev->flags);
rdev->raid_disk = disk;
found = 1;
if (rdev->saved_raid_disk != disk)
conf->fullsync = 1;
- p->rdev = rdev;
+ rcu_assign_pointer(p->rdev, rdev);
break;
}
print_raid5_conf(conf);
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c
index 77578694770..eae5a35629c 100644
--- a/drivers/md/raid6main.c
+++ b/drivers/md/raid6main.c
@@ -507,19 +507,19 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
raid6_conf_t *conf = (raid6_conf_t *) mddev->private;
PRINTK("raid6: error called\n");
- if (!rdev->faulty) {
+ if (!test_bit(Faulty, &rdev->flags)) {
mddev->sb_dirty = 1;
- if (rdev->in_sync) {
+ if (test_bit(In_sync, &rdev->flags)) {
conf->working_disks--;
mddev->degraded++;
conf->failed_disks++;
- rdev->in_sync = 0;
+ clear_bit(In_sync, &rdev->flags);
/*
* if recovery was running, make sure it aborts.
*/
set_bit(MD_RECOVERY_ERR, &mddev->recovery);
}
- rdev->faulty = 1;
+ set_bit(Faulty, &rdev->flags);
printk (KERN_ALERT
"raid6: Disk failure on %s, disabling device."
" Operation continuing on %d devices\n",
@@ -1071,7 +1071,7 @@ static void handle_stripe(struct stripe_head *sh)
}
if (dev->written) written++;
rdev = conf->disks[i].rdev; /* FIXME, should I be looking rdev */
- if (!rdev || !rdev->in_sync) {
+ if (!rdev || !test_bit(In_sync, &rdev->flags)) {
if ( failed < 2 )
failed_num[failed] = i;
failed++;
@@ -1464,8 +1464,8 @@ static void handle_stripe(struct stripe_head *sh)
bi->bi_end_io = raid6_end_read_request;
rcu_read_lock();
- rdev = conf->disks[i].rdev;
- if (rdev && rdev->faulty)
+ rdev = rcu_dereference(conf->disks[i].rdev);
+ if (rdev && test_bit(Faulty, &rdev->flags))
rdev = NULL;
if (rdev)
atomic_inc(&rdev->nr_pending);
@@ -1538,8 +1538,8 @@ static void unplug_slaves(mddev_t *mddev)
rcu_read_lock();
for (i=0; i<mddev->raid_disks; i++) {
- mdk_rdev_t *rdev = conf->disks[i].rdev;
- if (rdev && !rdev->faulty && atomic_read(&rdev->nr_pending)) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
+ if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
atomic_inc(&rdev->nr_pending);
@@ -1583,8 +1583,8 @@ static int raid6_issue_flush(request_queue_t *q, struct gendisk *disk,
rcu_read_lock();
for (i=0; i<mddev->raid_disks && ret == 0; i++) {
- mdk_rdev_t *rdev = conf->disks[i].rdev;
- if (rdev && !rdev->faulty) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
+ if (rdev && !test_bit(Faulty, &rdev->flags)) {
struct block_device *bdev = rdev->bdev;
request_queue_t *r_queue = bdev_get_queue(bdev);
@@ -1868,7 +1868,7 @@ static int run(mddev_t *mddev)
disk->rdev = rdev;
- if (rdev->in_sync) {
+ if (test_bit(In_sync, &rdev->flags)) {
char b[BDEVNAME_SIZE];
printk(KERN_INFO "raid6: device %s operational as raid"
" disk %d\n", bdevname(rdev->bdev,b),
@@ -2052,7 +2052,7 @@ static void status (struct seq_file *seq, mddev_t *mddev)
for (i = 0; i < conf->raid_disks; i++)
seq_printf (seq, "%s",
conf->disks[i].rdev &&
- conf->disks[i].rdev->in_sync ? "U" : "_");
+ test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_");
seq_printf (seq, "]");
#if RAID6_DUMPSTATE
seq_printf (seq, "\n");
@@ -2078,7 +2078,7 @@ static void print_raid6_conf (raid6_conf_t *conf)
tmp = conf->disks + i;
if (tmp->rdev)
printk(" disk %d, o:%d, dev:%s\n",
- i, !tmp->rdev->faulty,
+ i, !test_bit(Faulty, &tmp->rdev->flags),
bdevname(tmp->rdev->bdev,b));
}
}
@@ -2092,12 +2092,12 @@ static int raid6_spare_active(mddev_t *mddev)
for (i = 0; i < conf->raid_disks; i++) {
tmp = conf->disks + i;
if (tmp->rdev
- && !tmp->rdev->faulty
- && !tmp->rdev->in_sync) {
+ && !test_bit(Faulty, &tmp->rdev->flags)
+ && !test_bit(In_sync, &tmp->rdev->flags)) {
mddev->degraded--;
conf->failed_disks--;
conf->working_disks++;
- tmp->rdev->in_sync = 1;
+ set_bit(In_sync, &tmp->rdev->flags);
}
}
print_raid6_conf(conf);
@@ -2114,7 +2114,7 @@ static int raid6_remove_disk(mddev_t *mddev, int number)
print_raid6_conf(conf);
rdev = p->rdev;
if (rdev) {
- if (rdev->in_sync ||
+ if (test_bit(In_sync, &rdev->flags) ||
atomic_read(&rdev->nr_pending)) {
err = -EBUSY;
goto abort;
@@ -2149,12 +2149,12 @@ static int raid6_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
*/
for (disk=0; disk < mddev->raid_disks; disk++)
if ((p=conf->disks + disk)->rdev == NULL) {
- rdev->in_sync = 0;
+ clear_bit(In_sync, &rdev->flags);
rdev->raid_disk = disk;
found = 1;
if (rdev->saved_raid_disk != disk)
conf->fullsync = 1;
- p->rdev = rdev;
+ rcu_assign_pointer(p->rdev, rdev);
break;
}
print_raid6_conf(conf);
diff --git a/drivers/media/common/ir-common.c b/drivers/media/common/ir-common.c
index 31fccb4f05d..4b71fd6f7ae 100644
--- a/drivers/media/common/ir-common.c
+++ b/drivers/media/common/ir-common.c
@@ -116,7 +116,7 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
[ 46 ] = KEY_BLUE,
[ 24 ] = KEY_KPPLUS, /* fine tune + */
[ 25 ] = KEY_KPMINUS, /* fine tune - */
- [ 33 ] = KEY_KPDOT,
+ [ 33 ] = KEY_KPDOT,
[ 19 ] = KEY_KPENTER,
[ 34 ] = KEY_BACK,
[ 35 ] = KEY_PLAYPAUSE,
@@ -239,7 +239,7 @@ static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
dprintk(1,"%s: key event code=%d down=%d\n",
dev->name,ir->keycode,ir->keypressed);
input_report_key(dev,ir->keycode,ir->keypressed);
- input_sync(dev);
+ input_sync(dev);
}
/* -------------------------------------------------------------------------- */
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 47e28b0ee95..a35330315f6 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -13,6 +13,8 @@
#include "bcm3510.h"
#include "stv0297.h"
#include "mt312.h"
+#include "lgdt330x.h"
+#include "dvb-pll.h"
/* lnb control */
@@ -234,7 +236,6 @@ static struct stv0299_config samsung_tbmu24112_config = {
.inittab = samsung_tbmu24112_inittab,
.mclk = 88000000UL,
.invert = 0,
- .enhanced_tuning = 0,
.skip_reinit = 0,
.lock_output = STV0229_LOCKOUTPUT_LK,
.volt13_op0_op1 = STV0299_VOLT13_OP1,
@@ -296,6 +297,52 @@ static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct fir
return request_firmware(fw, name, fc->dev);
}
+static int lgdt3303_pll_set(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params)
+{
+ struct flexcop_device *fc = fe->dvb->priv;
+ u8 buf[4];
+ struct i2c_msg msg =
+ { .addr = 0x61, .flags = 0, .buf = buf, .len = 4 };
+ int err;
+
+ dvb_pll_configure(&dvb_pll_tdvs_tua6034,buf, params->frequency, 0);
+ dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
+ if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lgdt3303: %s error "
+ "(addr %02x <- %02x, err = %i)\n",
+ __FUNCTION__, buf[0], buf[1], err);
+ if (err < 0)
+ return err;
+ else
+ return -EREMOTEIO;
+ }
+
+ buf[0] = 0x86 | 0x18;
+ buf[1] = 0x50;
+ msg.len = 2;
+ if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lgdt3303: %s error "
+ "(addr %02x <- %02x, err = %i)\n",
+ __FUNCTION__, buf[0], buf[1], err);
+ if (err < 0)
+ return err;
+ else
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static struct lgdt330x_config air2pc_atsc_hd5000_config = {
+ .demod_address = 0x59,
+ .demod_chip = LGDT3303,
+ .serial_mpeg = 0x04,
+ .pll_set = lgdt3303_pll_set,
+ .clock_polarity_flip = 1,
+};
+
static struct nxt2002_config samsung_tbmv_config = {
.demod_address = 0x0a,
.request_firmware = flexcop_fe_request_firmware,
@@ -458,6 +505,11 @@ int flexcop_frontend_init(struct flexcop_device *fc)
fc->dev_type = FC_AIR_ATSC2;
info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
} else
+ /* try the air atsc 3nd generation (lgdt3303) */
+ if ((fc->fe = lgdt330x_attach(&air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
+ fc->dev_type = FC_AIR_ATSC3;
+ info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
+ } else
/* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
if ((fc->fe = bcm3510_attach(&air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_AIR_ATSC1;
diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c
index 3a08d38b318..62282d8dbfa 100644
--- a/drivers/media/dvb/b2c2/flexcop-misc.c
+++ b/drivers/media/dvb/b2c2/flexcop-misc.c
@@ -51,6 +51,7 @@ const char *flexcop_device_names[] = {
"Sky2PC/SkyStar 2 DVB-S",
"Sky2PC/SkyStar 2 DVB-S (old version)",
"Cable2PC/CableStar 2 DVB-C",
+ "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
};
const char *flexcop_bus_names[] = {
diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h
index 4ae1eb5bfe9..23cc6431e2b 100644
--- a/drivers/media/dvb/b2c2/flexcop-reg.h
+++ b/drivers/media/dvb/b2c2/flexcop-reg.h
@@ -26,6 +26,7 @@ typedef enum {
FC_SKY,
FC_SKY_OLD,
FC_CABLE,
+ FC_AIR_ATSC3,
} flexcop_device_type_t;
typedef enum {
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
index 12873d43540..123ed96f6fa 100644
--- a/drivers/media/dvb/b2c2/flexcop.c
+++ b/drivers/media/dvb/b2c2/flexcop.c
@@ -193,6 +193,7 @@ static void flexcop_reset(struct flexcop_device *fc)
v204 = fc->read_ibi_reg(fc,misc_204);
v204.misc_204.Per_reset_sig = 0;
fc->write_ibi_reg(fc,misc_204,v204);
+ msleep(1);
v204.misc_204.Per_reset_sig = 1;
fc->write_ibi_reg(fc,misc_204,v204);
}
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index 1e85d16491b..2337b41714e 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -6,10 +6,12 @@ config DVB_BT8XX
select DVB_NXT6000
select DVB_CX24110
select DVB_OR51211
+ select DVB_LGDT330X
help
Support for PCI cards based on the Bt8xx PCI bridge. Examples are
the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
- the pcHDTV HD2000 cards, and certain AVerMedia cards.
+ the pcHDTV HD2000 cards, the DViCO FusionHDTV Lite cards, and
+ some AVerMedia cards.
Since these cards have no MPEG decoder onboard, they transmit
only compressed MPEG data over the PCI bus, so you need
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index b3c9d7327ac..8977c7a313d 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -690,8 +690,8 @@ struct dst_types dst_tlist[] = {
.device_id = "DTT-CI",
.offset = 1,
.dst_type = DST_TYPE_IS_TERR,
- .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2,
- .dst_feature = 0
+ .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE,
+ .dst_feature = DST_TYPE_HAS_CA
},
{
@@ -796,6 +796,56 @@ static int dst_get_vendor(struct dst_state *state)
return 0;
}
+static int dst_get_tuner_info(struct dst_state *state)
+{
+ u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ u8 get_tuner_2[] = { 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ get_tuner_1[7] = dst_check_sum(get_tuner_1, 7);
+ get_tuner_2[7] = dst_check_sum(get_tuner_2, 7);
+ if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
+ if (dst_command(state, get_tuner_2, 8) < 0) {
+ dprintk(verbose, DST_INFO, 1, "Unsupported Command");
+ return -1;
+ }
+ } else {
+ if (dst_command(state, get_tuner_1, 8) < 0) {
+ dprintk(verbose, DST_INFO, 1, "Unsupported Command");
+ return -1;
+ }
+ }
+ memset(&state->board_info, '\0', 8);
+ memcpy(&state->board_info, &state->rxbuffer, 8);
+ if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
+ if (state->board_info[1] == 0x0b) {
+ if (state->type_flags & DST_TYPE_HAS_TS204)
+ state->type_flags &= ~DST_TYPE_HAS_TS204;
+ state->type_flags |= DST_TYPE_HAS_NEWTUNE;
+ dprintk(verbose, DST_INFO, 1, "DST type has TS=188");
+ } else {
+ if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
+ state->type_flags &= ~DST_TYPE_HAS_NEWTUNE;
+ state->type_flags |= DST_TYPE_HAS_TS204;
+ dprintk(verbose, DST_INFO, 1, "DST type has TS=204");
+ }
+ } else {
+ if (state->board_info[0] == 0xbc) {
+ if (state->type_flags & DST_TYPE_HAS_TS204)
+ state->type_flags &= ~DST_TYPE_HAS_TS204;
+ state->type_flags |= DST_TYPE_HAS_NEWTUNE;
+ dprintk(verbose, DST_INFO, 1, "DST type has TS=188, Daughterboard=[%d]", state->board_info[1]);
+
+ } else if (state->board_info[0] == 0xcc) {
+ if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
+ state->type_flags &= ~DST_TYPE_HAS_NEWTUNE;
+ state->type_flags |= DST_TYPE_HAS_TS204;
+ dprintk(verbose, DST_INFO, 1, "DST type has TS=204 Daughterboard=[%d]", state->board_info[1]);
+ }
+ }
+
+ return 0;
+}
+
static int dst_get_device_id(struct dst_state *state)
{
u8 reply;
@@ -855,15 +905,12 @@ static int dst_get_device_id(struct dst_state *state)
state->dst_type = use_dst_type;
dst_type_flags_print(state->type_flags);
- if (state->type_flags & DST_TYPE_HAS_TS204) {
- dst_packsize(state, 204);
- }
-
return 0;
}
static int dst_probe(struct dst_state *state)
{
+ sema_init(&state->dst_mutex, 1);
if ((rdc_8820_reset(state)) < 0) {
dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
return -1;
@@ -886,6 +933,13 @@ static int dst_probe(struct dst_state *state)
dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command");
return 0;
}
+ if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) {
+ if (dst_get_tuner_info(state) < 0)
+ dprintk(verbose, DST_INFO, 1, "Tuner: Unsupported command");
+ }
+ if (state->type_flags & DST_TYPE_HAS_TS204) {
+ dst_packsize(state, 204);
+ }
if (state->type_flags & DST_TYPE_HAS_FW_BUILD) {
if (dst_fw_ver(state) < 0) {
dprintk(verbose, DST_INFO, 1, "FW: Unsupported command");
@@ -907,21 +961,23 @@ static int dst_probe(struct dst_state *state)
int dst_command(struct dst_state *state, u8 *data, u8 len)
{
u8 reply;
+
+ down(&state->dst_mutex);
if ((dst_comm_init(state)) < 0) {
dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed.");
- return -1;
+ goto error;
}
if (write_dst(state, data, len)) {
dprintk(verbose, DST_INFO, 1, "Tring to recover.. ");
if ((dst_error_recovery(state)) < 0) {
dprintk(verbose, DST_ERROR, 1, "Recovery Failed.");
- return -1;
+ goto error;
}
- return -1;
+ goto error;
}
if ((dst_pio_disable(state)) < 0) {
dprintk(verbose, DST_ERROR, 1, "PIO Disable Failed.");
- return -1;
+ goto error;
}
if (state->type_flags & DST_TYPE_HAS_FW_1)
udelay(3000);
@@ -929,36 +985,41 @@ int dst_command(struct dst_state *state, u8 *data, u8 len)
dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. ");
if ((dst_error_recovery(state)) < 0) {
dprintk(verbose, DST_INFO, 1, "Recovery Failed.");
- return -1;
+ goto error;
}
- return -1;
+ goto error;
}
if (reply != ACK) {
dprintk(verbose, DST_INFO, 1, "write not acknowledged 0x%02x ", reply);
- return -1;
+ goto error;
}
if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3))
- return 0;
+ goto error;
if (state->type_flags & DST_TYPE_HAS_FW_1)
udelay(3000);
else
udelay(2000);
if (!dst_wait_dst_ready(state, NO_DELAY))
- return -1;
+ goto error;
if (read_dst(state, state->rxbuffer, FIXED_COMM)) {
dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. ");
if ((dst_error_recovery(state)) < 0) {
dprintk(verbose, DST_INFO, 1, "Recovery failed.");
- return -1;
+ goto error;
}
- return -1;
+ goto error;
}
if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) {
dprintk(verbose, DST_INFO, 1, "checksum failure");
- return -1;
+ goto error;
}
-
+ up(&state->dst_mutex);
return 0;
+
+error:
+ up(&state->dst_mutex);
+ return -EIO;
+
}
EXPORT_SYMBOL(dst_command);
@@ -1016,7 +1077,7 @@ static int dst_get_tuna(struct dst_state *state)
return 0;
state->diseq_flags &= ~(HAS_LOCK);
if (!dst_wait_dst_ready(state, NO_DELAY))
- return 0;
+ return -EIO;
if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
/* how to get variable length reply ???? */
retval = read_dst(state, state->rx_tuna, 10);
@@ -1024,22 +1085,27 @@ static int dst_get_tuna(struct dst_state *state)
retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM);
if (retval < 0) {
dprintk(verbose, DST_DEBUG, 1, "read not successful");
- return 0;
+ return retval;
}
if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
dprintk(verbose, DST_INFO, 1, "checksum failure ? ");
- return 0;
+ return -EIO;
}
} else {
if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) {
dprintk(verbose, DST_INFO, 1, "checksum failure? ");
- return 0;
+ return -EIO;
}
}
if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0)
return 0;
- state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3];
+ if (state->dst_type == DST_TYPE_IS_SAT) {
+ state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3];
+ } else {
+ state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 16) + (state->rx_tuna[3] << 8) + state->rx_tuna[4];
+ }
+ state->decode_freq = state->decode_freq * 1000;
state->decode_lock = 1;
state->diseq_flags |= HAS_LOCK;
@@ -1062,10 +1128,10 @@ static int dst_write_tuna(struct dvb_frontend *fe)
dst_set_voltage(fe, SEC_VOLTAGE_13);
}
state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
-
+ down(&state->dst_mutex);
if ((dst_comm_init(state)) < 0) {
dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed.");
- return -1;
+ goto error;
}
if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9);
@@ -1077,23 +1143,29 @@ static int dst_write_tuna(struct dvb_frontend *fe)
if (retval < 0) {
dst_pio_disable(state);
dprintk(verbose, DST_DEBUG, 1, "write not successful");
- return retval;
+ goto werr;
}
if ((dst_pio_disable(state)) < 0) {
dprintk(verbose, DST_DEBUG, 1, "DST PIO disable failed !");
- return -1;
+ goto error;
}
if ((read_dst(state, &reply, GET_ACK) < 0)) {
dprintk(verbose, DST_DEBUG, 1, "read verify not successful.");
- return -1;
+ goto error;
}
if (reply != ACK) {
dprintk(verbose, DST_DEBUG, 1, "write not acknowledged 0x%02x ", reply);
- return 0;
+ goto error;
}
state->diseq_flags |= ATTEMPT_TUNE;
-
- return dst_get_tuna(state);
+ retval = dst_get_tuna(state);
+werr:
+ up(&state->dst_mutex);
+ return retval;
+
+error:
+ up(&state->dst_mutex);
+ return -EIO;
}
/*
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index 6776a592045..e6541aff399 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -69,62 +69,53 @@ static int ca_set_pid(void)
}
-static int put_checksum(u8 *check_string, int length)
+static void put_checksum(u8 *check_string, int length)
{
- u8 i = 0, checksum = 0;
-
- dprintk(verbose, DST_CA_DEBUG, 1, " ========================= Checksum calculation ===========================");
- dprintk(verbose, DST_CA_DEBUG, 1, " String Length=[0x%02x]", length);
- dprintk(verbose, DST_CA_DEBUG, 1, " String=[");
-
- while (i < length) {
- dprintk(verbose, DST_CA_DEBUG, 0, " %02x", check_string[i]);
- checksum += check_string[i];
- i++;
- }
- dprintk(verbose, DST_CA_DEBUG, 0, " ]\n");
- dprintk(verbose, DST_CA_DEBUG, 1, "Sum=[%02x]\n", checksum);
- check_string[length] = ~checksum + 1;
- dprintk(verbose, DST_CA_DEBUG, 1, " Checksum=[%02x]", check_string[length]);
- dprintk(verbose, DST_CA_DEBUG, 1, " ==========================================================================");
-
- return 0;
+ dprintk(verbose, DST_CA_DEBUG, 1, " Computing string checksum.");
+ dprintk(verbose, DST_CA_DEBUG, 1, " -> string length : 0x%02x", length);
+ check_string[length] = dst_check_sum (check_string, length);
+ dprintk(verbose, DST_CA_DEBUG, 1, " -> checksum : 0x%02x", check_string[length]);
}
static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read)
{
u8 reply;
+ down(&state->dst_mutex);
dst_comm_init(state);
msleep(65);
if (write_dst(state, data, len)) {
dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover");
dst_error_recovery(state);
- return -1;
+ goto error;
}
if ((dst_pio_disable(state)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed.");
- return -1;
+ goto error;
}
if (read_dst(state, &reply, GET_ACK) < 0) {
dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
dst_error_recovery(state);
- return -1;
+ goto error;
}
if (read) {
if (! dst_wait_dst_ready(state, LONG_DELAY)) {
dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready");
- return -1;
+ goto error;
}
if (read_dst(state, ca_string, 128) < 0) { /* Try to make this dynamic */
dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
dst_error_recovery(state);
- return -1;
+ goto error;
}
}
-
+ up(&state->dst_mutex);
return 0;
+
+error:
+ up(&state->dst_mutex);
+ return -EIO;
}
@@ -166,7 +157,7 @@ static int ca_get_app_info(struct dst_state *state)
return 0;
}
-static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void *arg)
+static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void __user *arg)
{
int i;
u8 slot_cap[256];
@@ -192,25 +183,25 @@ static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps,
p_ca_caps->descr_num = slot_cap[7];
p_ca_caps->descr_type = 1;
- if (copy_to_user((struct ca_caps *)arg, p_ca_caps, sizeof (struct ca_caps)))
+ if (copy_to_user(arg, p_ca_caps, sizeof (struct ca_caps)))
return -EFAULT;
return 0;
}
/* Need some more work */
-static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
+static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
{
return -EOPNOTSUPP;
}
-static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void *arg)
+static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void __user *arg)
{
int i;
static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
- u8 *slot_info = state->rxbuffer;
+ u8 *slot_info = state->messages;
put_checksum(&slot_command[0], 7);
if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) {
@@ -238,19 +229,19 @@ static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_s
} else
p_ca_slot_info->flags = 0;
- if (copy_to_user((struct ca_slot_info *)arg, p_ca_slot_info, sizeof (struct ca_slot_info)))
+ if (copy_to_user(arg, p_ca_slot_info, sizeof (struct ca_slot_info)))
return -EFAULT;
return 0;
}
-static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
+static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
{
u8 i = 0;
u32 command = 0;
- if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg)))
+ if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg)))
return -EFAULT;
if (p_ca_message->msg) {
@@ -266,7 +257,7 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message,
switch (command) {
case CA_APP_INFO:
memcpy(p_ca_message->msg, state->messages, 128);
- if (copy_to_user((void *)arg, p_ca_message, sizeof (struct ca_msg)) )
+ if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
return -EFAULT;
break;
}
@@ -315,7 +306,7 @@ static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 l
return 0;
}
-u32 asn_1_decode(u8 *asn_1_array)
+static u32 asn_1_decode(u8 *asn_1_array)
{
u8 length_field = 0, word_count = 0, count = 0;
u32 length = 0;
@@ -328,7 +319,8 @@ u32 asn_1_decode(u8 *asn_1_array)
} else {
word_count = length_field & 0x7f;
for (count = 0; count < word_count; count++) {
- length = (length | asn_1_array[count + 1]) << 8;
+ length = length << 8;
+ length += asn_1_array[count + 1];
dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length);
}
}
@@ -399,13 +391,14 @@ static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message
return 0;
}
-static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
+static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
{
int i = 0;
unsigned int ca_message_header_len;
u32 command = 0;
struct ca_msg *hw_buffer;
+ int result = 0;
if ((hw_buffer = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
@@ -413,8 +406,11 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
}
dprintk(verbose, DST_CA_DEBUG, 1, " ");
- if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg)))
- return -EFAULT;
+ if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg))) {
+ result = -EFAULT;
+ goto free_mem_and_exit;
+ }
+
if (p_ca_message->msg) {
ca_message_header_len = p_ca_message->length; /* Restore it back when you are done */
@@ -433,7 +429,8 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT");
if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !");
- return -1;
+ result = -1;
+ goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !");
break;
@@ -442,7 +439,8 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
/* Have to handle the 2 basic types of cards here */
if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !");
- return -1;
+ result = -1;
+ goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !");
break;
@@ -451,22 +449,28 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
if ((ca_get_app_info(state)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !");
- return -1;
+ result = -1;
+ goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
break;
}
}
- return 0;
+free_mem_and_exit:
+ kfree (hw_buffer);
+
+ return result;
}
-static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg)
+static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long ioctl_arg)
{
struct dvb_device* dvbdev = (struct dvb_device*) file->private_data;
struct dst_state* state = (struct dst_state*) dvbdev->priv;
struct ca_slot_info *p_ca_slot_info;
struct ca_caps *p_ca_caps;
struct ca_msg *p_ca_message;
+ void __user *arg = (void __user *)ioctl_arg;
+ int result = 0;
if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
@@ -486,14 +490,16 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
dprintk(verbose, DST_CA_INFO, 1, " Sending message");
if ((ca_send_message(state, p_ca_message, arg)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !");
- return -1;
+ result = -1;
+ goto free_mem_and_exit;
}
break;
case CA_GET_MSG:
dprintk(verbose, DST_CA_INFO, 1, " Getting message");
if ((ca_get_message(state, p_ca_message, arg)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !");
- return -1;
+ result = -1;
+ goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !");
break;
@@ -506,7 +512,8 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info");
if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !");
- return -1;
+ result = -1;
+ goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !");
break;
@@ -514,7 +521,8 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities");
if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !");
- return -1;
+ result = -1;
+ goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !");
break;
@@ -522,7 +530,8 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description");
if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !");
- return -1;
+ result = -1;
+ goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !");
break;
@@ -530,7 +539,8 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler");
if ((ca_set_slot_descr()) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !");
- return -1;
+ result = -1;
+ goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !");
break;
@@ -538,14 +548,19 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
dprintk(verbose, DST_CA_INFO, 1, " Setting PID");
if ((ca_set_pid()) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !");
- return -1;
+ result = -1;
+ goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !");
default:
- return -EOPNOTSUPP;
+ result = -EOPNOTSUPP;
};
+ free_mem_and_exit:
+ kfree (p_ca_message);
+ kfree (p_ca_slot_info);
+ kfree (p_ca_caps);
- return 0;
+ return result;
}
static int dst_ca_open(struct inode *inode, struct file *file)
@@ -582,7 +597,7 @@ static int dst_ca_write(struct file *file, const char __user *buffer, size_t len
static struct file_operations dst_ca_fops = {
.owner = THIS_MODULE,
- .ioctl = (void *)dst_ca_ioctl,
+ .ioctl = dst_ca_ioctl,
.open = dst_ca_open,
.release = dst_ca_release,
.read = dst_ca_read,
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
index 3281a6ca368..81557f38fe3 100644
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ b/drivers/media/dvb/bt8xx/dst_common.h
@@ -22,6 +22,7 @@
#ifndef DST_COMMON_H
#define DST_COMMON_H
+#include <linux/smp_lock.h>
#include <linux/dvb/frontend.h>
#include <linux/device.h>
#include "bt878.h"
@@ -49,6 +50,7 @@
#define DST_TYPE_HAS_FW_BUILD 64
#define DST_TYPE_HAS_OBS_REGS 128
#define DST_TYPE_HAS_INC_COUNT 256
+#define DST_TYPE_HAS_MULTI_FE 512
/* Card capability list */
@@ -117,6 +119,9 @@ struct dst_state {
u8 fw_version[8];
u8 card_info[8];
u8 vendor[8];
+ u8 board_info[8];
+
+ struct semaphore dst_mutex;
};
struct dst_types {
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index c5c7672cd53..2e398090cf6 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -34,6 +34,7 @@
#include "dvb_frontend.h"
#include "dvb-bt8xx.h"
#include "bt878.h"
+#include "dvb-pll.h"
static int debug;
@@ -279,7 +280,7 @@ static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_front
data[0] = (div >> 8) & 0x7f;
data[1] = div & 0xff;
data[2] = ((div >> 10) & 0x60) | cfg;
- data[3] = cpump | band_select;
+ data[3] = (cpump << 6) | band_select;
i2c_transfer(card->i2c_adapter, &msg, 1);
return (div * 166666 - 36000000);
@@ -522,9 +523,7 @@ static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
/*
* Reset the frontend, must be called before trying
* to initialise the MT352 or mt352_attach
- * will fail.
- *
- * Presumably not required for the NXT6000 frontend.
+ * will fail. Same goes for the nxt6000 frontend.
*
*/
@@ -546,14 +545,63 @@ static struct mt352_config digitv_alps_tded4_config = {
.pll_set = digitv_alps_tded4_pll_set,
};
+static int tdvs_tua6034_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
+ u8 buf[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ int err;
+
+ dvb_pll_configure(&dvb_pll_tdvs_tua6034, buf, params->frequency, 0);
+ dprintk("%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
+ if ((err = i2c_transfer(card->i2c_adapter, &msg, 1)) != 1) {
+ printk(KERN_WARNING "dvb-bt8xx: %s error "
+ "(addr %02x <- %02x, err = %i)\n",
+ __FUNCTION__, buf[0], buf[1], err);
+ if (err < 0)
+ return err;
+ else
+ return -EREMOTEIO;
+ }
+
+ /* Set the Auxiliary Byte. */
+ buf[2] &= ~0x20;
+ buf[2] |= 0x18;
+ buf[3] = 0x50;
+ i2c_transfer(card->i2c_adapter, &msg, 1);
+
+ return 0;
+}
+
+static struct lgdt330x_config tdvs_tua6034_config = {
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3303,
+ .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
+ .pll_set = tdvs_tua6034_pll_set,
+};
+
+static void lgdt330x_reset(struct dvb_bt8xx_card *bt)
+{
+ /* Set pin 27 of the lgdt3303 chip high to reset the frontend */
+
+ /* Pulse the reset line */
+ bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
+ bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000000); /* Low */
+ msleep(100);
+
+ bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
+ msleep(100);
+}
+
static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
{
int ret;
struct dst_state* state = NULL;
switch(type) {
-#ifdef BTTV_DVICO_DVBT_LITE
- case BTTV_DVICO_DVBT_LITE:
+#ifdef BTTV_BOARD_DVICO_DVBT_LITE
+ case BTTV_BOARD_DVICO_DVBT_LITE:
card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
if (card->fe != NULL) {
card->fe->ops->info.frequency_min = 174000000;
@@ -562,10 +610,19 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
break;
#endif
-#ifdef BTTV_TWINHAN_VP3021
- case BTTV_TWINHAN_VP3021:
+#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE
+ case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
+ lgdt330x_reset(card);
+ card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter);
+ if (card->fe != NULL)
+ dprintk ("dvb_bt8xx: lgdt330x detected\n");
+ break;
+#endif
+
+#ifdef BTTV_BOARD_TWINHAN_VP3021
+ case BTTV_BOARD_TWINHAN_VP3021:
#else
- case BTTV_NEBULA_DIGITV:
+ case BTTV_BOARD_NEBULA_DIGITV:
#endif
/*
* It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK);
@@ -573,6 +630,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
*/
/* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */
+ digitv_alps_tded4_reset(card);
card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter);
if (card->fe != NULL) {
dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
@@ -587,11 +645,11 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n");
break;
- case BTTV_AVDVBT_761:
+ case BTTV_BOARD_AVDVBT_761:
card->fe = sp887x_attach(&microtune_mt7202dtf_config, card->i2c_adapter);
break;
- case BTTV_AVDVBT_771:
+ case BTTV_BOARD_AVDVBT_771:
card->fe = mt352_attach(&advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
if (card->fe != NULL) {
card->fe->ops->info.frequency_min = 174000000;
@@ -599,7 +657,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
}
break;
- case BTTV_TWINHAN_DST:
+ case BTTV_BOARD_TWINHAN_DST:
/* DST is not a frontend driver !!! */
state = (struct dst_state *) kmalloc(sizeof (struct dst_state), GFP_KERNEL);
/* Setup the Card */
@@ -620,11 +678,11 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
ret = dst_ca_attach(state, &card->dvb_adapter);
break;
- case BTTV_PINNACLESAT:
+ case BTTV_BOARD_PINNACLESAT:
card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter);
break;
- case BTTV_PC_HDTV:
+ case BTTV_BOARD_PC_HDTV:
card->fe = or51211_attach(&or51211_config, card->i2c_adapter);
break;
}
@@ -746,7 +804,7 @@ static int dvb_bt8xx_probe(struct device *dev)
card->i2c_adapter = &sub->core->i2c_adap;
switch(sub->core->type) {
- case BTTV_PINNACLESAT:
+ case BTTV_BOARD_PINNACLESAT:
card->gpio_mode = 0x0400c060;
/* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR,
BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */
@@ -754,8 +812,8 @@ static int dvb_bt8xx_probe(struct device *dev)
card->irq_err_ignore = 0;
break;
-#ifdef BTTV_DVICO_DVBT_LITE
- case BTTV_DVICO_DVBT_LITE:
+#ifdef BTTV_BOARD_DVICO_DVBT_LITE
+ case BTTV_BOARD_DVICO_DVBT_LITE:
#endif
card->gpio_mode = 0x0400C060;
card->op_sync_orin = 0;
@@ -765,26 +823,34 @@ static int dvb_bt8xx_probe(struct device *dev)
* DA_APP(parallel) */
break;
-#ifdef BTTV_TWINHAN_VP3021
- case BTTV_TWINHAN_VP3021:
+#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE
+ case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
+#endif
+ card->gpio_mode = 0x0400c060;
+ card->op_sync_orin = BT878_RISC_SYNC_MASK;
+ card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
+ break;
+
+#ifdef BTTV_BOARD_TWINHAN_VP3021
+ case BTTV_BOARD_TWINHAN_VP3021:
#else
- case BTTV_NEBULA_DIGITV:
+ case BTTV_BOARD_NEBULA_DIGITV:
#endif
- case BTTV_AVDVBT_761:
+ case BTTV_BOARD_AVDVBT_761:
card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
card->op_sync_orin = 0;
card->irq_err_ignore = 0;
/* A_PWRDN DA_SBR DA_APP (high speed serial) */
break;
- case BTTV_AVDVBT_771: //case 0x07711461:
+ case BTTV_BOARD_AVDVBT_771: //case 0x07711461:
card->gpio_mode = 0x0400402B;
card->op_sync_orin = BT878_RISC_SYNC_MASK;
card->irq_err_ignore = 0;
/* A_PWRDN DA_SBR DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/
break;
- case BTTV_TWINHAN_DST:
+ case BTTV_BOARD_TWINHAN_DST:
card->gpio_mode = 0x2204f2c;
card->op_sync_orin = BT878_RISC_SYNC_MASK;
card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR |
@@ -802,7 +868,7 @@ static int dvb_bt8xx_probe(struct device *dev)
* RISC+FIFO ENABLE */
break;
- case BTTV_PC_HDTV:
+ case BTTV_BOARD_PC_HDTV:
card->gpio_mode = 0x0100EC7B;
card->op_sync_orin = 0;
card->irq_err_ignore = 0;
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
index 9ec8e5bd6c1..cf035a80361 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
@@ -35,6 +35,7 @@
#include "nxt6000.h"
#include "cx24110.h"
#include "or51211.h"
+#include "lgdt330x.h"
struct dvb_bt8xx_card {
struct semaphore lock;
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index 9719a3b30f7..7d7b0067f22 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -48,8 +48,11 @@
* DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter.
*/
+#ifndef DMX_MAX_SECTION_SIZE
+#define DMX_MAX_SECTION_SIZE 4096
+#endif
#ifndef DMX_MAX_SECFEED_SIZE
-#define DMX_MAX_SECFEED_SIZE 4096
+#define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188)
#endif
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index dc476dda2b7..b4c899b1595 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -246,7 +246,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
for (n = 0; sec->secbufp + 2 < limit; n++) {
seclen = section_length(sec->secbuf);
- if (seclen <= 0 || seclen > DMX_MAX_SECFEED_SIZE
+ if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE
|| seclen + sec->secbufp > limit)
return 0;
sec->seclen = seclen;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index a8bc84240b5..6ffa6b21636 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -42,8 +42,6 @@
#include "dvb_frontend.h"
#include "dvbdev.h"
-// #define DEBUG_LOCKLOSS 1
-
static int dvb_frontend_debug;
static int dvb_shutdown_timeout = 5;
static int dvb_force_auto_inversion;
@@ -438,25 +436,6 @@ static int dvb_frontend_thread(void *data)
if (s & FE_HAS_LOCK)
continue;
else { /* if we _WERE_ tuned, but now don't have a lock */
-#ifdef DEBUG_LOCKLOSS
- /* first of all try setting the tone again if it was on - this
- * sometimes works around problems with noisy power supplies */
- if (fe->ops->set_tone && (fepriv->tone == SEC_TONE_ON)) {
- fe->ops->set_tone(fe, fepriv->tone);
- mdelay(100);
- s = 0;
- fe->ops->read_status(fe, &s);
- if (s & FE_HAS_LOCK) {
- printk("DVB%i: Lock was lost, but regained by setting "
- "the tone. This may indicate your power supply "
- "is noisy/slightly incompatable with this DVB-S "
- "adapter\n", fe->dvb->num);
- fepriv->state = FESTATE_TUNED;
- continue;
- }
- }
-#endif
- /* some other reason for losing the lock - start zigzagging */
fepriv->state = FESTATE_ZIGZAG_FAST;
fepriv->started_auto_step = fepriv->auto_step;
check_wrapped = 0;
@@ -577,6 +556,49 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
fepriv->thread_pid);
}
+s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)
+{
+ return ((curtime.tv_usec < lasttime.tv_usec) ?
+ 1000000 - lasttime.tv_usec + curtime.tv_usec :
+ curtime.tv_usec - lasttime.tv_usec);
+}
+EXPORT_SYMBOL(timeval_usec_diff);
+
+static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec)
+{
+ curtime->tv_usec += add_usec;
+ if (curtime->tv_usec >= 1000000) {
+ curtime->tv_usec -= 1000000;
+ curtime->tv_sec++;
+ }
+}
+
+/*
+ * Sleep until gettimeofday() > waketime + add_usec
+ * This needs to be as precise as possible, but as the delay is
+ * usually between 2ms and 32ms, it is done using a scheduled msleep
+ * followed by usleep (normally a busy-wait loop) for the remainder
+ */
+void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec)
+{
+ struct timeval lasttime;
+ s32 delta, newdelta;
+
+ timeval_usec_add(waketime, add_usec);
+
+ do_gettimeofday(&lasttime);
+ delta = timeval_usec_diff(lasttime, *waketime);
+ if (delta > 2500) {
+ msleep((delta - 1500) / 1000);
+ do_gettimeofday(&lasttime);
+ newdelta = timeval_usec_diff(lasttime, *waketime);
+ delta = (newdelta > delta) ? 0 : newdelta;
+ }
+ if (delta > 0)
+ udelay(delta);
+}
+EXPORT_SYMBOL(dvb_frontend_sleep_until);
+
static int dvb_frontend_start(struct dvb_frontend *fe)
{
int ret;
@@ -728,6 +750,60 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned int) parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
+ } else if (fe->ops->set_voltage) {
+ /*
+ * NOTE: This is a fallback condition. Some frontends
+ * (stv0299 for instance) take longer than 8msec to
+ * respond to a set_voltage command. Those switches
+ * need custom routines to switch properly. For all
+ * other frontends, the following shoule work ok.
+ * Dish network legacy switches (as used by Dish500)
+ * are controlled by sending 9-bit command words
+ * spaced 8msec apart.
+ * the actual command word is switch/port dependant
+ * so it is up to the userspace application to send
+ * the right command.
+ * The command must always start with a '0' after
+ * initialization, so parg is 8 bits and does not
+ * include the initialization or start bit
+ */
+ unsigned int cmd = ((unsigned int) parg) << 1;
+ struct timeval nexttime;
+ struct timeval tv[10];
+ int i;
+ u8 last = 1;
+ if (dvb_frontend_debug)
+ printk("%s switch command: 0x%04x\n", __FUNCTION__, cmd);
+ do_gettimeofday(&nexttime);
+ if (dvb_frontend_debug)
+ memcpy(&tv[0], &nexttime, sizeof(struct timeval));
+ /* before sending a command, initialize by sending
+ * a 32ms 18V to the switch
+ */
+ fe->ops->set_voltage(fe, SEC_VOLTAGE_18);
+ dvb_frontend_sleep_until(&nexttime, 32000);
+
+ for (i = 0; i < 9; i++) {
+ if (dvb_frontend_debug)
+ do_gettimeofday(&tv[i + 1]);
+ if ((cmd & 0x01) != last) {
+ /* set voltage to (last ? 13V : 18V) */
+ fe->ops->set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
+ last = (last) ? 0 : 1;
+ }
+ cmd = cmd >> 1;
+ if (i != 8)
+ dvb_frontend_sleep_until(&nexttime, 8000);
+ }
+ if (dvb_frontend_debug) {
+ printk("%s(%d): switch delay (should be 32k followed by all 8k\n",
+ __FUNCTION__, fe->dvb->num);
+ for (i = 1; i < 10; i++)
+ printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
+ }
+ err = 0;
+ fepriv->state = FESTATE_DISEQC;
+ fepriv->status = 0;
}
break;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index 9c2c1d1136b..348c9b0b988 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -101,4 +101,7 @@ extern int dvb_register_frontend(struct dvb_adapter* dvb,
extern int dvb_unregister_frontend(struct dvb_frontend* fe);
+extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec);
+extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime);
+
#endif
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c
index e55322ef76b..49f541d9a04 100644
--- a/drivers/media/dvb/dvb-usb/a800.c
+++ b/drivers/media/dvb/dvb-usb/a800.c
@@ -43,11 +43,9 @@ static struct dvb_usb_rc_key a800_rc_keys[] = {
{ 0x02, 0x13, KEY_RIGHT }, /* R / CH RTN */
{ 0x02, 0x17, KEY_PROG2 }, /* SNAP SHOT */
{ 0x02, 0x10, KEY_PROG3 }, /* 16-CH PREV */
- { 0x02, 0x03, KEY_CHANNELUP }, /* CH UP */
{ 0x02, 0x1e, KEY_VOLUMEDOWN }, /* VOL DOWN */
{ 0x02, 0x0c, KEY_ZOOM }, /* FULL SCREEN */
{ 0x02, 0x1f, KEY_VOLUMEUP }, /* VOL UP */
- { 0x02, 0x02, KEY_CHANNELDOWN }, /* CH DOWN */
{ 0x02, 0x14, KEY_MUTE }, /* MUTE */
{ 0x02, 0x08, KEY_AUDIO }, /* AUDIO */
{ 0x02, 0x19, KEY_RECORD }, /* RECORD */
@@ -57,8 +55,6 @@ static struct dvb_usb_rc_key a800_rc_keys[] = {
{ 0x02, 0x1d, KEY_BACK }, /* << / RED */
{ 0x02, 0x1c, KEY_FORWARD }, /* >> / YELLOW */
{ 0x02, 0x03, KEY_TEXT }, /* TELETEXT */
- { 0x02, 0x01, KEY_FIRST }, /* |<< / GREEN */
- { 0x02, 0x00, KEY_LAST }, /* >>| / BLUE */
{ 0x02, 0x04, KEY_EPG }, /* EPG */
{ 0x02, 0x15, KEY_MENU }, /* MENU */
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index 0058505634a..aa271a2496d 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -82,13 +82,15 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d)
static struct dvb_usb_properties dibusb1_1_properties;
static struct dvb_usb_properties dibusb1_1_an2235_properties;
static struct dvb_usb_properties dibusb2_0b_properties;
+static struct dvb_usb_properties artec_t1_usb2_properties;
static int dibusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
if (dvb_usb_device_init(intf,&dibusb1_1_properties,THIS_MODULE,NULL) == 0 ||
dvb_usb_device_init(intf,&dibusb1_1_an2235_properties,THIS_MODULE,NULL) == 0 ||
- dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE,NULL) == 0)
+ dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE,NULL) == 0 ||
+ dvb_usb_device_init(intf,&artec_t1_usb2_properties,THIS_MODULE,NULL) == 0)
return 0;
return -EINVAL;
@@ -128,10 +130,13 @@ static struct usb_device_id dibusb_dib3000mb_table [] = {
/* 27 */ { USB_DEVICE(USB_VID_KWORLD, USB_PID_KWORLD_VSTREAM_COLD) },
+/* 28 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
+/* 29 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) },
+
// #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
-/* 28 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
+/* 30 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
#endif
{ } /* Terminating entry */
};
@@ -264,7 +269,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
},
#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
{ "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
- { &dibusb_dib3000mb_table[28], NULL },
+ { &dibusb_dib3000mb_table[30], NULL },
{ NULL },
},
#endif
@@ -273,7 +278,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
static struct dvb_usb_properties dibusb2_0b_properties = {
.caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
- .pid_filter_count = 32,
+ .pid_filter_count = 16,
.usb_ctrl = CYPRESS_FX2,
@@ -321,6 +326,52 @@ static struct dvb_usb_properties dibusb2_0b_properties = {
}
};
+static struct dvb_usb_properties artec_t1_usb2_properties = {
+ .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+ .pid_filter_count = 16,
+
+ .usb_ctrl = CYPRESS_FX2,
+
+ .firmware = "dvb-usb-dibusb-6.0.0.8.fw",
+
+ .size_of_priv = sizeof(struct dibusb_state),
+
+ .streaming_ctrl = dibusb2_0_streaming_ctrl,
+ .pid_filter = dibusb_pid_filter,
+ .pid_filter_ctrl = dibusb_pid_filter_ctrl,
+ .power_ctrl = dibusb2_0_power_ctrl,
+ .frontend_attach = dibusb_dib3000mb_frontend_attach,
+ .tuner_attach = dibusb_tuner_probe_and_attach,
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dibusb_rc_keys,
+ .rc_key_map_size = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_query = dibusb_rc_query,
+
+ .i2c_algo = &dibusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 7,
+ .endpoint = 0x06,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { "Artec T1 USB2.0",
+ { &dibusb_dib3000mb_table[28], NULL },
+ { &dibusb_dib3000mb_table[29], NULL },
+ },
+ }
+};
+
static struct usb_driver dibusb_driver = {
.owner = THIS_MODULE,
.name = "dvb_usb_dibusb_mb",
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h
index 6611f62977c..2d99d05c7ea 100644
--- a/drivers/media/dvb/dvb-usb/dibusb.h
+++ b/drivers/media/dvb/dvb-usb/dibusb.h
@@ -11,7 +11,9 @@
#ifndef _DVB_USB_DIBUSB_H_
#define _DVB_USB_DIBUSB_H_
-#define DVB_USB_LOG_PREFIX "dibusb"
+#ifndef DVB_USB_LOG_PREFIX
+ #define DVB_USB_LOG_PREFIX "dibusb"
+#endif
#include "dvb-usb.h"
#include "dib3000.h"
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 0818996bf15..6be99e537e1 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -43,10 +43,14 @@
#define USB_PID_COMPRO_DVBU2000_WARM 0xd001
#define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c
#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d
+#define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064
+#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065
#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8
#define USB_PID_DIBCOM_MOD3000_WARM 0x0bb9
#define USB_PID_DIBCOM_MOD3001_COLD 0x0bc6
#define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7
+#define USB_PID_DIBCOM_STK7700 0x1e14
+#define USB_PID_DIBCOM_STK7700_REENUM 0x1e15
#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131
#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
@@ -68,6 +72,7 @@
#define USB_PID_ULTIMA_TVBOX_AN2235_WARM 0x8108
#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD 0x2235
#define USB_PID_ULTIMA_TVBOX_USB2_COLD 0x8109
+#define USB_PID_ULTIMA_TVBOX_USB2_WARM 0x810a
#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613
#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002
#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
index f5799a4c228..36b7048c02d 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
@@ -196,7 +196,9 @@ static int dvb_usb_allocate_stream_buffers(struct dvb_usb_device *d, int num, un
dvb_usb_free_stream_buffers(d);
return -ENOMEM;
}
- deb_mem("buffer %d: %p (dma: %d)\n",d->buf_num,d->buf_list[d->buf_num],d->dma_addr[d->buf_num]);
+ deb_mem("buffer %d: %p (dma: %llu)\n",
+ d->buf_num, d->buf_list[d->buf_num],
+ (unsigned long long)d->dma_addr[d->buf_num]);
memset(d->buf_list[d->buf_num],0,size);
}
deb_mem("allocation successful\n");
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index a50a41f6f79..8e269e1c1f9 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -164,6 +164,14 @@ config DVB_NXT2002
help
An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
+config DVB_NXT200X
+ tristate "Nextwave NXT2002/NXT2004 based"
+ depends on DVB_CORE
+ select FW_LOADER
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+ to support this frontend.
+
config DVB_OR51211
tristate "or51211 based (pcHDTV HD2000 card)"
depends on DVB_CORE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index ad8658ffd60..a98760fe08a 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_DVB_TDA80XX) += tda80xx.o
obj-$(CONFIG_DVB_TDA10021) += tda10021.o
obj-$(CONFIG_DVB_STV0297) += stv0297.o
obj-$(CONFIG_DVB_NXT2002) += nxt2002.o
+obj-$(CONFIG_DVB_NXT200X) += nxt200x.o
obj-$(CONFIG_DVB_OR51211) += or51211.o
obj-$(CONFIG_DVB_OR51132) += or51132.o
obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 536c35d969b..f857b869616 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -226,7 +226,7 @@ struct dvb_pll_desc dvb_pll_tua6034 = {
EXPORT_SYMBOL(dvb_pll_tua6034);
/* Infineon TUA6034
- * used in LG Innotek TDVS-H062F
+ * used in LG TDVS H061F and LG TDVS H062F
*/
struct dvb_pll_desc dvb_pll_tdvs_tua6034 = {
.name = "LG/Infineon TUA6034",
@@ -292,6 +292,58 @@ struct dvb_pll_desc dvb_pll_tded4 = {
};
EXPORT_SYMBOL(dvb_pll_tded4);
+/* ALPS TDHU2
+ * used in AverTVHD MCE A180
+ */
+struct dvb_pll_desc dvb_pll_tdhu2 = {
+ .name = "ALPS TDHU2",
+ .min = 54000000,
+ .max = 864000000,
+ .count = 4,
+ .entries = {
+ { 162000000, 44000000, 62500, 0x85, 0x01 },
+ { 426000000, 44000000, 62500, 0x85, 0x02 },
+ { 782000000, 44000000, 62500, 0x85, 0x08 },
+ { 999999999, 44000000, 62500, 0x85, 0x88 },
+ }
+};
+EXPORT_SYMBOL(dvb_pll_tdhu2);
+
+/* Philips TUV1236D
+ * used in ATI HDTV Wonder
+ */
+struct dvb_pll_desc dvb_pll_tuv1236d = {
+ .name = "Philips TUV1236D",
+ .min = 54000000,
+ .max = 864000000,
+ .count = 3,
+ .entries = {
+ { 157250000, 44000000, 62500, 0xc6, 0x41 },
+ { 454000000, 44000000, 62500, 0xc6, 0x42 },
+ { 999999999, 44000000, 62500, 0xc6, 0x44 },
+ },
+};
+EXPORT_SYMBOL(dvb_pll_tuv1236d);
+
+/* Samsung TBMV30111IN
+ * used in Air2PC ATSC - 2nd generation (nxt2002)
+ */
+struct dvb_pll_desc dvb_pll_tbmv30111in = {
+ .name = "Samsung TBMV30111IN",
+ .min = 54000000,
+ .max = 860000000,
+ .count = 4,
+ .entries = {
+ { 172000000, 44000000, 166666, 0xb4, 0x01 },
+ { 214000000, 44000000, 166666, 0xb4, 0x02 },
+ { 467000000, 44000000, 166666, 0xbc, 0x02 },
+ { 721000000, 44000000, 166666, 0xbc, 0x08 },
+ { 841000000, 44000000, 166666, 0xf4, 0x08 },
+ { 999999999, 44000000, 166666, 0xfc, 0x02 },
+ }
+};
+EXPORT_SYMBOL(dvb_pll_tbmv30111in);
+
/* ----------------------------------------------------------- */
/* code */
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 205b2d1a885..497d31dcf41 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -36,6 +36,10 @@ extern struct dvb_pll_desc dvb_pll_tda665x;
extern struct dvb_pll_desc dvb_pll_fmd1216me;
extern struct dvb_pll_desc dvb_pll_tded4;
+extern struct dvb_pll_desc dvb_pll_tuv1236d;
+extern struct dvb_pll_desc dvb_pll_tdhu2;
+extern struct dvb_pll_desc dvb_pll_tbmv30111in;
+
int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
u32 freq, int bandwidth);
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index 7852b83b82d..6a33f5a19a8 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -26,6 +26,8 @@
* DViCO FusionHDTV 3 Gold-Q
* DViCO FusionHDTV 3 Gold-T
* DViCO FusionHDTV 5 Gold
+ * DViCO FusionHDTV 5 Lite
+ * Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
*
* TODO:
* signal strength always returns 0.
@@ -222,6 +224,11 @@ static int lgdt330x_init(struct dvb_frontend* fe)
0x4c, 0x14
};
+ static u8 flip_lgdt3303_init_data[] = {
+ 0x4c, 0x14,
+ 0x87, 0xf3
+ };
+
struct lgdt330x_state* state = fe->demodulator_priv;
char *chip_name;
int err;
@@ -234,8 +241,13 @@ static int lgdt330x_init(struct dvb_frontend* fe)
break;
case LGDT3303:
chip_name = "LGDT3303";
- err = i2c_write_demod_bytes(state, lgdt3303_init_data,
- sizeof(lgdt3303_init_data));
+ if (state->config->clock_polarity_flip) {
+ err = i2c_write_demod_bytes(state, flip_lgdt3303_init_data,
+ sizeof(flip_lgdt3303_init_data));
+ } else {
+ err = i2c_write_demod_bytes(state, lgdt3303_init_data,
+ sizeof(lgdt3303_init_data));
+ }
break;
default:
chip_name = "undefined";
@@ -743,9 +755,8 @@ static struct dvb_frontend_ops lgdt3302_ops = {
.frequency_min= 54000000,
.frequency_max= 858000000,
.frequency_stepsize= 62500,
- /* Symbol rate is for all VSB modes need to check QAM */
- .symbol_rate_min = 10762000,
- .symbol_rate_max = 10762000,
+ .symbol_rate_min = 5056941, /* QAM 64 */
+ .symbol_rate_max = 10762000, /* VSB 8 */
.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
},
.init = lgdt330x_init,
@@ -767,9 +778,8 @@ static struct dvb_frontend_ops lgdt3303_ops = {
.frequency_min= 54000000,
.frequency_max= 858000000,
.frequency_stepsize= 62500,
- /* Symbol rate is for all VSB modes need to check QAM */
- .symbol_rate_min = 10762000,
- .symbol_rate_max = 10762000,
+ .symbol_rate_min = 5056941, /* QAM 64 */
+ .symbol_rate_max = 10762000, /* VSB 8 */
.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
},
.init = lgdt330x_init,
diff --git a/drivers/media/dvb/frontends/lgdt330x.h b/drivers/media/dvb/frontends/lgdt330x.h
index e209ba1e47c..2a6529cccf1 100644
--- a/drivers/media/dvb/frontends/lgdt330x.h
+++ b/drivers/media/dvb/frontends/lgdt330x.h
@@ -47,6 +47,10 @@ struct lgdt330x_config
/* Need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+
+ /* Flip the polarity of the mpeg data transfer clock using alternate init data
+ * This option applies ONLY to LGDT3303 - 0:disabled (default) 1:enabled */
+ int clock_polarity_flip;
};
extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
new file mode 100644
index 00000000000..bad0933eb71
--- /dev/null
+++ b/drivers/media/dvb/frontends/nxt200x.c
@@ -0,0 +1,1205 @@
+/*
+ * Support for NXT2002 and NXT2004 - VSB/QAM
+ *
+ * Copyright (C) 2005 Kirk Lapray (kirk.lapray@gmail.com)
+ * based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net>
+ * and nxt2004 by Jean-Francois Thibert (jeanfrancois@sagetv.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+/*
+ * NOTES ABOUT THIS DRIVER
+ *
+ * This Linux driver supports:
+ * B2C2/BBTI Technisat Air2PC - ATSC (NXT2002)
+ * AverTVHD MCE A180 (NXT2004)
+ * ATI HDTV Wonder (NXT2004)
+ *
+ * This driver needs external firmware. Please use the command
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" or
+ * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to
+ * download/extract the appropriate firmware, and then copy it to
+ * /usr/lib/hotplug/firmware/ or /lib/firmware/
+ * (depending on configuration of firmware hotplug).
+ */
+#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
+#define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw"
+#define CRC_CCIT_MASK 0x1021
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include "dvb_frontend.h"
+#include "dvb-pll.h"
+#include "nxt200x.h"
+
+struct nxt200x_state {
+
+ struct i2c_adapter* i2c;
+ struct dvb_frontend_ops ops;
+ const struct nxt200x_config* config;
+ struct dvb_frontend frontend;
+
+ /* demodulator private data */
+ nxt_chip_type demod_chip;
+ u8 initialised:1;
+};
+
+static int debug;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "nxt200x: " args); \
+ } while (0)
+
+static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len)
+{
+ int err;
+ struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len };
+
+ if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+ printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n",
+ __FUNCTION__, addr, err);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static u8 i2c_readbytes (struct nxt200x_state* state, u8 addr, u8* buf, u8 len)
+{
+ int err;
+ struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len };
+
+ if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+ printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n",
+ __FUNCTION__, addr, err);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg, u8 *buf, u8 len)
+{
+ u8 buf2 [len+1];
+ int err;
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 };
+
+ buf2[0] = reg;
+ memcpy(&buf2[1], buf, len);
+
+ if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+ printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n",
+ __FUNCTION__, state->config->demod_address, err);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static u8 nxt200x_readbytes (struct nxt200x_state* state, u8 reg, u8* buf, u8 len)
+{
+ u8 reg2 [] = { reg };
+
+ struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = reg2, .len = 1 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } };
+
+ int err;
+
+ if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {
+ printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n",
+ __FUNCTION__, state->config->demod_address, err);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static u16 nxt200x_crc(u16 crc, u8 c)
+{
+ u8 i;
+ u16 input = (u16) c & 0xFF;
+
+ input<<=8;
+ for(i=0; i<8; i++) {
+ if((crc^input) & 0x8000)
+ crc=(crc<<1)^CRC_CCIT_MASK;
+ else
+ crc<<=1;
+ input<<=1;
+ }
+ return crc;
+}
+
+static int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len)
+{
+ u8 attr, len2, buf;
+ dprintk("%s\n", __FUNCTION__);
+
+ /* set mutli register register */
+ nxt200x_writebytes(state, 0x35, &reg, 1);
+
+ /* send the actual data */
+ nxt200x_writebytes(state, 0x36, data, len);
+
+ switch (state->demod_chip) {
+ case NXT2002:
+ len2 = len;
+ buf = 0x02;
+ break;
+ case NXT2004:
+ /* probably not right, but gives correct values */
+ attr = 0x02;
+ if (reg & 0x80) {
+ attr = attr << 1;
+ if (reg & 0x04)
+ attr = attr >> 1;
+ }
+ /* set write bit */
+ len2 = ((attr << 4) | 0x10) | len;
+ buf = 0x80;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ /* set multi register length */
+ nxt200x_writebytes(state, 0x34, &len2, 1);
+
+ /* toggle the multireg write bit */
+ nxt200x_writebytes(state, 0x21, &buf, 1);
+
+ nxt200x_readbytes(state, 0x21, &buf, 1);
+
+ switch (state->demod_chip) {
+ case NXT2002:
+ if ((buf & 0x02) == 0)
+ return 0;
+ break;
+ case NXT2004:
+ if (buf == 0)
+ return 0;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ printk(KERN_WARNING "nxt200x: Error writing multireg register 0x%02X\n",reg);
+
+ return 0;
+}
+
+static int nxt200x_readreg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len)
+{
+ int i;
+ u8 buf, len2, attr;
+ dprintk("%s\n", __FUNCTION__);
+
+ /* set mutli register register */
+ nxt200x_writebytes(state, 0x35, &reg, 1);
+
+ switch (state->demod_chip) {
+ case NXT2002:
+ /* set multi register length */
+ len2 = len & 0x80;
+ nxt200x_writebytes(state, 0x34, &len2, 1);
+
+ /* read the actual data */
+ nxt200x_readbytes(state, reg, data, len);
+ return 0;
+ break;
+ case NXT2004:
+ /* probably not right, but gives correct values */
+ attr = 0x02;
+ if (reg & 0x80) {
+ attr = attr << 1;
+ if (reg & 0x04)
+ attr = attr >> 1;
+ }
+
+ /* set multi register length */
+ len2 = (attr << 4) | len;
+ nxt200x_writebytes(state, 0x34, &len2, 1);
+
+ /* toggle the multireg bit*/
+ buf = 0x80;
+ nxt200x_writebytes(state, 0x21, &buf, 1);
+
+ /* read the actual data */
+ for(i = 0; i < len; i++) {
+ nxt200x_readbytes(state, 0x36 + i, &data[i], 1);
+ }
+ return 0;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+}
+
+static void nxt200x_microcontroller_stop (struct nxt200x_state* state)
+{
+ u8 buf, stopval, counter = 0;
+ dprintk("%s\n", __FUNCTION__);
+
+ /* set correct stop value */
+ switch (state->demod_chip) {
+ case NXT2002:
+ stopval = 0x40;
+ break;
+ case NXT2004:
+ stopval = 0x10;
+ break;
+ default:
+ stopval = 0;
+ break;
+ }
+
+ buf = 0x80;
+ nxt200x_writebytes(state, 0x22, &buf, 1);
+
+ while (counter < 20) {
+ nxt200x_readbytes(state, 0x31, &buf, 1);
+ if (buf & stopval)
+ return;
+ msleep(10);
+ counter++;
+ }
+
+ printk(KERN_WARNING "nxt200x: Timeout waiting for nxt200x to stop. This is ok after firmware upload.\n");
+ return;
+}
+
+static void nxt200x_microcontroller_start (struct nxt200x_state* state)
+{
+ u8 buf;
+ dprintk("%s\n", __FUNCTION__);
+
+ buf = 0x00;
+ nxt200x_writebytes(state, 0x22, &buf, 1);
+}
+
+static void nxt2004_microcontroller_init (struct nxt200x_state* state)
+{
+ u8 buf[9];
+ u8 counter = 0;
+ dprintk("%s\n", __FUNCTION__);
+
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0x2b, buf, 1);
+ buf[0] = 0x70;
+ nxt200x_writebytes(state, 0x34, buf, 1);
+ buf[0] = 0x04;
+ nxt200x_writebytes(state, 0x35, buf, 1);
+ buf[0] = 0x01; buf[1] = 0x23; buf[2] = 0x45; buf[3] = 0x67; buf[4] = 0x89;
+ buf[5] = 0xAB; buf[6] = 0xCD; buf[7] = 0xEF; buf[8] = 0xC0;
+ nxt200x_writebytes(state, 0x36, buf, 9);
+ buf[0] = 0x80;
+ nxt200x_writebytes(state, 0x21, buf, 1);
+
+ while (counter < 20) {
+ nxt200x_readbytes(state, 0x21, buf, 1);
+ if (buf[0] == 0)
+ return;
+ msleep(10);
+ counter++;
+ }
+
+ printk(KERN_WARNING "nxt200x: Timeout waiting for nxt2004 to init.\n");
+
+ return;
+}
+
+static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
+{
+ u8 buf, count = 0;
+
+ dprintk("%s\n", __FUNCTION__);
+
+ dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[0], data[1], data[2], data[3]);
+
+ /* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip.
+ * direct write is required for Philips TUV1236D and ALPS TDHU2 */
+ switch (state->demod_chip) {
+ case NXT2004:
+ if (i2c_writebytes(state, state->config->pll_address, data, 4))
+ printk(KERN_WARNING "nxt200x: error writing to tuner\n");
+ /* wait until we have a lock */
+ while (count < 20) {
+ i2c_readbytes(state, state->config->pll_address, &buf, 1);
+ if (buf & 0x40)
+ return 0;
+ msleep(100);
+ count++;
+ }
+ printk("nxt2004: timeout waiting for tuner lock\n");
+ break;
+ case NXT2002:
+ /* set the i2c transfer speed to the tuner */
+ buf = 0x03;
+ nxt200x_writebytes(state, 0x20, &buf, 1);
+
+ /* setup to transfer 4 bytes via i2c */
+ buf = 0x04;
+ nxt200x_writebytes(state, 0x34, &buf, 1);
+
+ /* write actual tuner bytes */
+ nxt200x_writebytes(state, 0x36, data, 4);
+
+ /* set tuner i2c address */
+ buf = state->config->pll_address;
+ nxt200x_writebytes(state, 0x35, &buf, 1);
+
+ /* write UC Opmode to begin transfer */
+ buf = 0x80;
+ nxt200x_writebytes(state, 0x21, &buf, 1);
+
+ while (count < 20) {
+ nxt200x_readbytes(state, 0x21, &buf, 1);
+ if ((buf & 0x80)== 0x00)
+ return 0;
+ msleep(100);
+ count++;
+ }
+ printk("nxt2002: timeout error writing tuner\n");
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ return 0;
+}
+
+static void nxt200x_agc_reset(struct nxt200x_state* state)
+{
+ u8 buf;
+ dprintk("%s\n", __FUNCTION__);
+
+ switch (state->demod_chip) {
+ case NXT2002:
+ buf = 0x08;
+ nxt200x_writebytes(state, 0x08, &buf, 1);
+ buf = 0x00;
+ nxt200x_writebytes(state, 0x08, &buf, 1);
+ break;
+ case NXT2004:
+ nxt200x_readreg_multibyte(state, 0x08, &buf, 1);
+ buf = 0x08;
+ nxt200x_writereg_multibyte(state, 0x08, &buf, 1);
+ buf = 0x00;
+ nxt200x_writereg_multibyte(state, 0x08, &buf, 1);
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
+{
+
+ struct nxt200x_state* state = fe->demodulator_priv;
+ u8 buf[3], written = 0, chunkpos = 0;
+ u16 rambase, position, crc = 0;
+
+ dprintk("%s\n", __FUNCTION__);
+ dprintk("Firmware is %zu bytes\n", fw->size);
+
+ /* Get the RAM base for this nxt2002 */
+ nxt200x_readbytes(state, 0x10, buf, 1);
+
+ if (buf[0] & 0x10)
+ rambase = 0x1000;
+ else
+ rambase = 0x0000;
+
+ dprintk("rambase on this nxt2002 is %04X\n", rambase);
+
+ /* Hold the micro in reset while loading firmware */
+ buf[0] = 0x80;
+ nxt200x_writebytes(state, 0x2B, buf, 1);
+
+ for (position = 0; position < fw->size; position++) {
+ if (written == 0) {
+ crc = 0;
+ chunkpos = 0x28;
+ buf[0] = ((rambase + position) >> 8);
+ buf[1] = (rambase + position) & 0xFF;
+ buf[2] = 0x81;
+ /* write starting address */
+ nxt200x_writebytes(state, 0x29, buf, 3);
+ }
+ written++;
+ chunkpos++;
+
+ if ((written % 4) == 0)
+ nxt200x_writebytes(state, chunkpos, &fw->data[position-3], 4);
+
+ crc = nxt200x_crc(crc, fw->data[position]);
+
+ if ((written == 255) || (position+1 == fw->size)) {
+ /* write remaining bytes of firmware */
+ nxt200x_writebytes(state, chunkpos+4-(written %4),
+ &fw->data[position-(written %4) + 1],
+ written %4);
+ buf[0] = crc << 8;
+ buf[1] = crc & 0xFF;
+
+ /* write crc */
+ nxt200x_writebytes(state, 0x2C, buf, 2);
+
+ /* do a read to stop things */
+ nxt200x_readbytes(state, 0x2A, buf, 1);
+
+ /* set transfer mode to complete */
+ buf[0] = 0x80;
+ nxt200x_writebytes(state, 0x2B, buf, 1);
+
+ written = 0;
+ }
+ }
+
+ return 0;
+};
+
+static int nxt2004_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
+{
+
+ struct nxt200x_state* state = fe->demodulator_priv;
+ u8 buf[3];
+ u16 rambase, position, crc=0;
+
+ dprintk("%s\n", __FUNCTION__);
+ dprintk("Firmware is %zu bytes\n", fw->size);
+
+ /* set rambase */
+ rambase = 0x1000;
+
+ /* hold the micro in reset while loading firmware */
+ buf[0] = 0x80;
+ nxt200x_writebytes(state, 0x2B, buf,1);
+
+ /* calculate firmware CRC */
+ for (position = 0; position < fw->size; position++) {
+ crc = nxt200x_crc(crc, fw->data[position]);
+ }
+
+ buf[0] = rambase >> 8;
+ buf[1] = rambase & 0xFF;
+ buf[2] = 0x81;
+ /* write starting address */
+ nxt200x_writebytes(state,0x29,buf,3);
+
+ for (position = 0; position < fw->size;) {
+ nxt200x_writebytes(state, 0x2C, &fw->data[position],
+ fw->size-position > 255 ? 255 : fw->size-position);
+ position += (fw->size-position > 255 ? 255 : fw->size-position);
+ }
+ buf[0] = crc >> 8;
+ buf[1] = crc & 0xFF;
+
+ dprintk("firmware crc is 0x%02X 0x%02X\n", buf[0], buf[1]);
+
+ /* write crc */
+ nxt200x_writebytes(state, 0x2C, buf,2);
+
+ /* do a read to stop things */
+ nxt200x_readbytes(state, 0x2C, buf, 1);
+
+ /* set transfer mode to complete */
+ buf[0] = 0x80;
+ nxt200x_writebytes(state, 0x2B, buf,1);
+
+ return 0;
+};
+
+static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct nxt200x_state* state = fe->demodulator_priv;
+ u8 buf[4];
+
+ /* stop the micro first */
+ nxt200x_microcontroller_stop(state);
+
+ if (state->demod_chip == NXT2004) {
+ /* make sure demod is set to digital */
+ buf[0] = 0x04;
+ nxt200x_writebytes(state, 0x14, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0x17, buf, 1);
+ }
+
+ /* get tuning information */
+ dvb_pll_configure(state->config->pll_desc, buf, p->frequency, 0);
+
+ /* set additional params */
+ switch (p->u.vsb.modulation) {
+ case QAM_64:
+ case QAM_256:
+ /* Set punctured clock for QAM */
+ /* This is just a guess since I am unable to test it */
+ if (state->config->set_ts_params)
+ state->config->set_ts_params(fe, 1);
+
+ /* set input */
+ if (state->config->set_pll_input)
+ state->config->set_pll_input(buf, 1);
+ break;
+ case VSB_8:
+ /* Set non-punctured clock for VSB */
+ if (state->config->set_ts_params)
+ state->config->set_ts_params(fe, 0);
+
+ /* set input */
+ if (state->config->set_pll_input)
+ state->config->set_pll_input(buf, 0);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ /* write frequency information */
+ nxt200x_writetuner(state, buf);
+
+ /* reset the agc now that tuning has been completed */
+ nxt200x_agc_reset(state);
+
+ /* set target power level */
+ switch (p->u.vsb.modulation) {
+ case QAM_64:
+ case QAM_256:
+ buf[0] = 0x74;
+ break;
+ case VSB_8:
+ buf[0] = 0x70;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ nxt200x_writebytes(state, 0x42, buf, 1);
+
+ /* configure sdm */
+ switch (state->demod_chip) {
+ case NXT2002:
+ buf[0] = 0x87;
+ break;
+ case NXT2004:
+ buf[0] = 0x07;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ nxt200x_writebytes(state, 0x57, buf, 1);
+
+ /* write sdm1 input */
+ buf[0] = 0x10;
+ buf[1] = 0x00;
+ nxt200x_writebytes(state, 0x58, buf, 2);
+
+ /* write sdmx input */
+ switch (p->u.vsb.modulation) {
+ case QAM_64:
+ buf[0] = 0x68;
+ break;
+ case QAM_256:
+ buf[0] = 0x64;
+ break;
+ case VSB_8:
+ buf[0] = 0x60;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ buf[1] = 0x00;
+ nxt200x_writebytes(state, 0x5C, buf, 2);
+
+ /* write adc power lpf fc */
+ buf[0] = 0x05;
+ nxt200x_writebytes(state, 0x43, buf, 1);
+
+ if (state->demod_chip == NXT2004) {
+ /* write ??? */
+ buf[0] = 0x00;
+ buf[1] = 0x00;
+ nxt200x_writebytes(state, 0x46, buf, 2);
+ }
+
+ /* write accumulator2 input */
+ buf[0] = 0x80;
+ buf[1] = 0x00;
+ nxt200x_writebytes(state, 0x4B, buf, 2);
+
+ /* write kg1 */
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0x4D, buf, 1);
+
+ /* write sdm12 lpf fc */
+ buf[0] = 0x44;
+ nxt200x_writebytes(state, 0x55, buf, 1);
+
+ /* write agc control reg */
+ buf[0] = 0x04;
+ nxt200x_writebytes(state, 0x41, buf, 1);
+
+ if (state->demod_chip == NXT2004) {
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x24;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+ /* soft reset? */
+ nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+ buf[0] = 0x10;
+ nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+ nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x04;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x81, buf, 1);
+ buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x82, buf, 3);
+ nxt200x_readreg_multibyte(state, 0x88, buf, 1);
+ buf[0] = 0x11;
+ nxt200x_writereg_multibyte(state, 0x88, buf, 1);
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x44;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+ }
+
+ /* write agc ucgp0 */
+ switch (p->u.vsb.modulation) {
+ case QAM_64:
+ buf[0] = 0x02;
+ break;
+ case QAM_256:
+ buf[0] = 0x03;
+ break;
+ case VSB_8:
+ buf[0] = 0x00;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ nxt200x_writebytes(state, 0x30, buf, 1);
+
+ /* write agc control reg */
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0x41, buf, 1);
+
+ /* write accumulator2 input */
+ buf[0] = 0x80;
+ buf[1] = 0x00;
+ nxt200x_writebytes(state, 0x49, buf,2);
+ nxt200x_writebytes(state, 0x4B, buf,2);
+
+ /* write agc control reg */
+ buf[0] = 0x04;
+ nxt200x_writebytes(state, 0x41, buf, 1);
+
+ nxt200x_microcontroller_start(state);
+
+ if (state->demod_chip == NXT2004) {
+ nxt2004_microcontroller_init(state);
+
+ /* ???? */
+ buf[0] = 0xF0;
+ buf[1] = 0x00;
+ nxt200x_writebytes(state, 0x5C, buf, 2);
+ }
+
+ /* adjacent channel detection should be done here, but I don't
+ have any stations with this need so I cannot test it */
+
+ return 0;
+}
+
+static int nxt200x_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct nxt200x_state* state = fe->demodulator_priv;
+ u8 lock;
+ nxt200x_readbytes(state, 0x31, &lock, 1);
+
+ *status = 0;
+ if (lock & 0x20) {
+ *status |= FE_HAS_SIGNAL;
+ *status |= FE_HAS_CARRIER;
+ *status |= FE_HAS_VITERBI;
+ *status |= FE_HAS_SYNC;
+ *status |= FE_HAS_LOCK;
+ }
+ return 0;
+}
+
+static int nxt200x_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ struct nxt200x_state* state = fe->demodulator_priv;
+ u8 b[3];
+
+ nxt200x_readreg_multibyte(state, 0xE6, b, 3);
+
+ *ber = ((b[0] << 8) + b[1]) * 8;
+
+ return 0;
+}
+
+static int nxt200x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ struct nxt200x_state* state = fe->demodulator_priv;
+ u8 b[2];
+ u16 temp = 0;
+
+ /* setup to read cluster variance */
+ b[0] = 0x00;
+ nxt200x_writebytes(state, 0xA1, b, 1);
+
+ /* get multreg val */
+ nxt200x_readreg_multibyte(state, 0xA6, b, 2);
+
+ temp = (b[0] << 8) | b[1];
+ *strength = ((0x7FFF - temp) & 0x0FFF) * 16;
+
+ return 0;
+}
+
+static int nxt200x_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+
+ struct nxt200x_state* state = fe->demodulator_priv;
+ u8 b[2];
+ u16 temp = 0, temp2;
+ u32 snrdb = 0;
+
+ /* setup to read cluster variance */
+ b[0] = 0x00;
+ nxt200x_writebytes(state, 0xA1, b, 1);
+
+ /* get multreg val from 0xA6 */
+ nxt200x_readreg_multibyte(state, 0xA6, b, 2);
+
+ temp = (b[0] << 8) | b[1];
+ temp2 = 0x7FFF - temp;
+
+ /* snr will be in db */
+ if (temp2 > 0x7F00)
+ snrdb = 1000*24 + ( 1000*(30-24) * ( temp2 - 0x7F00 ) / ( 0x7FFF - 0x7F00 ) );
+ else if (temp2 > 0x7EC0)
+ snrdb = 1000*18 + ( 1000*(24-18) * ( temp2 - 0x7EC0 ) / ( 0x7F00 - 0x7EC0 ) );
+ else if (temp2 > 0x7C00)
+ snrdb = 1000*12 + ( 1000*(18-12) * ( temp2 - 0x7C00 ) / ( 0x7EC0 - 0x7C00 ) );
+ else
+ snrdb = 1000*0 + ( 1000*(12-0) * ( temp2 - 0 ) / ( 0x7C00 - 0 ) );
+
+ /* the value reported back from the frontend will be FFFF=32db 0000=0db */
+ *snr = snrdb * (0xFFFF/32000);
+
+ return 0;
+}
+
+static int nxt200x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct nxt200x_state* state = fe->demodulator_priv;
+ u8 b[3];
+
+ nxt200x_readreg_multibyte(state, 0xE6, b, 3);
+ *ucblocks = b[2];
+
+ return 0;
+}
+
+static int nxt200x_sleep(struct dvb_frontend* fe)
+{
+ return 0;
+}
+
+static int nxt2002_init(struct dvb_frontend* fe)
+{
+ struct nxt200x_state* state = fe->demodulator_priv;
+ const struct firmware *fw;
+ int ret;
+ u8 buf[2];
+
+ /* request the firmware, this will block until someone uploads it */
+ printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE);
+ ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE, &state->i2c->dev);
+ printk("nxt2002: Waiting for firmware upload(2)...\n");
+ if (ret) {
+ printk("nxt2002: No firmware uploaded (timeout or file not found?)\n");
+ return ret;
+ }
+
+ ret = nxt2002_load_firmware(fe, fw);
+ if (ret) {
+ printk("nxt2002: Writing firmware to device failed\n");
+ release_firmware(fw);
+ return ret;
+ }
+ printk("nxt2002: Firmware upload complete\n");
+
+ /* Put the micro into reset */
+ nxt200x_microcontroller_stop(state);
+
+ /* ensure transfer is complete */
+ buf[0]=0x00;
+ nxt200x_writebytes(state, 0x2B, buf, 1);
+
+ /* Put the micro into reset for real this time */
+ nxt200x_microcontroller_stop(state);
+
+ /* soft reset everything (agc,frontend,eq,fec)*/
+ buf[0] = 0x0F;
+ nxt200x_writebytes(state, 0x08, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0x08, buf, 1);
+
+ /* write agc sdm configure */
+ buf[0] = 0xF1;
+ nxt200x_writebytes(state, 0x57, buf, 1);
+
+ /* write mod output format */
+ buf[0] = 0x20;
+ nxt200x_writebytes(state, 0x09, buf, 1);
+
+ /* write fec mpeg mode */
+ buf[0] = 0x7E;
+ buf[1] = 0x00;
+ nxt200x_writebytes(state, 0xE9, buf, 2);
+
+ /* write mux selection */
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0xCC, buf, 1);
+
+ return 0;
+}
+
+static int nxt2004_init(struct dvb_frontend* fe)
+{
+ struct nxt200x_state* state = fe->demodulator_priv;
+ const struct firmware *fw;
+ int ret;
+ u8 buf[3];
+
+ /* ??? */
+ buf[0]=0x00;
+ nxt200x_writebytes(state, 0x1E, buf, 1);
+
+ /* request the firmware, this will block until someone uploads it */
+ printk("nxt2004: Waiting for firmware upload (%s)...\n", NXT2004_DEFAULT_FIRMWARE);
+ ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE, &state->i2c->dev);
+ printk("nxt2004: Waiting for firmware upload(2)...\n");
+ if (ret) {
+ printk("nxt2004: No firmware uploaded (timeout or file not found?)\n");
+ return ret;
+ }
+
+ ret = nxt2004_load_firmware(fe, fw);
+ if (ret) {
+ printk("nxt2004: Writing firmware to device failed\n");
+ release_firmware(fw);
+ return ret;
+ }
+ printk("nxt2004: Firmware upload complete\n");
+
+ /* ensure transfer is complete */
+ buf[0] = 0x01;
+ nxt200x_writebytes(state, 0x19, buf, 1);
+
+ nxt2004_microcontroller_init(state);
+ nxt200x_microcontroller_stop(state);
+ nxt200x_microcontroller_stop(state);
+ nxt2004_microcontroller_init(state);
+ nxt200x_microcontroller_stop(state);
+
+ /* soft reset everything (agc,frontend,eq,fec)*/
+ buf[0] = 0xFF;
+ nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+ /* write agc sdm configure */
+ buf[0] = 0xD7;
+ nxt200x_writebytes(state, 0x57, buf, 1);
+
+ /* ???*/
+ buf[0] = 0x07;
+ buf[1] = 0xfe;
+ nxt200x_writebytes(state, 0x35, buf, 2);
+ buf[0] = 0x12;
+ nxt200x_writebytes(state, 0x34, buf, 1);
+ buf[0] = 0x80;
+ nxt200x_writebytes(state, 0x21, buf, 1);
+
+ /* ???*/
+ buf[0] = 0x21;
+ nxt200x_writebytes(state, 0x0A, buf, 1);
+
+ /* ???*/
+ buf[0] = 0x01;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+ /* write fec mpeg mode */
+ buf[0] = 0x7E;
+ buf[1] = 0x00;
+ nxt200x_writebytes(state, 0xE9, buf, 2);
+
+ /* write mux selection */
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0xCC, buf, 1);
+
+ /* ???*/
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+ /* soft reset? */
+ nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+ buf[0] = 0x10;
+ nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+ nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+ /* ???*/
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x01;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x70;
+ nxt200x_writereg_multibyte(state, 0x81, buf, 1);
+ buf[0] = 0x31; buf[1] = 0x5E; buf[2] = 0x66;
+ nxt200x_writereg_multibyte(state, 0x82, buf, 3);
+
+ nxt200x_readreg_multibyte(state, 0x88, buf, 1);
+ buf[0] = 0x11;
+ nxt200x_writereg_multibyte(state, 0x88, buf, 1);
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x40;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+ nxt200x_readbytes(state, 0x10, buf, 1);
+ buf[0] = 0x10;
+ nxt200x_writebytes(state, 0x10, buf, 1);
+ nxt200x_readbytes(state, 0x0A, buf, 1);
+ buf[0] = 0x21;
+ nxt200x_writebytes(state, 0x0A, buf, 1);
+
+ nxt2004_microcontroller_init(state);
+
+ buf[0] = 0x21;
+ nxt200x_writebytes(state, 0x0A, buf, 1);
+ buf[0] = 0x7E;
+ nxt200x_writebytes(state, 0xE9, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0xEA, buf, 1);
+
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+ /* soft reset? */
+ nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+ buf[0] = 0x10;
+ nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+ nxt200x_readreg_multibyte(state, 0x08, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x08, buf, 1);
+
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x04;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x81, buf, 1);
+ buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00;
+ nxt200x_writereg_multibyte(state, 0x82, buf, 3);
+
+ nxt200x_readreg_multibyte(state, 0x88, buf, 1);
+ buf[0] = 0x11;
+ nxt200x_writereg_multibyte(state, 0x88, buf, 1);
+
+ nxt200x_readreg_multibyte(state, 0x80, buf, 1);
+ buf[0] = 0x44;
+ nxt200x_writereg_multibyte(state, 0x80, buf, 1);
+
+ /* initialize tuner */
+ nxt200x_readbytes(state, 0x10, buf, 1);
+ buf[0] = 0x12;
+ nxt200x_writebytes(state, 0x10, buf, 1);
+ buf[0] = 0x04;
+ nxt200x_writebytes(state, 0x13, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0x16, buf, 1);
+ buf[0] = 0x04;
+ nxt200x_writebytes(state, 0x14, buf, 1);
+ buf[0] = 0x00;
+ nxt200x_writebytes(state, 0x14, buf, 1);
+ nxt200x_writebytes(state, 0x17, buf, 1);
+ nxt200x_writebytes(state, 0x14, buf, 1);
+ nxt200x_writebytes(state, 0x17, buf, 1);
+
+ return 0;
+}
+
+static int nxt200x_init(struct dvb_frontend* fe)
+{
+ struct nxt200x_state* state = fe->demodulator_priv;
+ int ret = 0;
+
+ if (!state->initialised) {
+ switch (state->demod_chip) {
+ case NXT2002:
+ ret = nxt2002_init(fe);
+ break;
+ case NXT2004:
+ ret = nxt2004_init(fe);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ state->initialised = 1;
+ }
+ return ret;
+}
+
+static int nxt200x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+ fesettings->min_delay_ms = 500;
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
+ return 0;
+}
+
+static void nxt200x_release(struct dvb_frontend* fe)
+{
+ struct nxt200x_state* state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops nxt200x_ops;
+
+struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
+ struct i2c_adapter* i2c)
+{
+ struct nxt200x_state* state = NULL;
+ u8 buf [] = {0,0,0,0,0};
+
+ /* allocate memory for the internal state */
+ state = (struct nxt200x_state*) kmalloc(sizeof(struct nxt200x_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+ memset(state,0,sizeof(*state));
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops));
+ state->initialised = 0;
+
+ /* read card id */
+ nxt200x_readbytes(state, 0x00, buf, 5);
+ dprintk("NXT info: %02X %02X %02X %02X %02X\n",
+ buf[0], buf[1], buf[2], buf[3], buf[4]);
+
+ /* set demod chip */
+ switch (buf[0]) {
+ case 0x04:
+ state->demod_chip = NXT2002;
+ printk("nxt200x: NXT2002 Detected\n");
+ break;
+ case 0x05:
+ state->demod_chip = NXT2004;
+ printk("nxt200x: NXT2004 Detected\n");
+ break;
+ default:
+ goto error;
+ }
+
+ /* make sure demod chip is supported */
+ switch (state->demod_chip) {
+ case NXT2002:
+ if (buf[0] != 0x04) goto error; /* device id */
+ if (buf[1] != 0x02) goto error; /* fab id */
+ if (buf[2] != 0x11) goto error; /* month */
+ if (buf[3] != 0x20) goto error; /* year msb */
+ if (buf[4] != 0x00) goto error; /* year lsb */
+ break;
+ case NXT2004:
+ if (buf[0] != 0x05) goto error; /* device id */
+ break;
+ default:
+ goto error;
+ }
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ kfree(state);
+ printk("Unknown/Unsupported NXT chip: %02X %02X %02X %02X %02X\n",
+ buf[0], buf[1], buf[2], buf[3], buf[4]);
+ return NULL;
+}
+
+static struct dvb_frontend_ops nxt200x_ops = {
+
+ .info = {
+ .name = "Nextwave NXT200X VSB/QAM frontend",
+ .type = FE_ATSC,
+ .frequency_min = 54000000,
+ .frequency_max = 860000000,
+ .frequency_stepsize = 166666, /* stepsize is just a guess */
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_8VSB | FE_CAN_QAM_64 | FE_CAN_QAM_256
+ },
+
+ .release = nxt200x_release,
+
+ .init = nxt200x_init,
+ .sleep = nxt200x_sleep,
+
+ .set_frontend = nxt200x_setup_frontend_parameters,
+ .get_tune_settings = nxt200x_get_tune_settings,
+
+ .read_status = nxt200x_read_status,
+ .read_ber = nxt200x_read_ber,
+ .read_signal_strength = nxt200x_read_signal_strength,
+ .read_snr = nxt200x_read_snr,
+ .read_ucblocks = nxt200x_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("NXT200X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
+MODULE_AUTHOR("Kirk Lapray, Jean-Francois Thibert, and Taylor Jacob");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(nxt200x_attach);
+
diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h
new file mode 100644
index 00000000000..1d9d70bc37e
--- /dev/null
+++ b/drivers/media/dvb/frontends/nxt200x.h
@@ -0,0 +1,61 @@
+/*
+ * Support for NXT2002 and NXT2004 - VSB/QAM
+ *
+ * Copyright (C) 2005 Kirk Lapray (kirk.lapray@gmail.com)
+ * based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net>
+ * and nxt2004 by Jean-Francois Thibert (jeanfrancois@sagetv.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+#ifndef NXT200X_H
+#define NXT200X_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+typedef enum nxt_chip_t {
+ NXTUNDEFINED,
+ NXT2002,
+ NXT2004
+}nxt_chip_type;
+
+struct nxt200x_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* tuner information */
+ u8 pll_address;
+ struct dvb_pll_desc *pll_desc;
+
+ /* used to set pll input */
+ int (*set_pll_input)(u8* buf, int input);
+
+ /* need to set device param for start_dma */
+ int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+};
+
+extern struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
+ struct i2c_adapter* i2c);
+
+#endif /* NXT200X_H */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index fc74c40d647..78bded861d0 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -468,6 +468,7 @@ static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength)
unsigned char snd_buf[2];
u8 rcvr_stat;
u16 snr_equ;
+ u32 signal_strength;
int usK;
snd_buf[0]=0x04;
@@ -503,7 +504,11 @@ static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength)
usK = (rcvr_stat & 0x10) ? 3 : 0;
/* The value reported back from the frontend will be FFFF=100% 0000=0% */
- *strength = (((8952 - i20Log10(snr_equ) - usK*100)/3+5)*65535)/1000;
+ signal_strength = (((8952 - i20Log10(snr_equ) - usK*100)/3+5)*65535)/1000;
+ if (signal_strength > 0xffff)
+ *strength = 0xffff;
+ else
+ *strength = signal_strength;
dprintk("read_signal_strength %i\n",*strength);
return 0;
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index 8a9db23dd1b..531f76246e5 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -339,6 +339,7 @@ static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength)
u8 rec_buf[2];
u8 snd_buf[4];
u8 snr_equ;
+ u32 signal_strength;
/* SNR after Equalizer */
snd_buf[0] = 0x04;
@@ -358,8 +359,11 @@ static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength)
snr_equ = rec_buf[0] & 0xff;
/* The value reported back from the frontend will be FFFF=100% 0000=0% */
- *strength = (((5334 - i20Log10(snr_equ))/3+5)*65535)/1000;
-
+ signal_strength = (((5334 - i20Log10(snr_equ))/3+5)*65535)/1000;
+ if (signal_strength > 0xffff)
+ *strength = 0xffff;
+ else
+ *strength = signal_strength;
dprintk("read_signal_strength %i\n",*strength);
return 0;
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 889d9257215..29c48665e13 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -64,8 +64,12 @@ struct stv0299_state {
u32 tuner_frequency;
u32 symbol_rate;
fe_code_rate_t fec_inner;
+ int errmode;
};
+#define STATUS_BER 0
+#define STATUS_UCBLOCKS 1
+
static int debug;
static int debug_legacy_dish_switch;
#define dprintk(args...) \
@@ -383,36 +387,6 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag
};
}
-static inline s32 stv0299_calc_usec_delay (struct timeval lasttime, struct timeval curtime)
-{
- return ((curtime.tv_usec < lasttime.tv_usec) ?
- 1000000 - lasttime.tv_usec + curtime.tv_usec :
- curtime.tv_usec - lasttime.tv_usec);
-}
-
-static void stv0299_sleep_until (struct timeval *waketime, u32 add_usec)
-{
- struct timeval lasttime;
- s32 delta, newdelta;
-
- waketime->tv_usec += add_usec;
- if (waketime->tv_usec >= 1000000) {
- waketime->tv_usec -= 1000000;
- waketime->tv_sec++;
- }
-
- do_gettimeofday (&lasttime);
- delta = stv0299_calc_usec_delay (lasttime, *waketime);
- if (delta > 2500) {
- msleep ((delta - 1500) / 1000);
- do_gettimeofday (&lasttime);
- newdelta = stv0299_calc_usec_delay (lasttime, *waketime);
- delta = (newdelta > delta) ? 0 : newdelta;
- }
- if (delta > 0)
- udelay (delta);
-}
-
static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
{
struct stv0299_state* state = fe->demodulator_priv;
@@ -440,7 +414,7 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
memcpy (&tv[0], &nexttime, sizeof (struct timeval));
stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */
- stv0299_sleep_until (&nexttime, 32000);
+ dvb_frontend_sleep_until(&nexttime, 32000);
for (i=0; i<9; i++) {
if (debug_legacy_dish_switch)
@@ -454,13 +428,13 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd)
cmd = cmd >> 1;
if (i != 8)
- stv0299_sleep_until (&nexttime, 8000);
+ dvb_frontend_sleep_until(&nexttime, 8000);
}
if (debug_legacy_dish_switch) {
printk ("%s(%d): switch delay (should be 32k followed by all 8k\n",
__FUNCTION__, fe->dvb->num);
- for (i=1; i < 10; i++)
- printk ("%d: %d\n", i, stv0299_calc_usec_delay (tv[i-1] , tv[i]));
+ for (i = 1; i < 10; i++)
+ printk ("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
}
return 0;
@@ -517,8 +491,7 @@ static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber)
{
struct stv0299_state* state = fe->demodulator_priv;
- stv0299_writeregI(state, 0x34, (stv0299_readreg(state, 0x34) & 0xcf) | 0x10);
- msleep(100);
+ if (state->errmode != STATUS_BER) return 0;
*ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
return 0;
@@ -557,9 +530,8 @@ static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
{
struct stv0299_state* state = fe->demodulator_priv;
- stv0299_writeregI(state, 0x34, (stv0299_readreg(state, 0x34) & 0xcf) | 0x30);
- msleep(100);
- *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
+ if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0;
+ else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e);
return 0;
}
@@ -581,49 +553,14 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
if (state->config->invert) invval = (~invval) & 1;
stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
- if (state->config->enhanced_tuning) {
- /* check if we should do a finetune */
- int frequency_delta = p->frequency - state->tuner_frequency;
- int minmax = p->u.qpsk.symbol_rate / 2000;
- if (minmax < 5000) minmax = 5000;
-
- if ((frequency_delta > -minmax) && (frequency_delta < minmax) && (frequency_delta != 0) &&
- (state->fec_inner == p->u.qpsk.fec_inner) &&
- (state->symbol_rate == p->u.qpsk.symbol_rate)) {
- int Drot_freq = (frequency_delta << 16) / (state->config->mclk / 1000);
-
- // zap the derotator registers first
- stv0299_writeregI(state, 0x22, 0x00);
- stv0299_writeregI(state, 0x23, 0x00);
-
- // now set them as we want
- stv0299_writeregI(state, 0x22, Drot_freq >> 8);
- stv0299_writeregI(state, 0x23, Drot_freq);
- } else {
- /* A "normal" tune is requested */
- stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
- state->config->pll_set(fe, state->i2c, p);
- stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */
-
- stv0299_writeregI(state, 0x32, 0x80);
- stv0299_writeregI(state, 0x22, 0x00);
- stv0299_writeregI(state, 0x23, 0x00);
- stv0299_writeregI(state, 0x32, 0x19);
- stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
- stv0299_set_FEC (state, p->u.qpsk.fec_inner);
- }
- } else {
- stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
- state->config->pll_set(fe, state->i2c, p);
- stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */
+ stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
+ state->config->pll_set(fe, state->i2c, p);
+ stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */
- stv0299_set_FEC (state, p->u.qpsk.fec_inner);
- stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
- stv0299_writeregI(state, 0x22, 0x00);
- stv0299_writeregI(state, 0x23, 0x00);
- stv0299_readreg (state, 0x23);
- stv0299_writeregI(state, 0x12, 0xb9);
- }
+ stv0299_set_FEC (state, p->u.qpsk.fec_inner);
+ stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
+ stv0299_writeregI(state, 0x22, 0x00);
+ stv0299_writeregI(state, 0x23, 0x00);
state->tuner_frequency = p->frequency;
state->fec_inner = p->u.qpsk.fec_inner;
@@ -708,6 +645,7 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
state->tuner_frequency = 0;
state->symbol_rate = 0;
state->fec_inner = 0;
+ state->errmode = STATUS_BER;
/* check if the demod is there */
stv0299_writeregI(state, 0x02, 0x34); /* standby off */
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h
index d0c4484861e..9af3d71c89d 100644
--- a/drivers/media/dvb/frontends/stv0299.h
+++ b/drivers/media/dvb/frontends/stv0299.h
@@ -73,9 +73,6 @@ struct stv0299_config
/* does the inversion require inversion? */
u8 invert:1;
- /* Should the enhanced tuning code be used? */
- u8 enhanced_tuning:1;
-
/* Skip reinitialisation? */
u8 skip_reinit:1;
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index 3529c618f82..7968743826f 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -420,7 +420,7 @@ static void tda10046_init_plls(struct dvb_frontend* fe)
struct tda1004x_state* state = fe->demodulator_priv;
tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
- tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10
+ tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x0a); // PLL M = 10
if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__);
tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
@@ -597,7 +597,10 @@ static int tda10046_init(struct dvb_frontend* fe)
// Init the tuner PLL
if (state->config->pll_init) {
tda1004x_enable_tuner_i2c(state);
- state->config->pll_init(fe);
+ if (state->config->pll_init(fe)) {
+ printk(KERN_ERR "tda1004x: pll init failed\n");
+ return -EIO;
+ }
tda1004x_disable_tuner_i2c(state);
}
@@ -667,7 +670,10 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
// set frequency
tda1004x_enable_tuner_i2c(state);
- state->config->pll_set(fe, fe_params);
+ if (state->config->pll_set(fe, fe_params)) {
+ printk(KERN_ERR "tda1004x: pll set failed\n");
+ return -EIO;
+ }
tda1004x_disable_tuner_i2c(state);
// Hardcoded to use auto as much as possible on the TDA10045 as it
@@ -832,6 +838,8 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
case TDA1004X_DEMOD_TDA10046:
tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40);
+ msleep(1);
+ tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 1);
break;
}
@@ -1129,7 +1137,12 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
if (state->config->pll_sleep != NULL) {
tda1004x_enable_tuner_i2c(state);
state->config->pll_sleep(fe);
- tda1004x_disable_tuner_i2c(state);
+ if (state->config->if_freq != TDA10046_FREQ_052) {
+ /* special hack for Philips EUROPA Based boards:
+ * keep the I2c bridge open for tuner access in analog mode
+ */
+ tda1004x_disable_tuner_i2c(state);
+ }
}
tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
break;
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
index 85b437bbddc..bbebd1c4cac 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -286,15 +286,10 @@ static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets)
* although one packet has been transfered.
*/
if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) {
- unsigned int i = 0, valid;
+ unsigned int i = 0;
while (pluto->dma_buf[i] == 0x47)
i += 188;
- valid = i / 188;
- if (nbpackets != valid) {
- dev_err(&pluto->pdev->dev, "nbpackets=%u valid=%u\n",
- nbpackets, valid);
- nbpackets = valid;
- }
+ nbpackets = i / 188;
}
dvb_dmx_swfilter_packets(&pluto->demux, pluto->dma_buf, nbpackets);
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 22b203f8ff2..87ea52757a2 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -1566,7 +1566,7 @@ static u8 alps_bsru6_inittab[] = {
0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
0x10, 0x3f, // AGC2 0x3d
0x11, 0x84,
- 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x12, 0xb9,
0x15, 0xc9, // lock detector threshold
0x16, 0x00,
0x17, 0x00,
@@ -1644,7 +1644,6 @@ static struct stv0299_config alps_bsru6_config = {
.inittab = alps_bsru6_inittab,
.mclk = 88000000UL,
.invert = 1,
- .enhanced_tuning = 0,
.skip_reinit = 0,
.lock_output = STV0229_LOCKOUTPUT_1,
.volt13_op0_op1 = STV0299_VOLT13_OP1,
@@ -1669,7 +1668,7 @@ static u8 alps_bsbe1_inittab[] = {
0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
0x10, 0x3f, // AGC2 0x3d
0x11, 0x84,
- 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x12, 0xb9,
0x15, 0xc9, // lock detector threshold
0x16, 0x00,
0x17, 0x00,
@@ -1721,7 +1720,6 @@ static struct stv0299_config alps_bsbe1_config = {
.inittab = alps_bsbe1_inittab,
.mclk = 88000000UL,
.invert = 1,
- .enhanced_tuning = 0,
.skip_reinit = 0,
.min_delay_ms = 100,
.set_symbol_rate = alps_bsru6_set_symbol_rate,
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 7692cd23f83..aa75dc03a0b 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -499,7 +499,7 @@ static u8 typhoon_cinergy1200s_inittab[] = {
0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
0x10, 0x3f, // AGC2 0x3d
0x11, 0x84,
- 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x12, 0xb9,
0x15, 0xc9, // lock detector threshold
0x16, 0x00,
0x17, 0x00,
@@ -531,7 +531,6 @@ static struct stv0299_config typhoon_config = {
.inittab = typhoon_cinergy1200s_inittab,
.mclk = 88000000UL,
.invert = 0,
- .enhanced_tuning = 0,
.skip_reinit = 0,
.lock_output = STV0229_LOCKOUTPUT_1,
.volt13_op0_op1 = STV0299_VOLT13_OP0,
@@ -546,7 +545,6 @@ static struct stv0299_config cinergy_1200s_config = {
.inittab = typhoon_cinergy1200s_inittab,
.mclk = 88000000UL,
.invert = 0,
- .enhanced_tuning = 0,
.skip_reinit = 0,
.lock_output = STV0229_LOCKOUTPUT_0,
.volt13_op0_op1 = STV0299_VOLT13_OP0,
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 51c30ba6814..75fb92d6099 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -490,7 +490,7 @@ static u8 alps_bsru6_inittab[] = {
0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
0x10, 0x3f, // AGC2 0x3d
0x11, 0x84,
- 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x12, 0xb9,
0x15, 0xc9, // lock detector threshold
0x16, 0x00,
0x17, 0x00,
@@ -580,7 +580,6 @@ static struct stv0299_config alps_bsru6_config = {
.inittab = alps_bsru6_inittab,
.mclk = 88000000UL,
.invert = 1,
- .enhanced_tuning = 0,
.skip_reinit = 0,
.lock_output = STV0229_LOCKOUTPUT_1,
.volt13_op0_op1 = STV0299_VOLT13_OP1,
@@ -710,7 +709,6 @@ static struct stv0299_config philips_su1278_tt_config = {
.inittab = philips_su1278_tt_inittab,
.mclk = 64000000UL,
.invert = 0,
- .enhanced_tuning = 1,
.skip_reinit = 1,
.lock_output = STV0229_LOCKOUTPUT_1,
.volt13_op0_op1 = STV0299_VOLT13_OP1,
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index b1f21ef0e3b..755df81cbc4 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -305,7 +305,7 @@ static u8 alps_bsru6_inittab[] = {
0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
0x10, 0x3f, // AGC2 0x3d
0x11, 0x84,
- 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x12, 0xb9,
0x15, 0xc9, // lock detector threshold
0x16, 0x00,
0x17, 0x00,
@@ -379,7 +379,6 @@ static struct stv0299_config alps_bsru6_config = {
.inittab = alps_bsru6_inittab,
.mclk = 88000000UL,
.invert = 1,
- .enhanced_tuning = 0,
.skip_reinit = 0,
.lock_output = STV0229_LOCKOUTPUT_1,
.volt13_op0_op1 = STV0299_VOLT13_OP1,
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 43d6c826864..4fd8bbc4703 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -226,12 +226,14 @@ static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, int arg)
return 0;
}
-static void lnbp21_init(struct budget* budget)
+static int lnbp21_init(struct budget* budget)
{
u8 buf = 0x00;
struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = &buf, .len = sizeof(buf) };
- i2c_transfer (&budget->i2c_adap, &msg, 1);
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+ return 0;
}
static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
@@ -273,7 +275,7 @@ static u8 alps_bsru6_inittab[] = {
0x01, 0x15,
0x02, 0x00,
0x03, 0x00,
- 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
0x06, 0x40, /* DAC not used, set to high impendance mode */
0x07, 0x00, /* DAC LSB */
@@ -284,7 +286,7 @@ static u8 alps_bsru6_inittab[] = {
0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
0x10, 0x3f, // AGC2 0x3d
0x11, 0x84,
- 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x12, 0xb9,
0x15, 0xc9, // lock detector threshold
0x16, 0x00,
0x17, 0x00,
@@ -358,7 +360,6 @@ static struct stv0299_config alps_bsru6_config = {
.inittab = alps_bsru6_inittab,
.mclk = 88000000UL,
.invert = 1,
- .enhanced_tuning = 0,
.skip_reinit = 0,
.lock_output = STV0229_LOCKOUTPUT_1,
.volt13_op0_op1 = STV0299_VOLT13_OP1,
@@ -367,6 +368,79 @@ static struct stv0299_config alps_bsru6_config = {
.pll_set = alps_bsru6_pll_set,
};
+static u8 alps_bsbe1_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x30,
+ 0x03, 0x00,
+ 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
+ 0x06, 0x40, /* DAC not used, set to high impendance mode */
+ 0x07, 0x00, /* DAC LSB */
+ 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
+ 0x09, 0x00, /* FIFO */
+ 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+ 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
+ 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
+ 0x10, 0x3f, // AGC2 0x3d
+ 0x11, 0x84,
+ 0x12, 0xb9,
+ 0x15, 0xc9, // lock detector threshold
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
+ 0x29, 0x1e, // 1/2 threshold
+ 0x2a, 0x14, // 2/3 threshold
+ 0x2b, 0x0f, // 3/4 threshold
+ 0x2c, 0x09, // 5/6 threshold
+ 0x2d, 0x05, // 7/8 threshold
+ 0x2e, 0x01,
+ 0x31, 0x1f, // test all FECs
+ 0x32, 0x19, // viterbi and synchro search
+ 0x33, 0xfc, // rs control
+ 0x34, 0x93, // error control
+ 0x0f, 0x92, // 0x80 = inverse AGC
+ 0xff, 0xff
+};
+
+static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+{
+ int ret;
+ u8 data[4];
+ u32 div;
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ if ((params->frequency < 950000) || (params->frequency > 2150000))
+ return -EINVAL;
+
+ div = (params->frequency + (125 - 1)) / 125; // round correctly
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+ data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
+
+ ret = i2c_transfer(i2c, &msg, 1);
+ return (ret != 1) ? -EIO : 0;
+}
+
+static struct stv0299_config alps_bsbe1_config = {
+ .demod_address = 0x68,
+ .inittab = alps_bsbe1_inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .skip_reinit = 0,
+ .min_delay_ms = 100,
+ .set_symbol_rate = alps_bsru6_set_symbol_rate,
+ .pll_set = alps_bsbe1_pll_set,
+};
+
static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
@@ -500,6 +574,19 @@ static u8 read_pwm(struct budget* budget)
static void frontend_init(struct budget *budget)
{
switch(budget->dev->pci->subsystem_device) {
+ case 0x1017:
+ // try the ALPS BSBE1 now
+ budget->dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
+ budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+ if (lnbp21_init(budget)) {
+ printk("%s: No LNBP21 found!\n", __FUNCTION__);
+ goto error_out;
+ }
+ }
+
+ break;
case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
case 0x1013:
// try the ALPS BSRV2 first of all
@@ -554,7 +641,10 @@ static void frontend_init(struct budget *budget)
if (budget->dvb_frontend) {
budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
- lnbp21_init(budget);
+ if (lnbp21_init(budget)) {
+ printk("%s: No LNBP21 found!\n", __FUNCTION__);
+ goto error_out;
+ }
break;
}
}
@@ -566,13 +656,17 @@ static void frontend_init(struct budget *budget)
budget->dev->pci->subsystem_vendor,
budget->dev->pci->subsystem_device);
} else {
- if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
- printk("budget: Frontend registration failed!\n");
- if (budget->dvb_frontend->ops->release)
- budget->dvb_frontend->ops->release(budget->dvb_frontend);
- budget->dvb_frontend = NULL;
- }
+ if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend))
+ goto error_out;
}
+ return;
+
+error_out:
+ printk("budget: Frontend registration failed!\n");
+ if (budget->dvb_frontend->ops->release)
+ budget->dvb_frontend->ops->release(budget->dvb_frontend);
+ budget->dvb_frontend = NULL;
+ return;
}
static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
@@ -618,6 +712,7 @@ static int budget_detach (struct saa7146_dev* dev)
static struct saa7146_extension budget_extension;
+MAKE_BUDGET_INFO(ttbs2, "TT-Budget/WinTV-NOVA-S PCI (rev AL/alps bsbe1 lnbp21 frontend)", BUDGET_TT);
MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
@@ -630,6 +725,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004),
MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005),
MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
+ MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016),
MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index d200ab0ad9e..fd53d601050 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -1198,7 +1198,7 @@ static u8 alps_bsbe1_inittab[] = {
0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
0x10, 0x3f, // AGC2 0x3d
0x11, 0x84,
- 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x12, 0xb9,
0x15, 0xc9, // lock detector threshold
0x16, 0x00,
0x17, 0x00,
@@ -1240,7 +1240,7 @@ static u8 alps_bsru6_inittab[] = {
0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
0x10, 0x3f, // AGC2 0x3d
0x11, 0x84,
- 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x12, 0xb9,
0x15, 0xc9, // lock detector threshold
0x16, 0x00,
0x17, 0x00,
@@ -1335,7 +1335,6 @@ static struct stv0299_config alps_stv0299_config = {
.inittab = alps_bsru6_inittab,
.mclk = 88000000UL,
.invert = 1,
- .enhanced_tuning = 0,
.skip_reinit = 0,
.lock_output = STV0229_LOCKOUTPUT_1,
.volt13_op0_op1 = STV0299_VOLT13_OP1,
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index bbb989df4cf..199b0118885 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -25,6 +25,16 @@ config VIDEO_BT848
To compile this driver as a module, choose M here: the
module will be called bttv.
+config VIDEO_BT848_DVB
+ tristate "DVB/ATSC Support for bt878 based TV cards"
+ depends on VIDEO_BT848 && DVB_CORE
+ select DVB_BT8XX
+ ---help---
+ This adds support for DVB/ATSC cards based on the BT878 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called dvb-bt8xx.
+
config VIDEO_SAA6588
tristate "SAA6588 Radio Chip RDS decoder support on BT848 cards"
depends on VIDEO_DEV && I2C && VIDEO_BT848
@@ -243,29 +253,7 @@ config VIDEO_MEYE
To compile this driver as a module, choose M here: the
module will be called meye.
-config VIDEO_SAA7134
- tristate "Philips SAA7134 support"
- depends on VIDEO_DEV && PCI && I2C && SOUND
- select VIDEO_BUF
- select VIDEO_IR
- select VIDEO_TUNER
- select CRC32
- ---help---
- This is a video4linux driver for Philips SAA7130/7134 based
- TV cards.
-
- To compile this driver as a module, choose M here: the
- module will be called saa7134.
-
-config VIDEO_SAA7134_DVB
- tristate "DVB Support for saa7134 based TV cards"
- depends on VIDEO_SAA7134 && DVB_CORE
- select VIDEO_BUF_DVB
- select DVB_MT352
- select DVB_TDA1004X
- ---help---
- This adds support for DVB cards based on the
- Philips saa7134 chip.
+source "drivers/media/video/saa7134/Kconfig"
config VIDEO_MXB
tristate "Siemens-Nixdorf 'Multimedia eXtension Board'"
@@ -316,34 +304,9 @@ config VIDEO_HEXIUM_GEMINI
To compile this driver as a module, choose M here: the
module will be called hexium_gemini.
-config VIDEO_CX88
- tristate "Conexant 2388x (bt878 successor) support"
- depends on VIDEO_DEV && PCI && I2C && EXPERIMENTAL
- select I2C_ALGOBIT
- select FW_LOADER
- select VIDEO_BTCX
- select VIDEO_BUF
- select VIDEO_TUNER
- select VIDEO_TVEEPROM
- select VIDEO_IR
- ---help---
- This is a video4linux driver for Conexant 2388x based
- TV cards.
+source "drivers/media/video/cx88/Kconfig"
- To compile this driver as a module, choose M here: the
- module will be called cx8800
-
-config VIDEO_CX88_DVB
- tristate "DVB Support for cx2388x based TV cards"
- depends on VIDEO_CX88 && DVB_CORE
- select VIDEO_BUF_DVB
- select DVB_MT352
- select DVB_OR51132
- select DVB_CX22702
- select DVB_LGDT330X
- ---help---
- This adds support for DVB/ATSC cards based on the
- Connexant 2388x chip.
+source "drivers/media/video/em28xx/Kconfig"
config VIDEO_OVCAMCHIP
tristate "OmniVision Camera Chip support"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 046b82de928..3ac46599240 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -5,7 +5,6 @@
bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \
bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o
zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o
-rds-objs := saa6588.o
zr36067-objs := zoran_procfs.o zoran_device.o \
zoran_driver.o zoran_card.o
tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o
@@ -16,7 +15,7 @@ obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \
obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
-obj-$(CONFIG_VIDEO_SAA6588) += rds.o
+obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
@@ -39,6 +38,8 @@ obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
obj-$(CONFIG_VIDEO_MEYE) += meye.o
obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
obj-$(CONFIG_VIDEO_CX88) += cx88/
+obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
+obj-$(CONFIG_VIDEO_EM28XX) += saa711x.o tvp5150.o
obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
obj-$(CONFIG_VIDEO_MXB) += saa7111.o tuner.o tda9840.o tea6415c.o tea6420.o mxb.o
obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index 0823ddaf700..881cdcb1875 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -22,7 +22,6 @@
#include <linux/init.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
diff --git a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c
index 76c1b63ebdf..e4063950ae5 100644
--- a/drivers/media/video/bt832.c
+++ b/drivers/media/video/bt832.c
@@ -32,7 +32,6 @@
#include <linux/slab.h>
#include <media/audiochip.h>
-#include <media/id.h>
#include "bttv.h"
#include "bt832.h"
@@ -54,36 +53,36 @@ static struct i2c_driver driver;
static struct i2c_client client_template;
struct bt832 {
- struct i2c_client client;
+ struct i2c_client client;
};
int bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf)
{
int i,rc;
buf[0]=0x80; // start at register 0 with auto-increment
- if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
- printk("bt832: i2c i/o error: rc == %d (should be 1)\n",rc);
+ if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
+ printk("bt832: i2c i/o error: rc == %d (should be 1)\n",rc);
- for(i=0;i<65;i++)
- buf[i]=0;
- if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
- printk("bt832: i2c i/o error: rc == %d (should be 65)\n",rc);
+ for(i=0;i<65;i++)
+ buf[i]=0;
+ if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
+ printk("bt832: i2c i/o error: rc == %d (should be 65)\n",rc);
- // Note: On READ the first byte is the current index
- // (e.g. 0x80, what we just wrote)
+ // Note: On READ the first byte is the current index
+ // (e.g. 0x80, what we just wrote)
- if(1) {
- int i;
- printk("BT832 hexdump:\n");
- for(i=1;i<65;i++) {
+ if(1) {
+ int i;
+ printk("BT832 hexdump:\n");
+ for(i=1;i<65;i++) {
if(i!=1) {
if(((i-1)%8)==0) printk(" ");
- if(((i-1)%16)==0) printk("\n");
+ if(((i-1)%16)==0) printk("\n");
}
- printk(" %02x",buf[i]);
- }
- printk("\n");
- }
+ printk(" %02x",buf[i]);
+ }
+ printk("\n");
+ }
return 0;
}
@@ -102,13 +101,13 @@ int bt832_init(struct i2c_client *i2c_client_s)
return 0;
}
- printk("Write 0 tp VPSTATUS\n");
- buf[0]=BT832_VP_STATUS; // Reg.52
- buf[1]= 0x00;
- if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+ printk("Write 0 tp VPSTATUS\n");
+ buf[0]=BT832_VP_STATUS; // Reg.52
+ buf[1]= 0x00;
+ if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+ printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
- bt832_hexdump(i2c_client_s,buf);
+ bt832_hexdump(i2c_client_s,buf);
// Leave low power mode:
@@ -116,17 +115,17 @@ int bt832_init(struct i2c_client *i2c_client_s)
buf[0]=BT832_CAM_SETUP0; //0x39 57
buf[1]=0x08;
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- printk("bt832: i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
+ printk("bt832: i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
- bt832_hexdump(i2c_client_s,buf);
+ bt832_hexdump(i2c_client_s,buf);
printk("Write 0 tp VPSTATUS\n");
- buf[0]=BT832_VP_STATUS; // Reg.52
- buf[1]= 0x00;
- if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+ buf[0]=BT832_VP_STATUS; // Reg.52
+ buf[1]= 0x00;
+ if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+ printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
- bt832_hexdump(i2c_client_s,buf);
+ bt832_hexdump(i2c_client_s,buf);
// Enable Output
@@ -134,22 +133,22 @@ int bt832_init(struct i2c_client *i2c_client_s)
buf[0]=BT832_VP_CONTROL1; // Reg.40
buf[1]= 0x27 & (~0x01); // Default | !skip
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc);
+ printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc);
- bt832_hexdump(i2c_client_s,buf);
+ bt832_hexdump(i2c_client_s,buf);
// for testing (even works when no camera attached)
printk("bt832: *** Generate NTSC M Bars *****\n");
buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
- if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
+ if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+ printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
printk("Bt832: Camera Present: %s\n",
(buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");
- bt832_hexdump(i2c_client_s,buf);
+ bt832_hexdump(i2c_client_s,buf);
kfree(buf);
return 1;
}
@@ -162,17 +161,17 @@ static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
printk("bt832_attach\n");
- client_template.adapter = adap;
- client_template.addr = addr;
+ client_template.adapter = adap;
+ client_template.addr = addr;
- printk("bt832: chip found @ 0x%x\n", addr<<1);
+ printk("bt832: chip found @ 0x%x\n", addr<<1);
- if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
- return -ENOMEM;
+ if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
+ return -ENOMEM;
memset(t,0,sizeof(*t));
t->client = client_template;
- i2c_set_clientdata(&t->client, t);
- i2c_attach_client(&t->client);
+ i2c_set_clientdata(&t->client, t);
+ i2c_attach_client(&t->client);
if(! bt832_init(&t->client)) {
bt832_detach(&t->client);
@@ -211,7 +210,7 @@ bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
printk("bt832: command %x\n",cmd);
- switch (cmd) {
+ switch (cmd) {
case BT832_HEXDUMP: {
unsigned char *buf;
buf=kmalloc(65,GFP_KERNEL);
diff --git a/drivers/media/video/bt832.h b/drivers/media/video/bt832.h
index 9b6a8d2c96b..1ce8fa71f7d 100644
--- a/drivers/media/video/bt832.h
+++ b/drivers/media/video/bt832.h
@@ -233,8 +233,8 @@ SetInterlaceMode( spec.interlace );
/* from web:
Video Sampling
Digital video is a sampled form of analog video. The most common sampling schemes in use today are:
- Pixel Clock Horiz Horiz Vert
- Rate Total Active
+ Pixel Clock Horiz Horiz Vert
+ Rate Total Active
NTSC square pixel 12.27 MHz 780 640 525
NTSC CCIR-601 13.5 MHz 858 720 525
NTSC 4FSc 14.32 MHz 910 768 525
diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c
index 0881a17d522..3413bace443 100644
--- a/drivers/media/video/bttv-cards.c
+++ b/drivers/media/video/bttv-cards.c
@@ -6,7 +6,7 @@
like the big tvcards array for the most part
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
- & Marcus Metzler (mocm@thp.uni-koeln.de)
+ & Marcus Metzler (mocm@thp.uni-koeln.de)
(c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
This program is free software; you can redistribute it and/or modify
@@ -145,162 +145,163 @@ static struct CARD {
int cardnr;
char *name;
} cards[] __devinitdata = {
- { 0x13eb0070, BTTV_HAUPPAUGE878, "Hauppauge WinTV" },
- { 0x39000070, BTTV_HAUPPAUGE878, "Hauppauge WinTV-D" },
- { 0x45000070, BTTV_HAUPPAUGEPVR, "Hauppauge WinTV/PVR" },
- { 0xff000070, BTTV_OSPREY1x0, "Osprey-100" },
- { 0xff010070, BTTV_OSPREY2x0_SVID,"Osprey-200" },
- { 0xff020070, BTTV_OSPREY500, "Osprey-500" },
- { 0xff030070, BTTV_OSPREY2000, "Osprey-2000" },
- { 0xff040070, BTTV_OSPREY540, "Osprey-540" },
-
- { 0x00011002, BTTV_ATI_TVWONDER, "ATI TV Wonder" },
- { 0x00031002, BTTV_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
-
- { 0x6606107d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" },
- { 0x6607107d, BTTV_WINFASTVC100, "Leadtek WinFast VC 100" },
- { 0x6609107d, BTTV_WINFAST2000, "Leadtek TV 2000 XP" },
- { 0x263610b4, BTTV_STB2, "STB TV PCI FM, Gateway P/N 6000704" },
- { 0x264510b4, BTTV_STB2, "STB TV PCI FM, Gateway P/N 6000704" },
- { 0x402010fc, BTTV_GVBCTV3PCI, "I-O Data Co. GV-BCTV3/PCI" },
- { 0x405010fc, BTTV_GVBCTV4PCI, "I-O Data Co. GV-BCTV4/PCI" },
- { 0x407010fc, BTTV_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" },
- { 0xd01810fc, BTTV_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" },
-
- { 0x001211bd, BTTV_PINNACLE, "Pinnacle PCTV" },
+ { 0x13eb0070, BTTV_BOARD_HAUPPAUGE878, "Hauppauge WinTV" },
+ { 0x39000070, BTTV_BOARD_HAUPPAUGE878, "Hauppauge WinTV-D" },
+ { 0x45000070, BTTV_BOARD_HAUPPAUGEPVR, "Hauppauge WinTV/PVR" },
+ { 0xff000070, BTTV_BOARD_OSPREY1x0, "Osprey-100" },
+ { 0xff010070, BTTV_BOARD_OSPREY2x0_SVID,"Osprey-200" },
+ { 0xff020070, BTTV_BOARD_OSPREY500, "Osprey-500" },
+ { 0xff030070, BTTV_BOARD_OSPREY2000, "Osprey-2000" },
+ { 0xff040070, BTTV_BOARD_OSPREY540, "Osprey-540" },
+ { 0xff070070, BTTV_BOARD_OSPREY440, "Osprey-440" },
+
+ { 0x00011002, BTTV_BOARD_ATI_TVWONDER, "ATI TV Wonder" },
+ { 0x00031002, BTTV_BOARD_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
+
+ { 0x6606107d, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" },
+ { 0x6607107d, BTTV_BOARD_WINFASTVC100, "Leadtek WinFast VC 100" },
+ { 0x6609107d, BTTV_BOARD_WINFAST2000, "Leadtek TV 2000 XP" },
+ { 0x263610b4, BTTV_BOARD_STB2, "STB TV PCI FM, Gateway P/N 6000704" },
+ { 0x264510b4, BTTV_BOARD_STB2, "STB TV PCI FM, Gateway P/N 6000704" },
+ { 0x402010fc, BTTV_BOARD_GVBCTV3PCI, "I-O Data Co. GV-BCTV3/PCI" },
+ { 0x405010fc, BTTV_BOARD_GVBCTV4PCI, "I-O Data Co. GV-BCTV4/PCI" },
+ { 0x407010fc, BTTV_BOARD_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" },
+ { 0xd01810fc, BTTV_BOARD_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" },
+
+ { 0x001211bd, BTTV_BOARD_PINNACLE, "Pinnacle PCTV" },
/* some cards ship with byteswapped IDs ... */
- { 0x1200bd11, BTTV_PINNACLE, "Pinnacle PCTV [bswap]" },
- { 0xff00bd11, BTTV_PINNACLE, "Pinnacle PCTV [bswap]" },
+ { 0x1200bd11, BTTV_BOARD_PINNACLE, "Pinnacle PCTV [bswap]" },
+ { 0xff00bd11, BTTV_BOARD_PINNACLE, "Pinnacle PCTV [bswap]" },
/* this seems to happen as well ... */
- { 0xff1211bd, BTTV_PINNACLE, "Pinnacle PCTV" },
-
- { 0x3000121a, BTTV_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" },
- { 0x263710b4, BTTV_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" },
- { 0x3060121a, BTTV_STB2, "3Dfx VoodooTV 100/ STB OEM" },
-
- { 0x3000144f, BTTV_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
- { 0xa005144f, BTTV_MAGICTVIEW063, "CPH06X TView99-Card" },
- { 0x3002144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" },
- { 0x3005144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" },
- { 0x5000144f, BTTV_MAGICTVIEW061, "Askey CPH050" },
- { 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" },
- { 0x300214ff, BTTV_PHOEBE_TVMAS, "Phoebe TV Master (CPH060)" },
-
- { 0x00011461, BTTV_AVPHONE98, "AVerMedia TVPhone98" },
- { 0x00021461, BTTV_AVERMEDIA98, "AVermedia TVCapture 98" },
- { 0x00031461, BTTV_AVPHONE98, "AVerMedia TVPhone98" },
- { 0x00041461, BTTV_AVERMEDIA98, "AVerMedia TVCapture 98" },
- { 0x03001461, BTTV_AVERMEDIA98, "VDOMATE TV TUNER CARD" },
-
- { 0x1117153b, BTTV_TERRATVALUE, "Terratec TValue (Philips PAL B/G)" },
- { 0x1118153b, BTTV_TERRATVALUE, "Terratec TValue (Temic PAL B/G)" },
- { 0x1119153b, BTTV_TERRATVALUE, "Terratec TValue (Philips PAL I)" },
- { 0x111a153b, BTTV_TERRATVALUE, "Terratec TValue (Temic PAL I)" },
-
- { 0x1123153b, BTTV_TERRATVRADIO, "Terratec TV Radio+" },
- { 0x1127153b, BTTV_TERRATV, "Terratec TV+ (V1.05)" },
+ { 0xff1211bd, BTTV_BOARD_PINNACLE, "Pinnacle PCTV" },
+
+ { 0x3000121a, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" },
+ { 0x263710b4, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" },
+ { 0x3060121a, BTTV_BOARD_STB2, "3Dfx VoodooTV 100/ STB OEM" },
+
+ { 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
+ { 0xa005144f, BTTV_BOARD_MAGICTVIEW063, "CPH06X TView99-Card" },
+ { 0x3002144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" },
+ { 0x3005144f, BTTV_BOARD_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH061/06L (T1/LC)" },
+ { 0x5000144f, BTTV_BOARD_MAGICTVIEW061, "Askey CPH050" },
+ { 0x300014ff, BTTV_BOARD_MAGICTVIEW061, "TView 99 (CPH061)" },
+ { 0x300214ff, BTTV_BOARD_PHOEBE_TVMAS, "Phoebe TV Master (CPH060)" },
+
+ { 0x00011461, BTTV_BOARD_AVPHONE98, "AVerMedia TVPhone98" },
+ { 0x00021461, BTTV_BOARD_AVERMEDIA98, "AVermedia TVCapture 98" },
+ { 0x00031461, BTTV_BOARD_AVPHONE98, "AVerMedia TVPhone98" },
+ { 0x00041461, BTTV_BOARD_AVERMEDIA98, "AVerMedia TVCapture 98" },
+ { 0x03001461, BTTV_BOARD_AVERMEDIA98, "VDOMATE TV TUNER CARD" },
+
+ { 0x1117153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Philips PAL B/G)" },
+ { 0x1118153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Temic PAL B/G)" },
+ { 0x1119153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Philips PAL I)" },
+ { 0x111a153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (Temic PAL I)" },
+
+ { 0x1123153b, BTTV_BOARD_TERRATVRADIO, "Terratec TV Radio+" },
+ { 0x1127153b, BTTV_BOARD_TERRATV, "Terratec TV+ (V1.05)" },
/* clashes with FlyVideo
- *{ 0x18521852, BTTV_TERRATV, "Terratec TV+ (V1.10)" }, */
- { 0x1134153b, BTTV_TERRATVALUE, "Terratec TValue (LR102)" },
- { 0x1135153b, BTTV_TERRATVALUER, "Terratec TValue Radio" }, /* LR102 */
- { 0x5018153b, BTTV_TERRATVALUE, "Terratec TValue" }, /* ?? */
- { 0xff3b153b, BTTV_TERRATVALUER, "Terratec TValue Radio" }, /* ?? */
-
- { 0x400015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
- { 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
- { 0x400d15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
- { 0x401015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
- { 0x401615b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
-
- { 0x1430aa00, BTTV_PV143, "Provideo PV143A" },
- { 0x1431aa00, BTTV_PV143, "Provideo PV143B" },
- { 0x1432aa00, BTTV_PV143, "Provideo PV143C" },
- { 0x1433aa00, BTTV_PV143, "Provideo PV143D" },
- { 0x1433aa03, BTTV_PV143, "Security Eyes" },
-
- { 0x1460aa00, BTTV_PV150, "Provideo PV150A-1" },
- { 0x1461aa01, BTTV_PV150, "Provideo PV150A-2" },
- { 0x1462aa02, BTTV_PV150, "Provideo PV150A-3" },
- { 0x1463aa03, BTTV_PV150, "Provideo PV150A-4" },
-
- { 0x1464aa04, BTTV_PV150, "Provideo PV150B-1" },
- { 0x1465aa05, BTTV_PV150, "Provideo PV150B-2" },
- { 0x1466aa06, BTTV_PV150, "Provideo PV150B-3" },
- { 0x1467aa07, BTTV_PV150, "Provideo PV150B-4" },
-
- { 0xa132ff00, BTTV_IVC100, "IVC-100" },
- { 0xa1550000, BTTV_IVC200, "IVC-200" },
- { 0xa1550001, BTTV_IVC200, "IVC-200" },
- { 0xa1550002, BTTV_IVC200, "IVC-200" },
- { 0xa1550003, BTTV_IVC200, "IVC-200" },
- { 0xa1550100, BTTV_IVC200, "IVC-200G" },
- { 0xa1550101, BTTV_IVC200, "IVC-200G" },
- { 0xa1550102, BTTV_IVC200, "IVC-200G" },
- { 0xa1550103, BTTV_IVC200, "IVC-200G" },
- { 0xa182ff00, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff01, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff02, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff03, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff04, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff05, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff06, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff07, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff08, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff09, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff0a, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff0b, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff0c, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff0d, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff0e, BTTV_IVC120, "IVC-120G" },
- { 0xa182ff0f, BTTV_IVC120, "IVC-120G" },
-
- { 0x41424344, BTTV_GRANDTEC, "GrandTec Multi Capture" },
- { 0x01020304, BTTV_XGUARD, "Grandtec Grand X-Guard" },
-
- { 0x18501851, BTTV_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
- { 0xa0501851, BTTV_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
- { 0x18511851, BTTV_FLYVIDEO98EZ, "FlyVideo 98EZ (LR51)/ CyberMail AV" },
- { 0x18521852, BTTV_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
- { 0x41a0a051, BTTV_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" },
- { 0x18501f7f, BTTV_FLYVIDEO_98, "Lifeview Flyvideo 98" },
-
- { 0x010115cb, BTTV_GMV1, "AG GMV1" },
- { 0x010114c7, BTTV_MODTEC_205, "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
-
- { 0x10b42636, BTTV_HAUPPAUGE878, "STB ???" },
- { 0x217d6606, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" },
- { 0xfff6f6ff, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" },
- { 0x03116000, BTTV_SENSORAY311, "Sensoray 311" },
- { 0x00790e11, BTTV_WINDVR, "Canopus WinDVR PCI" },
- { 0xa0fca1a0, BTTV_ZOLTRIX, "Face to Face Tvmax" },
- { 0x20007063, BTTV_PC_HDTV, "pcHDTV HD-2000 TV"},
- { 0x82b2aa6a, BTTV_SIMUS_GVC1100, "SIMUS GVC1100" },
- { 0x146caa0c, BTTV_PV951, "ituner spectra8" },
- { 0x200a1295, BTTV_PXC200, "ImageNation PXC200A" },
-
- { 0x40111554, BTTV_PV_BT878P_9B, "Prolink Pixelview PV-BT" },
- { 0x17de0a01, BTTV_KWORLD, "Mecer TV/FM/Video Tuner" },
-
- { 0x01051805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #1" },
- { 0x01061805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #2" },
- { 0x01071805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" },
- { 0x01081805, BTTV_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" },
-
- { 0x15409511, BTTV_ACORP_Y878F, "Acorp Y878F" },
+ *{ 0x18521852, BTTV_BOARD_TERRATV, "Terratec TV+ (V1.10)" }, */
+ { 0x1134153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue (LR102)" },
+ { 0x1135153b, BTTV_BOARD_TERRATVALUER, "Terratec TValue Radio" }, /* LR102 */
+ { 0x5018153b, BTTV_BOARD_TERRATVALUE, "Terratec TValue" }, /* ?? */
+ { 0xff3b153b, BTTV_BOARD_TERRATVALUER, "Terratec TValue Radio" }, /* ?? */
+
+ { 0x400015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
+ { 0x400a15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
+ { 0x400d15b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+ { 0x401015b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+ { 0x401615b0, BTTV_BOARD_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+
+ { 0x1430aa00, BTTV_BOARD_PV143, "Provideo PV143A" },
+ { 0x1431aa00, BTTV_BOARD_PV143, "Provideo PV143B" },
+ { 0x1432aa00, BTTV_BOARD_PV143, "Provideo PV143C" },
+ { 0x1433aa00, BTTV_BOARD_PV143, "Provideo PV143D" },
+ { 0x1433aa03, BTTV_BOARD_PV143, "Security Eyes" },
+
+ { 0x1460aa00, BTTV_BOARD_PV150, "Provideo PV150A-1" },
+ { 0x1461aa01, BTTV_BOARD_PV150, "Provideo PV150A-2" },
+ { 0x1462aa02, BTTV_BOARD_PV150, "Provideo PV150A-3" },
+ { 0x1463aa03, BTTV_BOARD_PV150, "Provideo PV150A-4" },
+
+ { 0x1464aa04, BTTV_BOARD_PV150, "Provideo PV150B-1" },
+ { 0x1465aa05, BTTV_BOARD_PV150, "Provideo PV150B-2" },
+ { 0x1466aa06, BTTV_BOARD_PV150, "Provideo PV150B-3" },
+ { 0x1467aa07, BTTV_BOARD_PV150, "Provideo PV150B-4" },
+
+ { 0xa132ff00, BTTV_BOARD_IVC100, "IVC-100" },
+ { 0xa1550000, BTTV_BOARD_IVC200, "IVC-200" },
+ { 0xa1550001, BTTV_BOARD_IVC200, "IVC-200" },
+ { 0xa1550002, BTTV_BOARD_IVC200, "IVC-200" },
+ { 0xa1550003, BTTV_BOARD_IVC200, "IVC-200" },
+ { 0xa1550100, BTTV_BOARD_IVC200, "IVC-200G" },
+ { 0xa1550101, BTTV_BOARD_IVC200, "IVC-200G" },
+ { 0xa1550102, BTTV_BOARD_IVC200, "IVC-200G" },
+ { 0xa1550103, BTTV_BOARD_IVC200, "IVC-200G" },
+ { 0xa182ff00, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff01, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff02, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff03, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff04, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff05, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff06, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff07, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff08, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff09, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff0a, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff0b, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff0c, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff0d, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff0e, BTTV_BOARD_IVC120, "IVC-120G" },
+ { 0xa182ff0f, BTTV_BOARD_IVC120, "IVC-120G" },
+
+ { 0x41424344, BTTV_BOARD_GRANDTEC, "GrandTec Multi Capture" },
+ { 0x01020304, BTTV_BOARD_XGUARD, "Grandtec Grand X-Guard" },
+
+ { 0x18501851, BTTV_BOARD_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
+ { 0xa0501851, BTTV_BOARD_CHRONOS_VS2, "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
+ { 0x18511851, BTTV_BOARD_FLYVIDEO98EZ, "FlyVideo 98EZ (LR51)/ CyberMail AV" },
+ { 0x18521852, BTTV_BOARD_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
+ { 0x41a0a051, BTTV_BOARD_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" },
+ { 0x18501f7f, BTTV_BOARD_FLYVIDEO_98, "Lifeview Flyvideo 98" },
+
+ { 0x010115cb, BTTV_BOARD_GMV1, "AG GMV1" },
+ { 0x010114c7, BTTV_BOARD_MODTEC_205, "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
+
+ { 0x10b42636, BTTV_BOARD_HAUPPAUGE878, "STB ???" },
+ { 0x217d6606, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" },
+ { 0xfff6f6ff, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" },
+ { 0x03116000, BTTV_BOARD_SENSORAY311, "Sensoray 311" },
+ { 0x00790e11, BTTV_BOARD_WINDVR, "Canopus WinDVR PCI" },
+ { 0xa0fca1a0, BTTV_BOARD_ZOLTRIX, "Face to Face Tvmax" },
+ { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV"},
+ { 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" },
+ { 0x146caa0c, BTTV_BOARD_PV951, "ituner spectra8" },
+ { 0x200a1295, BTTV_BOARD_PXC200, "ImageNation PXC200A" },
+
+ { 0x40111554, BTTV_BOARD_PV_BT878P_9B, "Prolink Pixelview PV-BT" },
+ { 0x17de0a01, BTTV_BOARD_KWORLD, "Mecer TV/FM/Video Tuner" },
+
+ { 0x01051805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #1" },
+ { 0x01061805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #2" },
+ { 0x01071805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #3" },
+ { 0x01081805, BTTV_BOARD_PICOLO_TETRA_CHIP, "Picolo Tetra Chip #4" },
+
+ { 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" },
/* likely broken, vendor id doesn't match the other magic views ...
- * { 0xa0fca04f, BTTV_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */
+ * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */
/* DVB cards (using pci function .1 for mpeg data xfer) */
- { 0x01010071, BTTV_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
- { 0x07611461, BTTV_AVDVBT_761, "AverMedia AverTV DVB-T 761" },
- { 0x001c11bd, BTTV_PINNACLESAT, "Pinnacle PCTV Sat" },
- { 0x002611bd, BTTV_TWINHAN_DST, "Pinnacle PCTV SAT CI" },
- { 0x00011822, BTTV_TWINHAN_DST, "Twinhan VisionPlus DVB" },
- { 0xfc00270f, BTTV_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" },
- { 0x07711461, BTTV_AVDVBT_771, "AVermedia AverTV DVB-T 771" },
- { 0xdb1018ac, BTTV_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" },
- { 0xd50018ac, BTTV_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
+ { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" },
+ { 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" },
+ { 0x001c11bd, BTTV_BOARD_PINNACLESAT, "Pinnacle PCTV Sat" },
+ { 0x002611bd, BTTV_BOARD_TWINHAN_DST, "Pinnacle PCTV SAT CI" },
+ { 0x00011822, BTTV_BOARD_TWINHAN_DST, "Twinhan VisionPlus DVB" },
+ { 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" },
+ { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
{ 0, -1, NULL }
};
@@ -309,2116 +310,2494 @@ static struct CARD {
/* array with description for bt848 / bt878 tv/grabber cards */
struct tvcard bttv_tvcards[] = {
-{
-/* ---- card 0x00 ---------------------------------- */
- .name = " *** UNKNOWN/GENERIC *** ",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .muxsel = { 2, 3, 1, 0},
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "MIRO PCTV",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 15,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 2, 0, 0, 0, 10},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Hauppauge (bt848)",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 7,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 1, 2, 3, 4},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "STB, Gateway P/N 6000699 (bt848)",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 7,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 4, 0, 2, 3, 1},
- .no_msp34xx = 1,
- .needs_tvaudio = 1,
- .tuner_type = TUNER_PHILIPS_NTSC,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_28,
- .has_radio = 1,
-},{
-
-/* ---- card 0x04 ---------------------------------- */
- .name = "Intel Create and Share PCI/ Smart Video Recorder III",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 2,
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0 },
- .needs_tvaudio = 0,
- .tuner_type = 4,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Diamond DTV2000",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 3,
- .muxsel = { 2, 3, 1, 0},
- .audiomux = { 0, 1, 0, 1, 3},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "AVerMedia TVPhone",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 3,
- .muxsel = { 2, 3, 1, 1},
- .gpiomask = 0x0f,
- .audiomux = { 0x0c, 0x04, 0x08, 0x04, 0},
- /* 0x04 for some cards ?? */
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = avermedia_tvphone_audio,
- .has_remote = 1,
-},{
- .name = "MATRIX-Vision MV-Delta",
- .video_inputs = 5,
- .audio_inputs = 1,
- .tuner = -1,
- .svhs = 3,
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 0, 0},
- .audiomux = {0 },
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x08 ---------------------------------- */
- .name = "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xc00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0xc00, 0x800, 0x400, 0xc00, 0},
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "IMS/IXmicro TurboTV",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 3,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 1, 1, 2, 3, 0},
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .tuner_type = TUNER_TEMIC_PAL,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Hauppauge (bt878)",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x0f, /* old: 7 */
- .muxsel = { 2, 0, 1, 1},
- .audiomux = { 0, 1, 2, 3, 4},
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "MIRO PCTV pro",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x3014f,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x20001,0x10001, 0, 0,10},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x0c ---------------------------------- */
- .name = "ADS Technologies Channel Surfer TV (bt848)",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 15,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 13, 14, 11, 7, 0, 0},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "AVerMedia TVCapture 98",
- .video_inputs = 3,
- .audio_inputs = 4,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 15,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 13, 14, 11, 7, 0, 0},
- .needs_tvaudio = 1,
- .msp34xx_alt = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = avermedia_tv_stereo_audio,
-},{
- .name = "Aimslab Video Highway Xtreme (VHX)",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 7,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 2, 1, 3, 4}, /* old: { 0, 1, 2, 3, 4} */
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Zoltrix TV-Max",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 15,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = {0 , 0, 1 , 0, 10},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x10 ---------------------------------- */
- .name = "Prolink Pixelview PlayTV (bt878)",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x01fe00,
- .muxsel = { 2, 3, 1, 1},
- /* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
- .audiomux = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
-},{
- .name = "Leadtek WinView 601",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x8300f8,
- .muxsel = { 2, 3, 1, 1,0},
- .audiomux = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = winview_audio,
- .has_radio = 1,
-},{
- .name = "AVEC Intercapture",
- .video_inputs = 3,
- .audio_inputs = 2,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0,
- .muxsel = {2, 3, 1, 1},
- .audiomux = {1, 0, 0, 0, 0},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = -1,
- .svhs = -1,
- .gpiomask = 0x8dff00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0 },
- .no_msp34xx = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x14 ---------------------------------- */
- .name = "CEI Raffles Card",
- .video_inputs = 3,
- .audio_inputs = 3,
- .tuner = 0,
- .svhs = 2,
- .muxsel = {2, 3, 1, 1},
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
- .video_inputs = 4,
- .audio_inputs = 2, /* tuner, line in */
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1800,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800},
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL_I,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Askey CPH050/ Phoebe Tv Master + FM",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xc00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = {0, 1, 0x800, 0x400, 0xc00, 0},
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = -1,
- .gpiomask = 7,
- .muxsel = { 2, 3, -1 },
- .digital_mode = DIGITAL_MODE_CAMERA,
- .audiomux = { 0, 0, 0, 0, 0 },
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_ALPS_TSBB5_PAL_I,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x18 ---------------------------------- */
- .name = "Askey CPH05X/06X (bt878) [many vendors]",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xe00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = {0x400, 0x400, 0x400, 0x400, 0xc00},
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .has_remote = 1,
-},{
- .name = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1f0fff,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x20000, 0x30000, 0x10000, 0, 0x40000},
- .needs_tvaudio = 0,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = terratv_audio,
-},{
- .name = "Hauppauge WinCam newer (bt878)",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 3,
- .gpiomask = 7,
- .muxsel = { 2, 0, 1, 1},
- .audiomux = { 0, 1, 2, 3, 4},
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
- .video_inputs = 4,
- .audio_inputs = 2,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1800,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800},
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_SECAM,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x1c ---------------------------------- */
- .name = "Terratec TerraTV+ Version 1.1 (bt878)",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1f0fff,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x20000, 0x30000, 0x10000, 0x00000, 0x40000},
- .needs_tvaudio = 0,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = terratv_audio,
- /* GPIO wiring:
- External 20 pin connector (for Active Radio Upgrade board)
- gpio00: i2c-sda
- gpio01: i2c-scl
- gpio02: om5610-data
- gpio03: om5610-clk
- gpio04: om5610-wre
- gpio05: om5610-stereo
- gpio06: rds6588-davn
- gpio07: Pin 7 n.c.
- gpio08: nIOW
- gpio09+10: nIOR, nSEL ?? (bt878)
- gpio09: nIOR (bt848)
- gpio10: nSEL (bt848)
- Sound Routing:
- gpio16: u2-A0 (1st 4052bt)
- gpio17: u2-A1
- gpio18: u2-nEN
- gpio19: u4-A0 (2nd 4052)
- gpio20: u4-A1
- u4-nEN - GND
- Btspy:
- 00000 : Cdrom (internal audio input)
- 10000 : ext. Video audio input
- 20000 : TV Mono
- a0000 : TV Mono/2
- 1a0000 : TV Stereo
- 30000 : Radio
- 40000 : Mute
-*/
-
-},{
- /* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
- .name = "Imagenation PXC200",
- .video_inputs = 5,
- .audio_inputs = 1,
- .tuner = -1,
- .svhs = 1, /* was: 4 */
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 0, 0},
- .audiomux = { 0 },
- .needs_tvaudio = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .muxsel_hook = PXC200_muxsel,
-
-},{
- .name = "Lifeview FlyVideo 98 LR50",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1800, /* 0x8dfe00 */
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 },
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Formac iProTV, Formac ProTV I (bt848)",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 3,
- .gpiomask = 1,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 1, 0, 0, 0, 0 },
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x20 ---------------------------------- */
- .name = "Intel Create and Share PCI/ Smart Video Recorder III",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 2,
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0 },
- .needs_tvaudio = 0,
- .tuner_type = 4,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Terratec TerraTValue Version Bt878",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xffff00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x500, 0, 0x300, 0x900, 0x900},
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Leadtek WinFast 2000/ WinFast 2000 XP",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .muxsel = { 2, 3, 1, 1, 0}, /* TV, CVid, SVid, CVid over SVid connector */
- /* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
- .gpiomask = 0xb33000,
- .audiomux = { 0x122000,0x1000,0x0000,0x620000,0x800000 },
- /* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
- gpio23 -- hef4052:nEnable (0x800000)
- gpio12 -- hef4052:A1
- gpio13 -- hef4052:A0
- 0x0000: external audio
- 0x1000: FM
- 0x2000: TV
- 0x3000: n.c.
- Note: There exists another variant "Winfast 2000" with tv stereo !?
- Note: eeprom only contains FF and pci subsystem id 107d:6606
- */
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .has_radio = 1,
- .tuner_type = 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */
- .tuner_addr = ADDR_UNSET,
- .audio_hook = winfast2000_audio,
- .has_remote = 1,
-},{
- .name = "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
- .video_inputs = 4,
- .audio_inputs = 3,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1800,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800},
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x24 ---------------------------------- */
- .name = "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
- .video_inputs = 4,
- .audio_inputs = 3,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1800,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .has_radio = 1,
-},{
- .name = "Prolink PixelView PlayTV pro",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xff,
- .muxsel = { 2, 3, 1, 1 },
- .audiomux = { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Askey CPH06X TView99",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x551e00,
- .muxsel = { 2, 3, 1, 0},
- .audiomux = { 0x551400, 0x551200, 0, 0, 0x551c00, 0x551200 },
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = 1,
- .tuner_addr = ADDR_UNSET,
- .has_remote = 1,
-},{
- .name = "Pinnacle PCTV Studio/Rave",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x03000F,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 2, 0xd0001, 0, 0, 1},
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x28 ---------------------------------- */
- .name = "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 7,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 4, 0, 2, 3, 1},
- .no_msp34xx = 1,
- .needs_tvaudio = 1,
- .tuner_type = TUNER_PHILIPS_NTSC,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_28,
- .has_radio = 1,
-},{
- .name = "AVerMedia TVPhone 98",
- .video_inputs = 3,
- .audio_inputs = 4,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 15,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 13, 4, 11, 7, 0, 0},
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .has_radio = 1,
- .audio_hook = avermedia_tvphone_audio,
-},{
- .name = "ProVideo PV951", /* pic16c54 */
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0, 0, 0, 0},
- .needs_tvaudio = 1,
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = 1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Little OnAir TV",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xe00b,
- .muxsel = {2, 3, 1, 1},
- .audiomux = {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},
- .no_msp34xx = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x2c ---------------------------------- */
- .name = "Sigma TVII-FM",
- .video_inputs = 2,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = -1,
- .gpiomask = 3,
- .muxsel = {2, 3, 1, 1},
- .audiomux = {1, 1, 0, 2, 3},
- .no_msp34xx = 1,
- .pll = PLL_NONE,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "MATRIX-Vision MV-Delta 2",
- .video_inputs = 5,
- .audio_inputs = 1,
- .tuner = -1,
- .svhs = 3,
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 0, 0},
- .audiomux = {0 },
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Zoltrix Genie TV/FM",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xbcf03f,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0xbc803f, 0xbc903f, 0xbcb03f, 0, 0xbcb03f},
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = 21,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Terratec TV/Radio+",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x70000,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x20000, 0x30000, 0x10000, 0, 0x40000, 0x20000 },
- .needs_tvaudio = 1,
- .no_msp34xx = 1,
- .pll = PLL_35,
- .tuner_type = 1,
- .tuner_addr = ADDR_UNSET,
- .has_radio = 1,
-},{
-
-/* ---- card 0x30 ---------------------------------- */
- .name = "Askey CPH03x/ Dynalink Magic TView",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 15,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = {2,0,0,0,1},
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "IODATA GV-BCTV3/PCI",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x010f00,
- .muxsel = {2, 3, 0, 0},
- .audiomux = {0x10000, 0, 0x10000, 0, 0, 0},
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_ALPS_TSHC6_NTSC,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = gvbctv3pci_audio,
-},{
- .name = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
- .video_inputs = 5,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 3,
- .gpiomask = 0xAA0000,
- .muxsel = { 2,3,1,1,-1 },
- .digital_mode = DIGITAL_MODE_CAMERA,
- .audiomux = { 0x20000, 0, 0x80000, 0x80000, 0xa8000, 0x46000 },
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL_I,
- .tuner_addr = ADDR_UNSET,
- .has_remote = 1,
- /* GPIO wiring: (different from Rev.4C !)
- GPIO17: U4.A0 (first hef4052bt)
- GPIO19: U4.A1
- GPIO20: U5.A1 (second hef4052bt)
- GPIO21: U4.nEN
- GPIO22: BT832 Reset Line
- GPIO23: A5,A0, U5,nEN
- Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22
- */
-},{
- .name = "Eagle Wireless Capricorn2 (bt878A)",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 7,
- .muxsel = { 2, 0, 1, 1},
- .audiomux = { 0, 1, 2, 3, 4},
- .pll = PLL_28,
- .tuner_type = -1 /* TUNER_ALPS_TMDH2_NTSC */,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x34 ---------------------------------- */
- /* David Härdeman <david@2gen.com> */
- .name = "Pinnacle PCTV Studio Pro",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 3,
- .gpiomask = 0x03000F,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 1, 0xd0001, 0, 0, 10},
- /* sound path (5 sources):
- MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable)
- 0= ext. Audio IN
- 1= from MUX2
- 2= Mono TV sound from Tuner
- 3= not connected
- MUX2 (mask 0x30000):
- 0,2,3= from MSP34xx
- 1= FM stereo Radio from Tuner */
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Claas Langbehn <claas@bigfoot.com>,
- Sven Grothklags <sven@upb.de> */
- .name = "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
- .video_inputs = 4,
- .audio_inputs = 3,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1c,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0, 0x10, 8, 4 },
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .has_radio = 1,
-},{
- /* Tim Röstermundt <rosterm@uni-muenster.de>
- in de.comp.os.unix.linux.hardware:
- options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
- audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
- options tuner type=5 */
- .name = "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x18e0,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x0000,0x0800,0x1000,0x1000,0x18e0 },
- /* For cards with tda9820/tda9821:
- 0x0000: Tuner normal stereo
- 0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
- 0x0880: Tuner A2 stereo */
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Miguel Angel Alvarez <maacruz@navegalia.com>
- old Easy TV BT848 version (model CPH031) */
- .name = "Askey CPH031/ BESTBUY Easy TV",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xF,
- .muxsel = { 2, 3, 1, 0},
- .audiomux = { 2, 0, 0, 0, 10},
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .tuner_type = TUNER_TEMIC_PAL,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x38 ---------------------------------- */
- /* Gordon Heydon <gjheydon@bigfoot.com ('98) */
- .name = "Lifeview FlyVideo 98FM LR50",
- .video_inputs = 4,
- .audio_inputs = 3,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1800,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
- .pll = PLL_28,
- .tuner_type = 5,
- .tuner_addr = ADDR_UNSET,
-},{
- /* This is the ultimate cheapo capture card
- * just a BT848A on a small PCB!
- * Steve Hosgood <steve@equiinet.com> */
- .name = "GrandTec 'Grand Video Capture' (Bt848)",
- .video_inputs = 2,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 1,
- .gpiomask = 0,
- .muxsel = { 3, 1 },
- .audiomux = { 0 },
- .needs_tvaudio = 0,
- .no_msp34xx = 1,
- .pll = PLL_35,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Daniel Herrington <daniel.herrington@home.com> */
- .name = "Askey CPH060/ Phoebe TV Master Only (No FM)",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xe00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_TEMIC_4036FY5_NTSC,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Matti Mottus <mottus@physic.ut.ee> */
- .name = "Askey CPH03x TV Capturer",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x03000F,
- .muxsel = { 2, 3, 1, 0},
- .audiomux = { 2,0,0,0,1 },
- .pll = PLL_28,
- .tuner_type = 0,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x3c ---------------------------------- */
- /* Philip Blundell <philb@gnu.org> */
- .name = "Modular Technology MM100PCTV",
- .video_inputs = 2,
- .audio_inputs = 2,
- .tuner = 0,
- .svhs = -1,
- .gpiomask = 11,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 2, 0, 0, 1, 8},
- .pll = PLL_35,
- .tuner_type = TUNER_TEMIC_PAL,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Adrian Cox <adrian@humboldt.co.uk */
- .name = "AG Electronics GMV1",
- .video_inputs = 2,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 1,
- .gpiomask = 0xF,
- .muxsel = { 2, 2},
- .audiomux = { },
- .no_msp34xx = 1,
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Miguel Angel Alvarez <maacruz@navegalia.com>
- new Easy TV BT878 version (model CPH061)
- special thanks to Informatica Mieres for providing the card */
- .name = "Askey CPH061/ BESTBUY Easy TV (bt878)",
- .video_inputs = 3,
- .audio_inputs = 2,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xFF,
- .muxsel = { 2, 3, 1, 0},
- .audiomux = { 1, 0, 4, 4, 9},
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Lukas Gebauer <geby@volny.cz> */
- .name = "ATI TV-Wonder",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xf03f,
- .muxsel = { 2, 3, 1, 0 },
- .audiomux = { 0xbffe, 0, 0xbfff, 0, 0xbffe},
- .pll = PLL_28,
- .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x40 ---------------------------------- */
- /* Lukas Gebauer <geby@volny.cz> */
- .name = "ATI TV-Wonder VE",
- .video_inputs = 2,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = -1,
- .gpiomask = 1,
- .muxsel = { 2, 3, 0, 1},
- .audiomux = { 0, 0, 1, 0, 0},
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL,
- .tuner_addr = ADDR_UNSET,
-},{
- /* DeeJay <deejay@westel900.net (2000S) */
- .name = "Lifeview FlyVideo 2000S LR90",
- .video_inputs = 3,
- .audio_inputs = 3,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x18e0,
- .muxsel = { 2, 3, 0, 1},
- /* Radio changed from 1e80 to 0x800 to make
- FlyVideo2000S in .hu happy (gm)*/
- /* -dk-???: set mute=0x1800 for tda9874h daughterboard */
- .audiomux = { 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 },
- .audio_hook = fv2000s_audio,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = 5,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Terratec TValueRadio",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0xffff00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x500, 0x500, 0x300, 0x900, 0x900},
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .has_radio = 1,
-},{
- /* TANAKA Kei <peg00625@nifty.com> */
- .name = "IODATA GV-BCTV4/PCI",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x010f00,
- .muxsel = {2, 3, 0, 0},
- .audiomux = {0x10000, 0, 0x10000, 0, 0, 0},
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_SHARP_2U5JF5540_NTSC,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = gvbctv3pci_audio,
-},{
-
-/* ---- card 0x44 ---------------------------------- */
- .name = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
- /* try "insmod msp3400 simple=0" if you have
- * sound problems with this card. */
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = -1,
- .gpiomask = 0x4f8a00,
- /* 0x100000: 1=MSP enabled (0=disable again)
- * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
- .audiomux = {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff},
- /* tvtuner, radio, external,internal, mute, stereo
- * tuner, Composit, SVid, Composit-on-Svid-adapter */
- .muxsel = { 2, 3 ,0 ,1},
- .tuner_type = TUNER_MT2032,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_28,
- .has_radio = 1,
-},{
- /* Philip Blundell <pb@nexus.co.uk> */
- .name = "Active Imaging AIMMS",
- .video_inputs = 1,
- .audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_28,
- .muxsel = { 2 },
- .gpiomask = 0
-},{
- /* Tomasz Pyra <hellfire@sedez.iq.pl> */
- .name = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)",
- .video_inputs = 3,
- .audio_inputs = 4,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 15,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0, 11, 7, 13, 0}, /* TV and Radio with same GPIO ! */
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = 25,
- .tuner_addr = ADDR_UNSET,
- .has_remote = 1,
- /* GPIO wiring:
- GPIO0: U4.A0 (hef4052bt)
- GPIO1: U4.A1
- GPIO2: U4.A1 (second hef4052bt)
- GPIO3: U4.nEN, U5.A0, A5.nEN
- GPIO8-15: vrd866b ?
+ /* ---- card 0x00 ---------------------------------- */
+ [BTTV_BOARD_UNKNOWN] = {
+ .name = " *** UNKNOWN/GENERIC *** ",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1, 0},
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MIRO] = {
+ .name = "MIRO PCTV",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 15,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 2, 0, 0, 0, 10},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_HAUPPAUGE] = {
+ .name = "Hauppauge (bt848)",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 7,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 1, 2, 3, 4},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_STB] = {
+ .name = "STB, Gateway P/N 6000699 (bt848)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 7,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 4, 0, 2, 3, 1},
+ .no_msp34xx = 1,
+ .needs_tvaudio = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ },
+
+ /* ---- card 0x04 ---------------------------------- */
+ [BTTV_BOARD_INTEL] = {
+ .name = "Intel Create and Share PCI/ Smart Video Recorder III",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 2,
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0 },
+ .needs_tvaudio = 0,
+ .tuner_type = 4,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_DIAMOND] = {
+ .name = "Diamond DTV2000",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 3,
+ .muxsel = { 2, 3, 1, 0},
+ .audiomux = { 0, 1, 0, 1, 3},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_AVERMEDIA] = {
+ .name = "AVerMedia TVPhone",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 3,
+ .muxsel = { 2, 3, 1, 1},
+ .gpiomask = 0x0f,
+ .audiomux = { 0x0c, 0x04, 0x08, 0x04, 0},
+ /* 0x04 for some cards ?? */
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = avermedia_tvphone_audio,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_MATRIX_VISION] = {
+ .name = "MATRIX-Vision MV-Delta",
+ .video_inputs = 5,
+ .audio_inputs = 1,
+ .tuner = -1,
+ .svhs = 3,
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 0, 0},
+ .audiomux = {0 },
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x08 ---------------------------------- */
+ [BTTV_BOARD_FLYVIDEO] = {
+ .name = "Lifeview FlyVideo II (Bt848) LR26 / MAXI TV Video PCI2 LR26",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xc00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0xc00, 0x800, 0x400, 0xc00, 0},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TURBOTV] = {
+ .name = "IMS/IXmicro TurboTV",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 3,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 1, 1, 2, 3, 0},
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TEMIC_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_HAUPPAUGE878] = {
+ .name = "Hauppauge (bt878)",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x0f, /* old: 7 */
+ .muxsel = { 2, 0, 1, 1},
+ .audiomux = { 0, 1, 2, 3, 4},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MIROPRO] = {
+ .name = "MIRO PCTV pro",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x3014f,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x20001,0x10001, 0, 0,10},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x0c ---------------------------------- */
+ [BTTV_BOARD_ADSTECH_TV] = {
+ .name = "ADS Technologies Channel Surfer TV (bt848)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 15,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 13, 14, 11, 7, 0, 0},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_AVERMEDIA98] = {
+ .name = "AVerMedia TVCapture 98",
+ .video_inputs = 3,
+ .audio_inputs = 4,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 15,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 13, 14, 11, 7, 0, 0},
+ .needs_tvaudio = 1,
+ .msp34xx_alt = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = avermedia_tv_stereo_audio,
+ .no_gpioirq = 1,
+ },
+ [BTTV_BOARD_VHX] = {
+ .name = "Aimslab Video Highway Xtreme (VHX)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 7,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 2, 1, 3, 4}, /* old: { 0, 1, 2, 3, 4} */
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ZOLTRIX] = {
+ .name = "Zoltrix TV-Max",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 15,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = {0 , 0, 1 , 0, 10},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x10 ---------------------------------- */
+ [BTTV_BOARD_PIXVIEWPLAYTV] = {
+ .name = "Prolink Pixelview PlayTV (bt878)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x01fe00,
+ .muxsel = { 2, 3, 1, 1},
+ #if 0
+ /* old */
+ .audiomux = { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },
+ #else
+ /* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
+ .audiomux = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
+ #endif
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ },
+ [BTTV_BOARD_WINVIEW_601] = {
+ .name = "Leadtek WinView 601",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x8300f8,
+ .muxsel = { 2, 3, 1, 1,0},
+ .audiomux = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = winview_audio,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_AVEC_INTERCAP] = {
+ .name = "AVEC Intercapture",
+ .video_inputs = 3,
+ .audio_inputs = 2,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0,
+ .muxsel = {2, 3, 1, 1},
+ .audiomux = {1, 0, 0, 0, 0},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_LIFE_FLYKIT] = {
+ .name = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = -1,
+ .svhs = -1,
+ .gpiomask = 0x8dff00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0 },
+ .no_msp34xx = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x14 ---------------------------------- */
+ [BTTV_BOARD_CEI_RAFFLES] = {
+ .name = "CEI Raffles Card",
+ .video_inputs = 3,
+ .audio_inputs = 3,
+ .tuner = 0,
+ .svhs = 2,
+ .muxsel = {2, 3, 1, 1},
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_CONFERENCETV] = {
+ .name = "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
+ .video_inputs = 4,
+ .audio_inputs = 2, /* tuner, line in */
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1800,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800},
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_PHOEBE_TVMAS] = {
+ .name = "Askey CPH050/ Phoebe Tv Master + FM",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xc00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = {0, 1, 0x800, 0x400, 0xc00, 0},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MODTEC_205] = {
+ .name = "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = -1,
+ .gpiomask = 7,
+ .muxsel = { 2, 3, -1 },
+ .digital_mode = DIGITAL_MODE_CAMERA,
+ .audiomux = { 0, 0, 0, 0, 0 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_ALPS_TSBB5_PAL_I,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x18 ---------------------------------- */
+ [BTTV_BOARD_MAGICTVIEW061] = {
+ .name = "Askey CPH05X/06X (bt878) [many vendors]",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xe00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = {0x400, 0x400, 0x400, 0x400, 0xc00},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_VOBIS_BOOSTAR] = {
+ .name = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1f0fff,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x20000, 0x30000, 0x10000, 0, 0x40000},
+ .needs_tvaudio = 0,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = terratv_audio,
+ },
+ [BTTV_BOARD_HAUPPAUG_WCAM] = {
+ .name = "Hauppauge WinCam newer (bt878)",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 3,
+ .gpiomask = 7,
+ .muxsel = { 2, 0, 1, 1},
+ .audiomux = { 0, 1, 2, 3, 4},
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MAXI] = {
+ .name = "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
+ .video_inputs = 4,
+ .audio_inputs = 2,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1800,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800},
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_SECAM,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x1c ---------------------------------- */
+ [BTTV_BOARD_TERRATV] = {
+ .name = "Terratec TerraTV+ Version 1.1 (bt878)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1f0fff,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x20000, 0x30000, 0x10000, 0x00000, 0x40000},
+ .needs_tvaudio = 0,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = terratv_audio,
+ /* GPIO wiring:
+ External 20 pin connector (for Active Radio Upgrade board)
+ gpio00: i2c-sda
+ gpio01: i2c-scl
+ gpio02: om5610-data
+ gpio03: om5610-clk
+ gpio04: om5610-wre
+ gpio05: om5610-stereo
+ gpio06: rds6588-davn
+ gpio07: Pin 7 n.c.
+ gpio08: nIOW
+ gpio09+10: nIOR, nSEL ?? (bt878)
+ gpio09: nIOR (bt848)
+ gpio10: nSEL (bt848)
+ Sound Routing:
+ gpio16: u2-A0 (1st 4052bt)
+ gpio17: u2-A1
+ gpio18: u2-nEN
+ gpio19: u4-A0 (2nd 4052)
+ gpio20: u4-A1
+ u4-nEN - GND
+ Btspy:
+ 00000 : Cdrom (internal audio input)
+ 10000 : ext. Video audio input
+ 20000 : TV Mono
+ a0000 : TV Mono/2
+ 1a0000 : TV Stereo
+ 30000 : Radio
+ 40000 : Mute
*/
-},{
- .name = "Lifeview FlyVideo 98EZ (capture only) LR51",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 2,
- .muxsel = { 2, 3, 1, 1}, /* AV1, AV2, SVHS, CVid adapter on SVHS */
- .pll = PLL_28,
- .no_msp34xx = 1,
- .tuner_type = UNSET,
- .tuner_addr = ADDR_UNSET,
-},{
-
-/* ---- card 0x48 ---------------------------------- */
- /* Dariusz Kowalewski <darekk@automex.pl> */
- .name = "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x3f,
- .muxsel = { 2, 3, 1, 1 },
- .audiomux = { 0x01, 0x00, 0x03, 0x03, 0x09, 0x02 },
- .needs_tvaudio = 1,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .pll = PLL_28,
- .tuner_type = 5,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = pvbt878p9b_audio, /* Note: not all cards have stereo */
- .has_radio = 1, /* Note: not all cards have radio */
- .has_remote = 1,
- /* GPIO wiring:
- GPIO0: A0 hef4052
- GPIO1: A1 hef4052
- GPIO3: nEN hef4052
- GPIO8-15: vrd866b
- GPIO20,22,23: R30,R29,R28
- */
-},{
- /* Clay Kunz <ckunz@mail.arc.nasa.gov> */
- /* you must jumper JP5 for the card to work */
- .name = "Sensoray 311",
- .video_inputs = 5,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 4,
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 0, 0},
- .audiomux = { 0 },
- .needs_tvaudio = 0,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Miguel Freitas <miguel@cetuc.puc-rio.br> */
- .name = "RemoteVision MX (RV605)",
- .video_inputs = 16,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .gpiomask = 0x00,
- .gpiomask2 = 0x07ff,
- .muxsel = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
- 0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .muxsel_hook = rv605_muxsel,
-},{
- .name = "Powercolor MTV878/ MTV878R/ MTV878F",
- .video_inputs = 3,
- .audio_inputs = 2,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x1C800F, /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */
- .muxsel = { 2, 1, 1, },
- .audiomux = { 0, 1, 2, 2, 4 },
- .needs_tvaudio = 0,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_28,
- .has_radio = 1,
-},{
-
-/* ---- card 0x4c ---------------------------------- */
- /* Masaki Suzuki <masaki@btree.org> */
- .name = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x140007,
- .muxsel = { 2, 3, 1, 1 },
- .audiomux = { 0, 1, 2, 3, 4, 0 },
- .tuner_type = TUNER_PHILIPS_NTSC,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = windvr_audio,
-},{
- .name = "GrandTec Multi Capture Card (Bt878)",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 0 },
- .audiomux = { 0 },
- .needs_tvaudio = 0,
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
- .video_inputs = 4,
- .audio_inputs = 3,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 7,
- .muxsel = { 2, 3, 1, 1 }, /* Tuner, SVid, SVHS, SVid to SVHS connector */
- .audiomux = { 0 ,0 ,4, 4,4,4},/* Yes, this tuner uses the same audio output for TV and FM radio!
- * This card lacks external Audio In, so we mute it on Ext. & Int.
- * The PCB can take a sbx1637/sbx1673, wiring unknown.
- * This card lacks PCI subsystem ID, sigh.
- * audiomux=1: lower volume, 2+3: mute
- * btwincap uses 0x80000/0x80003
- */
- .needs_tvaudio = 0,
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = 5,
- .tuner_addr = ADDR_UNSET,
- /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
- radio signal strength indicators work fine. */
- .has_radio = 1,
- /* GPIO Info:
- GPIO0,1: HEF4052 A0,A1
- GPIO2: HEF4052 nENABLE
- GPIO3-7: n.c.
- GPIO8-13: IRDC357 data0-5 (data6 n.c. ?) [chip not present on my card]
- GPIO14,15: ??
- GPIO16-21: n.c.
- GPIO22,23: ??
- ?? : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/
-},{
- /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
- .name = "DSP Design TCVIDEO",
- .video_inputs = 4,
- .svhs = -1,
- .muxsel = { 2, 3, 1, 0},
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
- /* ---- card 0x50 ---------------------------------- */
- .name = "Hauppauge WinTV PVR",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .muxsel = { 2, 0, 1, 1},
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-
- .gpiomask = 7,
- .audiomux = {7},
-},{
- .name = "IODATA GV-BCTV5/PCI",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x0f0f80,
- .muxsel = {2, 3, 1, 0},
- .audiomux = {0x030000, 0x010000, 0, 0, 0x020000, 0},
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_NTSC_M,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = gvbctv5pci_audio,
- .has_radio = 1,
-},{
- .name = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
- .video_inputs = 4, /* id-inputs-clock */
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 3,
- .muxsel = { 3, 2, 0, 1 },
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
-},{
- .name = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
- .video_inputs = 3,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 2,
- .muxsel = { 2, 3, 1 },
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
-},{
-
- /* ---- card 0x54 ---------------------------------- */
- .name = "Osprey 101 (848)", /* 0x05-40C0-C1 */
- .video_inputs = 2,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 1,
- .muxsel = { 3, 1 },
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
-},{
- .name = "Osprey 101/151", /* 0x1(4|5)-0004-C4 */
- .video_inputs = 1,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .muxsel = { 0 },
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
-},{
- .name = "Osprey 101/151 w/ svid", /* 0x(16|17|20)-00C4-C1 */
- .video_inputs = 2,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 1,
- .muxsel = { 0, 1 },
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
-},{
- .name = "Osprey 200/201/250/251", /* 0x1(8|9|E|F)-0004-C4 */
- .video_inputs = 1,
- .audio_inputs = 1,
- .tuner = -1,
- .svhs = -1,
- .muxsel = { 0 },
- .pll = PLL_28,
- .tuner_type = UNSET,
- .tuner_addr = ADDR_UNSET,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
-},{
-
- /* ---- card 0x58 ---------------------------------- */
- .name = "Osprey 200/250", /* 0x1(A|B)-00C4-C1 */
- .video_inputs = 2,
- .audio_inputs = 1,
- .tuner = -1,
- .svhs = 1,
- .muxsel = { 0, 1 },
- .pll = PLL_28,
- .tuner_type = UNSET,
- .tuner_addr = ADDR_UNSET,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
-},{
- .name = "Osprey 210/220", /* 0x1(A|B)-04C0-C1 */
- .video_inputs = 2,
- .audio_inputs = 1,
- .tuner = -1,
- .svhs = 1,
- .muxsel = { 2, 3 },
- .pll = PLL_28,
- .tuner_type = UNSET,
- .tuner_addr = ADDR_UNSET,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
-},{
- .name = "Osprey 500", /* 500 */
- .video_inputs = 2,
- .audio_inputs = 1,
- .tuner = -1,
- .svhs = 1,
- .muxsel = { 2, 3 },
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
-},{
- .name = "Osprey 540", /* 540 */
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = -1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
-},{
-
- /* ---- card 0x5C ---------------------------------- */
- .name = "Osprey 2000", /* 2000 */
- .video_inputs = 2,
- .audio_inputs = 1,
- .tuner = -1,
- .svhs = 1,
- .muxsel = { 2, 3 },
- .pll = PLL_28,
- .tuner_type = UNSET,
- .tuner_addr = ADDR_UNSET,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1, /* must avoid, conflicts with the bt860 */
-},{
- /* M G Berberich <berberic@forwiss.uni-passau.de> */
- .name = "IDS Eagle",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .svhs = -1,
- .gpiomask = 0,
- .muxsel = { 0, 1, 2, 3 },
- .muxsel_hook = eagle_muxsel,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .pll = PLL_28,
-},{
- .name = "Pinnacle PCTV Sat",
- .video_inputs = 2,
- .audio_inputs = 0,
- .svhs = 1,
- .tuner = -1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .gpiomask = 0x01,
- .audiomux = { 0, 0, 0, 0, 1 },
- .muxsel = { 3, 0, 1, 2},
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .no_gpioirq = 1,
- .has_dvb = 1,
-},{
- .name = "Formac ProTV II (bt878)",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 3,
- .gpiomask = 2,
- /* TV, Comp1, Composite over SVID con, SVID */
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 2, 2, 0, 0, 0 },
- .pll = PLL_28,
- .has_radio = 1,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
-/* sound routing:
- GPIO=0x00,0x01,0x03: mute (?)
- 0x02: both TV and radio (tuner: FM1216/I)
- The card has onboard audio connectors labeled "cdrom" and "board",
- not soldered here, though unknown wiring.
- Card lacks: external audio in, pci subsystem id.
-*/
-},{
-
- /* ---- card 0x60 ---------------------------------- */
- .name = "MachTV",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = -1,
- .gpiomask = 7,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 1, 2, 3, 4},
- .needs_tvaudio = 1,
- .tuner_type = 5,
- .tuner_addr = ADDR_UNSET,
- .pll = 1,
-},{
- .name = "Euresys Picolo",
- .video_inputs = 3,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = 2,
- .gpiomask = 0,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .muxsel = { 2, 0, 1},
- .pll = PLL_28,
- .tuner_type = UNSET,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Luc Van Hoeylandt <luc@e-magic.be> */
- .name = "ProVideo PV150", /* 0x4f */
- .video_inputs = 2,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .gpiomask = 0,
- .muxsel = { 2, 3 },
- .audiomux = { 0 },
- .needs_tvaudio = 0,
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = UNSET,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Hiroshi Takekawa <sian@big.or.jp> */
- /* This card lacks subsystem ID */
- .name = "AD-TVK503", /* 0x63 */
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x001e8007,
- .muxsel = { 2, 3, 1, 0 },
- /* Tuner, Radio, external, internal, off, on */
- .audiomux = { 0x08, 0x0f, 0x0a, 0x08, 0x0f, 0x08 },
- .needs_tvaudio = 0,
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = 2,
- .tuner_addr = ADDR_UNSET,
- .audio_hook = adtvk503_audio,
-},{
-
- /* ---- card 0x64 ---------------------------------- */
- .name = "Hercules Smart TV Stereo",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x00,
- .muxsel = { 2, 3, 1, 1 },
- .needs_tvaudio = 1,
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = 5,
- .tuner_addr = ADDR_UNSET,
- /* Notes:
- - card lacks subsystem ID
- - stereo variant w/ daughter board with tda9874a @0xb0
- - Audio Routing:
- always from tda9874 independent of GPIO (?)
- external line in: unknown
- - Other chips: em78p156elp @ 0x96 (probably IR remote control)
- hef4053 (instead 4052) for unknown function
- */
-},{
- .name = "Pace TV & Radio Card",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .muxsel = { 2, 3, 1, 1}, /* Tuner, CVid, SVid, CVid over SVid connector */
- .gpiomask = 0,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .tuner_type = 1,
- .tuner_addr = ADDR_UNSET,
- .has_radio = 1,
- .pll = PLL_28,
- /* Bt878, Bt832, FI1246 tuner; no pci subsystem id
- only internal line out: (4pin header) RGGL
- Radio must be decoded by msp3410d (not routed through)*/
- /*
- .digital_mode = DIGITAL_MODE_CAMERA, todo!
- */
-},{
- /* Chris Willing <chris@vislab.usyd.edu.au> */
- .name = "IVC-200",
- .video_inputs = 1,
- .audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .svhs = -1,
- .gpiomask = 0xdf,
- .muxsel = { 2 },
- .pll = PLL_28,
-},{
- .name = "Grand X-Guard / Trust 814PCI",
- .video_inputs = 16,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .tuner_type = 4,
- .tuner_addr = ADDR_UNSET,
- .gpiomask2 = 0xff,
- .muxsel = { 2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0 },
- .muxsel_hook = xguard_muxsel,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .pll = PLL_28,
-},{
-
- /* ---- card 0x68 ---------------------------------- */
- .name = "Nebula Electronics DigiTV",
- .video_inputs = 1,
- .tuner = -1,
- .svhs = -1,
- .muxsel = { 2, 3, 1, 0},
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .has_dvb = 1,
- .no_gpioirq = 1,
-},{
- /* Jorge Boncompte - DTI2 <jorge@dti2.net> */
- .name = "ProVideo PV143",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .gpiomask = 0,
- .muxsel = { 2, 3, 1, 0 },
- .audiomux = { 0 },
- .needs_tvaudio = 0,
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* M.Klahr@phytec.de */
- .name = "PHYTEC VD-009-X1 MiniDIN (bt878)",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
- .svhs = 3,
- .gpiomask = 0x00,
- .muxsel = { 2, 3, 1, 0},
- .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "PHYTEC VD-009-X1 Combi (bt878)",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
- .svhs = 3,
- .gpiomask = 0x00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
-
- /* ---- card 0x6c ---------------------------------- */
- .name = "PHYTEC VD-009 MiniDIN (bt878)",
- .video_inputs = 10,
- .audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
- .svhs = 9,
- .gpiomask = 0x00,
- .gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
- via the upper nibble of muxsel. here: used for
- xternal video-mux */
- .muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x00 },
- .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "PHYTEC VD-009 Combi (bt878)",
- .video_inputs = 10,
- .audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
- .svhs = 9,
- .gpiomask = 0x00,
- .gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
- via the upper nibble of muxsel. here: used for
- xternal video-mux */
- .muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x01 },
- .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- .name = "IVC-100",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .svhs = -1,
- .gpiomask = 0xdf,
- .muxsel = { 2, 3, 1, 0 },
- .pll = PLL_28,
-},{
- /* IVC-120G - Alan Garfield <alan@fromorbit.com> */
- .name = "IVC-120G",
- .video_inputs = 16,
- .audio_inputs = 0, /* card has no audio */
- .tuner = -1, /* card has no tuner */
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .svhs = -1, /* card has no svhs */
- .needs_tvaudio = 0,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .gpiomask = 0x00,
- .muxsel = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
- .muxsel_hook = ivc120_muxsel,
- .pll = PLL_28,
-},{
-
- /* ---- card 0x70 ---------------------------------- */
- .name = "pcHDTV HD-2000 TV",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .muxsel = { 2, 3, 1, 0},
- .tuner_type = TUNER_PHILIPS_ATSC,
- .tuner_addr = ADDR_UNSET,
- .has_dvb = 1,
-},{
- .name = "Twinhan DST + clones",
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .tuner_type = TUNER_ABSENT,
- .tuner_addr = ADDR_UNSET,
- .no_video = 1,
- .has_dvb = 1,
-},{
- .name = "Winfast VC100",
- .video_inputs = 3,
- .audio_inputs = 0,
- .svhs = 1,
- .tuner = -1,
- .muxsel = { 3, 1, 1, 3}, /* Vid In, SVid In, Vid over SVid in connector */
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .tuner_type = TUNER_ABSENT,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_28,
-},{
- .name = "Teppro TEV-560/InterVision IV-560",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 3,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 1, 1, 1, 1, 0},
- .needs_tvaudio = 1,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_35,
-},{
-
- /* ---- card 0x74 ---------------------------------- */
- .name = "SIMUS GVC1100",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_28,
- .muxsel = { 2, 2, 2, 2},
- .gpiomask = 0x3F,
- .muxsel_hook = gvc1100_muxsel,
-},{
- /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */
- .name = "NGS NGSTV+",
- .video_inputs = 3,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x008007,
- .muxsel = {2, 3, 0, 0},
- .audiomux = {0, 0, 0, 0, 0x000003, 0},
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .has_remote = 1,
-},{
- /* http://linuxmedialabs.com */
- .name = "LMLBT4",
- .video_inputs = 4, /* IN1,IN2,IN3,IN4 */
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .muxsel = { 2, 3, 1, 0 },
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .needs_tvaudio = 0,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Helmroos Harri <harri.helmroos@pp.inet.fi> */
- .name = "Tekram M205 PRO",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .svhs = 2,
- .needs_tvaudio = 0,
- .gpiomask = 0x68,
- .muxsel = { 2, 3, 1},
- .audiomux = { 0x68, 0x68, 0x61, 0x61, 0x00 },
- .pll = PLL_28,
-},{
-
- /* ---- card 0x78 ---------------------------------- */
- /* Javier Cendan Ares <jcendan@lycos.es> */
- /* bt878 TV + FM without subsystem ID */
- .name = "Conceptronic CONTVFMi",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x008007,
- .muxsel = { 2, 3, 1, 1 },
- .audiomux = { 0, 1, 2, 2, 3 },
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .has_remote = 1,
- .has_radio = 1,
-},{
- /*Eric DEBIEF <debief@telemsa.com>*/
- /*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controled*/
- /* adds picolo_tetra_muxsel(), picolo_tetra_init(), the folowing declaration strucure, and #define BTTV_PICOLO_TETRA_CHIP*/
- /*0x79 in bttv.h*/
- .name = "Euresys Picolo Tetra",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .gpiomask = 0,
- .gpiomask2 = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .muxsel = {2,2,2,2},/*878A input is always MUX0, see above.*/
- .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
- .pll = PLL_28,
- .needs_tvaudio = 0,
- .muxsel_hook = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Spirit TV Tuner from http://spiritmodems.com.au */
- /* Stafford Goodsell <surge@goliath.homeunix.org> */
- .name = "Spirit TV Tuner",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x0000000f,
- .muxsel = { 2, 1, 1 },
- .audiomux = { 0x02, 0x00, 0x00, 0x00, 0x00},
- .tuner_type = TUNER_TEMIC_PAL,
- .tuner_addr = ADDR_UNSET,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
-},{
- /* Wolfram Joost <wojo@frokaschwei.de> */
- .name = "AVerMedia AVerTV DVB-T 771",
- .video_inputs = 2,
- .svhs = 1,
- .tuner = -1,
- .tuner_type = TUNER_ABSENT,
- .tuner_addr = ADDR_UNSET,
- .muxsel = { 3 , 3 },
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .pll = PLL_28,
- .has_dvb = 1,
- .no_gpioirq = 1,
- .has_remote = 1,
-},{
- /* ---- card 0x7c ---------------------------------- */
- /* Matt Jesson <dvb@jesson.eclipse.co.uk> */
- /* Based on the Nebula card data - added remote and new card number - BTTV_AVDVBT_761, see also ir-kbd-gpio.c */
- .name = "AverMedia AverTV DVB-T 761",
- .video_inputs = 2,
- .tuner = -1,
- .svhs = 1,
- .muxsel = { 3, 1, 2, 0}, /* Comp0, S-Video, ?, ? */
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .has_dvb = 1,
- .no_gpioirq = 1,
- .has_remote = 1,
-},{
- /* andre.schwarz@matrix-vision.de */
- .name = "MATRIX Vision Sigma-SQ",
- .video_inputs = 16,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .gpiomask = 0x0,
- .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2,
- 3, 3, 3, 3, 3, 3, 3, 3 },
- .muxsel_hook = sigmaSQ_muxsel,
- .audiomux = { 0 },
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* andre.schwarz@matrix-vision.de */
- .name = "MATRIX Vision Sigma-SLC",
- .video_inputs = 4,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .gpiomask = 0x0,
- .muxsel = { 2, 2, 2, 2 },
- .muxsel_hook = sigmaSLC_muxsel,
- .audiomux = { 0 },
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* BTTV_APAC_VIEWCOMP */
- /* Attila Kondoros <attila.kondoros@chello.hu> */
- /* bt878 TV + FM 0x00000000 subsystem ID */
- .name = "APAC Viewcomp 878(AMAX)",
- .video_inputs = 2,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = -1,
- .gpiomask = 0xFF,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 2, 0, 0, 0, 10},
- .needs_tvaudio = 0,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_PAL,
- .tuner_addr = ADDR_UNSET,
- .has_remote = 1, /* miniremote works, see ir-kbd-gpio.c */
- .has_radio = 1, /* not every card has radio */
-},{
-
- /* ---- card 0x80 ---------------------------------- */
- /* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
- .name = "DViCO FusionHDTV DVB-T Lite",
- .tuner = -1,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .pll = PLL_28,
- .no_video = 1,
- .has_dvb = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
-},{
- /* Steven <photon38@pchome.com.tw> */
- .name = "V-Gear MyVCD",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x3f,
- .muxsel = {2, 3, 1, 0},
- .audiomux = {0x31, 0x31, 0x31, 0x31, 0x31, 0x31},
- .no_msp34xx = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_PHILIPS_NTSC_M,
- .tuner_addr = ADDR_UNSET,
- .has_radio = 0,
-},{
- /* Rick C <cryptdragoon@gmail.com> */
- .name = "Super TV Tuner",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .muxsel = { 2, 3, 1, 0},
- .tuner_type = TUNER_PHILIPS_NTSC,
- .tuner_addr = ADDR_UNSET,
- .gpiomask = 0x008007,
- .audiomux = { 0, 0x000001,0,0, 0},
- .needs_tvaudio = 1,
- .has_radio = 1,
-},{
- /* Chris Fanning <video4linux@haydon.net> */
- .name = "Tibet Systems 'Progress DVR' CS16",
- .video_inputs = 16,
- .audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
- .pll = PLL_28,
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .muxsel_hook = tibetCS16_muxsel,
-},
-{
- /* Bill Brack <wbrack@mmm.com.hk> */
- /*
- * Note that, because of the card's wiring, the "master"
- * BT878A chip (i.e. the one which controls the analog switch
- * and must use this card type) is the 2nd one detected. The
- * other 3 chips should use card type 0x85, whose description
- * follows this one. There is a EEPROM on the card (which is
- * connected to the I2C of one of those other chips), but is
- * not currently handled. There is also a facility for a
- * "monitor", which is also not currently implemented.
- */
- .name = "Kodicom 4400R (master)",
- .video_inputs = 16,
- .audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .svhs = -1,
- /* GPIO bits 0-9 used for analog switch:
- * 00 - 03: camera selector
- * 04 - 06: channel (controller) selector
- * 07: data (1->on, 0->off)
- * 08: strobe
- * 09: reset
- * bit 16 is input from sync separator for the channel
- */
- .gpiomask = 0x0003ff,
- .no_gpioirq = 1,
- .muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
- .pll = PLL_28,
- .no_msp34xx = 1,
- .no_tda7432 = 1,
- .no_tda9875 = 1,
- .muxsel_hook = kodicom4400r_muxsel,
-},
-{
- /* Bill Brack <wbrack@mmm.com.hk> */
- /* Note that, for reasons unknown, the "master" BT878A chip (i.e. the
- * one which controls the analog switch, and must use the card type)
- * is the 2nd one detected. The other 3 chips should use this card
- * type
+
+ },
+ [BTTV_BOARD_PXC200] = {
+ /* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
+ .name = "Imagenation PXC200",
+ .video_inputs = 5,
+ .audio_inputs = 1,
+ .tuner = -1,
+ .svhs = 1, /* was: 4 */
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 0, 0},
+ .audiomux = { 0 },
+ .needs_tvaudio = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .muxsel_hook = PXC200_muxsel,
+
+ },
+ [BTTV_BOARD_FLYVIDEO_98] = {
+ .name = "Lifeview FlyVideo 98 LR50",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1800, /* 0x8dfe00 */
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 },
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_IPROTV] = {
+ .name = "Formac iProTV, Formac ProTV I (bt848)",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 3,
+ .gpiomask = 1,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 1, 0, 0, 0, 0 },
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x20 ---------------------------------- */
+ [BTTV_BOARD_INTEL_C_S_PCI] = {
+ .name = "Intel Create and Share PCI/ Smart Video Recorder III",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 2,
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0 },
+ .needs_tvaudio = 0,
+ .tuner_type = 4,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TERRATVALUE] = {
+ .name = "Terratec TerraTValue Version Bt878",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xffff00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x500, 0, 0x300, 0x900, 0x900},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_WINFAST2000] = {
+ .name = "Leadtek WinFast 2000/ WinFast 2000 XP",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1, 1, 0}, /* TV, CVid, SVid, CVid over SVid connector */
+ #if 0
+ .gpiomask = 0xc33000,
+ .audiomux = { 0x422000,0x1000,0x0000,0x620000,0x800000 },
+ #else
+ /* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
+ .gpiomask = 0xb33000,
+ .audiomux = { 0x122000,0x1000,0x0000,0x620000,0x800000 },
+ #endif
+ /* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
+ gpio23 -- hef4052:nEnable (0x800000)
+ gpio12 -- hef4052:A1
+ gpio13 -- hef4052:A0
+ 0x0000: external audio
+ 0x1000: FM
+ 0x2000: TV
+ 0x3000: n.c.
+ Note: There exists another variant "Winfast 2000" with tv stereo !?
+ Note: eeprom only contains FF and pci subsystem id 107d:6606
+ */
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .has_radio = 1,
+ .tuner_type = 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = winfast2000_audio,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_CHRONOS_VS2] = {
+ .name = "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
+ .video_inputs = 4,
+ .audio_inputs = 3,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1800,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800},
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x24 ---------------------------------- */
+ [BTTV_BOARD_TYPHOON_TVIEW] = {
+ .name = "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
+ .video_inputs = 4,
+ .audio_inputs = 3,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1800,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_PXELVWPLTVPRO] = {
+ .name = "Prolink PixelView PlayTV pro",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xff,
+ .muxsel = { 2, 3, 1, 1 },
+ .audiomux = { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MAGICTVIEW063] = {
+ .name = "Askey CPH06X TView99",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x551e00,
+ .muxsel = { 2, 3, 1, 0},
+ .audiomux = { 0x551400, 0x551200, 0, 0, 0x551c00, 0x551200 },
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = 1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_PINNACLE] = {
+ .name = "Pinnacle PCTV Studio/Rave",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x03000F,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 2, 0xd0001, 0, 0, 1},
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x28 ---------------------------------- */
+ [BTTV_BOARD_STB2] = {
+ .name = "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 7,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 4, 0, 2, 3, 1},
+ .no_msp34xx = 1,
+ .needs_tvaudio = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_AVPHONE98] = {
+ .name = "AVerMedia TVPhone 98",
+ .video_inputs = 3,
+ .audio_inputs = 4,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 15,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 13, 4, 11, 7, 0, 0},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ .audio_hook = avermedia_tvphone_audio,
+ },
+ [BTTV_BOARD_PV951] = {
+ .name = "ProVideo PV951", /* pic16c54 */
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0, 0, 0, 0},
+ .needs_tvaudio = 1,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = 1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ONAIR_TV] = {
+ .name = "Little OnAir TV",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xe00b,
+ .muxsel = {2, 3, 1, 1},
+ .audiomux = {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},
+ .no_msp34xx = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x2c ---------------------------------- */
+ [BTTV_BOARD_SIGMA_TVII_FM] = {
+ .name = "Sigma TVII-FM",
+ .video_inputs = 2,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = -1,
+ .gpiomask = 3,
+ .muxsel = {2, 3, 1, 1},
+ .audiomux = {1, 1, 0, 2, 3},
+ .no_msp34xx = 1,
+ .pll = PLL_NONE,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MATRIX_VISION2] = {
+ .name = "MATRIX-Vision MV-Delta 2",
+ .video_inputs = 5,
+ .audio_inputs = 1,
+ .tuner = -1,
+ .svhs = 3,
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 0, 0},
+ .audiomux = {0 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ZOLTRIX_GENIE] = {
+ .name = "Zoltrix Genie TV/FM",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xbcf03f,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0xbc803f, 0xbc903f, 0xbcb03f, 0, 0xbcb03f},
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = 21,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TERRATVRADIO] = {
+ .name = "Terratec TV/Radio+",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x70000,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x20000, 0x30000, 0x10000, 0, 0x40000, 0x20000 },
+ .needs_tvaudio = 1,
+ .no_msp34xx = 1,
+ .pll = PLL_35,
+ .tuner_type = 1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ },
+
+ /* ---- card 0x30 ---------------------------------- */
+ [BTTV_BOARD_DYNALINK] = {
+ .name = "Askey CPH03x/ Dynalink Magic TView",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 15,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = {2,0,0,0,1},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_GVBCTV3PCI] = {
+ .name = "IODATA GV-BCTV3/PCI",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x010f00,
+ .muxsel = {2, 3, 0, 0},
+ .audiomux = {0x10000, 0, 0x10000, 0, 0, 0},
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_ALPS_TSHC6_NTSC,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = gvbctv3pci_audio,
+ },
+ [BTTV_BOARD_PXELVWPLTVPAK] = {
+ .name = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
+ .video_inputs = 5,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 3,
+ .gpiomask = 0xAA0000,
+ .muxsel = { 2,3,1,1,-1 },
+ .digital_mode = DIGITAL_MODE_CAMERA,
+ .audiomux = { 0x20000, 0, 0x80000, 0x80000, 0xa8000, 0x46000 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ /* GPIO wiring: (different from Rev.4C !)
+ GPIO17: U4.A0 (first hef4052bt)
+ GPIO19: U4.A1
+ GPIO20: U5.A1 (second hef4052bt)
+ GPIO21: U4.nEN
+ GPIO22: BT832 Reset Line
+ GPIO23: A5,A0, U5,nEN
+ Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22
+ */
+ },
+ [BTTV_BOARD_EAGLE] = {
+ .name = "Eagle Wireless Capricorn2 (bt878A)",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 7,
+ .muxsel = { 2, 0, 1, 1},
+ .audiomux = { 0, 1, 2, 3, 4},
+ .pll = PLL_28,
+ .tuner_type = -1 /* TUNER_ALPS_TMDH2_NTSC */,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x34 ---------------------------------- */
+ [BTTV_BOARD_PINNACLEPRO] = {
+ /* David Härdeman <david@2gen.com> */
+ .name = "Pinnacle PCTV Studio Pro",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 3,
+ .gpiomask = 0x03000F,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 1, 0xd0001, 0, 0, 10},
+ /* sound path (5 sources):
+ MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable)
+ 0= ext. Audio IN
+ 1= from MUX2
+ 2= Mono TV sound from Tuner
+ 3= not connected
+ MUX2 (mask 0x30000):
+ 0,2,3= from MSP34xx
+ 1= FM stereo Radio from Tuner */
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TVIEW_RDS_FM] = {
+ /* Claas Langbehn <claas@bigfoot.com>,
+ Sven Grothklags <sven@upb.de> */
+ .name = "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
+ .video_inputs = 4,
+ .audio_inputs = 3,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1c,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0, 0x10, 8, 4 },
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_LIFETEC_9415] = {
+ /* Tim Röstermundt <rosterm@uni-muenster.de>
+ in de.comp.os.unix.linux.hardware:
+ options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
+ audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
+ options tuner type=5 */
+ .name = "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x18e0,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x0000,0x0800,0x1000,0x1000,0x18e0 },
+ /* For cards with tda9820/tda9821:
+ 0x0000: Tuner normal stereo
+ 0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
+ 0x0880: Tuner A2 stereo */
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_BESTBUY_EASYTV] = {
+ /* Miguel Angel Alvarez <maacruz@navegalia.com>
+ old Easy TV BT848 version (model CPH031) */
+ .name = "Askey CPH031/ BESTBUY Easy TV",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xF,
+ .muxsel = { 2, 3, 1, 0},
+ .audiomux = { 2, 0, 0, 0, 10},
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TEMIC_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x38 ---------------------------------- */
+ [BTTV_BOARD_FLYVIDEO_98FM] = {
+ /* Gordon Heydon <gjheydon@bigfoot.com ('98) */
+ .name = "Lifeview FlyVideo 98FM LR50",
+ .video_inputs = 4,
+ .audio_inputs = 3,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1800,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
+ .pll = PLL_28,
+ .tuner_type = 5,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ /* This is the ultimate cheapo capture card
+ * just a BT848A on a small PCB!
+ * Steve Hosgood <steve@equiinet.com> */
+ [BTTV_BOARD_GRANDTEC] = {
+ .name = "GrandTec 'Grand Video Capture' (Bt848)",
+ .video_inputs = 2,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 1,
+ .gpiomask = 0,
+ .muxsel = { 3, 1 },
+ .audiomux = { 0 },
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .pll = PLL_35,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ASKEY_CPH060] = {
+ /* Daniel Herrington <daniel.herrington@home.com> */
+ .name = "Askey CPH060/ Phoebe TV Master Only (No FM)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xe00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TEMIC_4036FY5_NTSC,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ASKEY_CPH03X] = {
+ /* Matti Mottus <mottus@physic.ut.ee> */
+ .name = "Askey CPH03x TV Capturer",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x03000F,
+ .muxsel = { 2, 3, 1, 0},
+ .audiomux = { 2,0,0,0,1 },
+ .pll = PLL_28,
+ .tuner_type = 0,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x3c ---------------------------------- */
+ [BTTV_BOARD_MM100PCTV] = {
+ /* Philip Blundell <philb@gnu.org> */
+ .name = "Modular Technology MM100PCTV",
+ .video_inputs = 2,
+ .audio_inputs = 2,
+ .tuner = 0,
+ .svhs = -1,
+ .gpiomask = 11,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 2, 0, 0, 1, 8},
+ .pll = PLL_35,
+ .tuner_type = TUNER_TEMIC_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_GMV1] = {
+ /* Adrian Cox <adrian@humboldt.co.uk */
+ .name = "AG Electronics GMV1",
+ .video_inputs = 2,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 1,
+ .gpiomask = 0xF,
+ .muxsel = { 2, 2},
+ .audiomux = { },
+ .no_msp34xx = 1,
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_BESTBUY_EASYTV2] = {
+ /* Miguel Angel Alvarez <maacruz@navegalia.com>
+ new Easy TV BT878 version (model CPH061)
+ special thanks to Informatica Mieres for providing the card */
+ .name = "Askey CPH061/ BESTBUY Easy TV (bt878)",
+ .video_inputs = 3,
+ .audio_inputs = 2,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xFF,
+ .muxsel = { 2, 3, 1, 0},
+ .audiomux = { 1, 0, 4, 4, 9},
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_ATI_TVWONDER] = {
+ /* Lukas Gebauer <geby@volny.cz> */
+ .name = "ATI TV-Wonder",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xf03f,
+ .muxsel = { 2, 3, 1, 0 },
+ .audiomux = { 0xbffe, 0, 0xbfff, 0, 0xbffe},
+ .pll = PLL_28,
+ .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x40 ---------------------------------- */
+ [BTTV_BOARD_ATI_TVWONDERVE] = {
+ /* Lukas Gebauer <geby@volny.cz> */
+ .name = "ATI TV-Wonder VE",
+ .video_inputs = 2,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = -1,
+ .gpiomask = 1,
+ .muxsel = { 2, 3, 0, 1},
+ .audiomux = { 0, 0, 1, 0, 0},
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TEMIC_4006FN5_MULTI_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_FLYVIDEO2000] = {
+ /* DeeJay <deejay@westel900.net (2000S) */
+ .name = "Lifeview FlyVideo 2000S LR90",
+ .video_inputs = 3,
+ .audio_inputs = 3,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x18e0,
+ .muxsel = { 2, 3, 0, 1},
+ /* Radio changed from 1e80 to 0x800 to make
+ FlyVideo2000S in .hu happy (gm)*/
+ /* -dk-???: set mute=0x1800 for tda9874h daughterboard */
+ .audiomux = { 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 },
+ .audio_hook = fv2000s_audio,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = 5,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TERRATVALUER] = {
+ .name = "Terratec TValueRadio",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0xffff00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x500, 0x500, 0x300, 0x900, 0x900},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_GVBCTV4PCI] = {
+ /* TANAKA Kei <peg00625@nifty.com> */
+ .name = "IODATA GV-BCTV4/PCI",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x010f00,
+ .muxsel = {2, 3, 0, 0},
+ .audiomux = {0x10000, 0, 0x10000, 0, 0, 0},
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_SHARP_2U5JF5540_NTSC,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = gvbctv3pci_audio,
+ },
+
+ /* ---- card 0x44 ---------------------------------- */
+ [BTTV_BOARD_VOODOOTV_FM] = {
+ .name = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
+ /* try "insmod msp3400 simple=0" if you have
+ * sound problems with this card. */
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = -1,
+ .gpiomask = 0x4f8a00,
+ /* 0x100000: 1=MSP enabled (0=disable again)
+ * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
+ .audiomux = {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff},
+ /* tvtuner, radio, external,internal, mute, stereo
+ * tuner, Composit, SVid, Composit-on-Svid-adapter */
+ .muxsel = { 2, 3 ,0 ,1},
+ .tuner_type = TUNER_MT2032,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_AIMMS] = {
+ /* Philip Blundell <pb@nexus.co.uk> */
+ .name = "Active Imaging AIMMS",
+ .video_inputs = 1,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .muxsel = { 2 },
+ .gpiomask = 0
+ },
+ [BTTV_BOARD_PV_BT878P_PLUS] = {
+ /* Tomasz Pyra <hellfire@sedez.iq.pl> */
+ .name = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)",
+ .video_inputs = 3,
+ .audio_inputs = 4,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 15,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0, 11, 7, 13, 0}, /* TV and Radio with same GPIO ! */
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = 25,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ /* GPIO wiring:
+ GPIO0: U4.A0 (hef4052bt)
+ GPIO1: U4.A1
+ GPIO2: U4.A1 (second hef4052bt)
+ GPIO3: U4.nEN, U5.A0, A5.nEN
+ GPIO8-15: vrd866b ?
+ */
+ },
+ [BTTV_BOARD_FLYVIDEO98EZ] = {
+ .name = "Lifeview FlyVideo 98EZ (capture only) LR51",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1, 1}, /* AV1, AV2, SVHS, CVid adapter on SVHS */
+ .pll = PLL_28,
+ .no_msp34xx = 1,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x48 ---------------------------------- */
+ [BTTV_BOARD_PV_BT878P_9B] = {
+ /* Dariusz Kowalewski <darekk@automex.pl> */
+ .name = "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x3f,
+ .muxsel = { 2, 3, 1, 1 },
+ .audiomux = { 0x01, 0x00, 0x03, 0x03, 0x09, 0x02 },
+ .needs_tvaudio = 1,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .pll = PLL_28,
+ .tuner_type = 5,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = pvbt878p9b_audio, /* Note: not all cards have stereo */
+ .has_radio = 1, /* Note: not all cards have radio */
+ .has_remote = 1,
+ /* GPIO wiring:
+ GPIO0: A0 hef4052
+ GPIO1: A1 hef4052
+ GPIO3: nEN hef4052
+ GPIO8-15: vrd866b
+ GPIO20,22,23: R30,R29,R28
+ */
+ },
+ [BTTV_BOARD_SENSORAY311] = {
+ /* Clay Kunz <ckunz@mail.arc.nasa.gov> */
+ /* you must jumper JP5 for the card to work */
+ .name = "Sensoray 311",
+ .video_inputs = 5,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 4,
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 0, 0},
+ .audiomux = { 0 },
+ .needs_tvaudio = 0,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_RV605] = {
+ /* Miguel Freitas <miguel@cetuc.puc-rio.br> */
+ .name = "RemoteVision MX (RV605)",
+ .video_inputs = 16,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .gpiomask = 0x00,
+ .gpiomask2 = 0x07ff,
+ .muxsel = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
+ 0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .muxsel_hook = rv605_muxsel,
+ },
+ [BTTV_BOARD_POWERCLR_MTV878] = {
+ .name = "Powercolor MTV878/ MTV878R/ MTV878F",
+ .video_inputs = 3,
+ .audio_inputs = 2,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x1C800F, /* Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset */
+ .muxsel = { 2, 1, 1, },
+ .audiomux = { 0, 1, 2, 2, 4 },
+ .needs_tvaudio = 0,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ },
+
+ /* ---- card 0x4c ---------------------------------- */
+ [BTTV_BOARD_WINDVR] = {
+ /* Masaki Suzuki <masaki@btree.org> */
+ .name = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x140007,
+ .muxsel = { 2, 3, 1, 1 },
+ .audiomux = { 0, 1, 2, 3, 4, 0 },
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = windvr_audio,
+ },
+ [BTTV_BOARD_GRANDTEC_MULTI] = {
+ .name = "GrandTec Multi Capture Card (Bt878)",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 0 },
+ .audiomux = { 0 },
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_KWORLD] = {
+ .name = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
+ .video_inputs = 4,
+ .audio_inputs = 3,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 7,
+ .muxsel = { 2, 3, 1, 1 }, /* Tuner, SVid, SVHS, SVid to SVHS connector */
+ .audiomux = { 0 ,0 ,4, 4,4,4},/* Yes, this tuner uses the same audio output for TV and FM radio!
+ * This card lacks external Audio In, so we mute it on Ext. & Int.
+ * The PCB can take a sbx1637/sbx1673, wiring unknown.
+ * This card lacks PCI subsystem ID, sigh.
+ * audiomux=1: lower volume, 2+3: mute
+ * btwincap uses 0x80000/0x80003
+ */
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = 5,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ /* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
+ radio signal strength indicators work fine. */
+ .has_radio = 1,
+ /* GPIO Info:
+ GPIO0,1: HEF4052 A0,A1
+ GPIO2: HEF4052 nENABLE
+ GPIO3-7: n.c.
+ GPIO8-13: IRDC357 data0-5 (data6 n.c. ?) [chip not present on my card]
+ GPIO14,15: ??
+ GPIO16-21: n.c.
+ GPIO22,23: ??
+ ?? : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/
+ },
+ [BTTV_BOARD_DSP_TCVIDEO] = {
+ /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
+ .name = "DSP Design TCVIDEO",
+ .video_inputs = 4,
+ .svhs = -1,
+ .muxsel = { 2, 3, 1, 0},
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x50 ---------------------------------- */
+ [BTTV_BOARD_HAUPPAUGEPVR] = {
+ .name = "Hauppauge WinTV PVR",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .muxsel = { 2, 0, 1, 1},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .gpiomask = 7,
+ .audiomux = {7},
+ },
+ [BTTV_BOARD_GVBCTV5PCI] = {
+ .name = "IODATA GV-BCTV5/PCI",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x0f0f80,
+ .muxsel = {2, 3, 1, 0},
+ .audiomux = {0x030000, 0x010000, 0, 0, 0x020000, 0},
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = gvbctv5pci_audio,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_OSPREY1x0] = {
+ .name = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
+ .video_inputs = 4, /* id-inputs-clock */
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 3,
+ .muxsel = { 3, 2, 0, 1 },
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+ [BTTV_BOARD_OSPREY1x0_848] = {
+ .name = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
+ .video_inputs = 3,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1 },
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+
+ /* ---- card 0x54 ---------------------------------- */
+ [BTTV_BOARD_OSPREY101_848] = {
+ .name = "Osprey 101 (848)", /* 0x05-40C0-C1 */
+ .video_inputs = 2,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 1,
+ .muxsel = { 3, 1 },
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+ [BTTV_BOARD_OSPREY1x1] = {
+ .name = "Osprey 101/151", /* 0x1(4|5)-0004-C4 */
+ .video_inputs = 1,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .muxsel = { 0 },
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+ [BTTV_BOARD_OSPREY1x1_SVID] = {
+ .name = "Osprey 101/151 w/ svid", /* 0x(16|17|20)-00C4-C1 */
+ .video_inputs = 2,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 1,
+ .muxsel = { 0, 1 },
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+ [BTTV_BOARD_OSPREY2xx] = {
+ .name = "Osprey 200/201/250/251", /* 0x1(8|9|E|F)-0004-C4 */
+ .video_inputs = 1,
+ .audio_inputs = 1,
+ .tuner = -1,
+ .svhs = -1,
+ .muxsel = { 0 },
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+
+ /* ---- card 0x58 ---------------------------------- */
+ [BTTV_BOARD_OSPREY2x0_SVID] = {
+ .name = "Osprey 200/250", /* 0x1(A|B)-00C4-C1 */
+ .video_inputs = 2,
+ .audio_inputs = 1,
+ .tuner = -1,
+ .svhs = 1,
+ .muxsel = { 0, 1 },
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+ [BTTV_BOARD_OSPREY2x0] = {
+ .name = "Osprey 210/220", /* 0x1(A|B)-04C0-C1 */
+ .video_inputs = 2,
+ .audio_inputs = 1,
+ .tuner = -1,
+ .svhs = 1,
+ .muxsel = { 2, 3 },
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+ [BTTV_BOARD_OSPREY500] = {
+ .name = "Osprey 500", /* 500 */
+ .video_inputs = 2,
+ .audio_inputs = 1,
+ .tuner = -1,
+ .svhs = 1,
+ .muxsel = { 2, 3 },
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+ [BTTV_BOARD_OSPREY540] = {
+ .name = "Osprey 540", /* 540 */
+ .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,
+ .radio_addr = ADDR_UNSET,
+ .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 ---------------------------------- */
+ [BTTV_BOARD_OSPREY2000] = {
+ .name = "Osprey 2000", /* 2000 */
+ .video_inputs = 2,
+ .audio_inputs = 1,
+ .tuner = -1,
+ .svhs = 1,
+ .muxsel = { 2, 3 },
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1, /* must avoid, conflicts with the bt860 */
+ },
+ [BTTV_BOARD_IDS_EAGLE] = {
+ /* M G Berberich <berberic@forwiss.uni-passau.de> */
+ .name = "IDS Eagle",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .svhs = -1,
+ .gpiomask = 0,
+ .muxsel = { 0, 1, 2, 3 },
+ .muxsel_hook = eagle_muxsel,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .pll = PLL_28,
+ },
+ [BTTV_BOARD_PINNACLESAT] = {
+ .name = "Pinnacle PCTV Sat",
+ .video_inputs = 2,
+ .audio_inputs = 0,
+ .svhs = 1,
+ .tuner = -1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .muxsel = { 3, 0, 1, 2},
+ .pll = PLL_28,
+ .no_gpioirq = 1,
+ .has_dvb = 1,
+ },
+ [BTTV_BOARD_FORMAC_PROTV] = {
+ .name = "Formac ProTV II (bt878)",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 3,
+ .gpiomask = 2,
+ /* TV, Comp1, Composite over SVID con, SVID */
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 2, 2, 0, 0, 0 },
+ .pll = PLL_28,
+ .has_radio = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ /* sound routing:
+ GPIO=0x00,0x01,0x03: mute (?)
+ 0x02: both TV and radio (tuner: FM1216/I)
+ The card has onboard audio connectors labeled "cdrom" and "board",
+ not soldered here, though unknown wiring.
+ Card lacks: external audio in, pci subsystem id.
*/
- .name = "Kodicom 4400R (slave)",
- .video_inputs = 16,
- .audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .svhs = -1,
- .gpiomask = 0x010000,
- .no_gpioirq = 1,
- .muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
- .pll = PLL_28,
- .no_msp34xx = 1,
- .no_tda7432 = 1,
- .no_tda9875 = 1,
- .muxsel_hook = kodicom4400r_muxsel,
-},
-{
- /* ---- card 0x86---------------------------------- */
- /* Michael Henson <mhenson@clarityvi.com> */
- /* Adlink RTV24 with special unlock codes */
- .name = "Adlink RTV24",
- .video_inputs = 4,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .muxsel = { 2, 3, 1, 0},
- .tuner_type = -1,
- .tuner_addr = ADDR_UNSET,
- .pll = PLL_28,
-},
-{
- /* ---- card 0x87---------------------------------- */
- /* Michael Krufky <mkrufky@m1k.net> */
- .name = "DViCO FusionHDTV 5 Lite",
- .tuner = 0,
- .tuner_type = TUNER_LG_TDVS_H062F,
- .tuner_addr = ADDR_UNSET,
- .video_inputs = 3,
- .audio_inputs = 1,
- .svhs = 2,
- .muxsel = { 2, 3, 1 },
- .gpiomask = 0x00e00007,
- .audiomux = { 0x00400005, 0, 0x00000001, 0, 0x00c00007, 0 },
- .no_msp34xx = 1,
- .no_tda9875 = 1,
- .no_tda7432 = 1,
-},{
- /* ---- card 0x88---------------------------------- */
- /* Mauro Carvalho Chehab <mchehab@brturbo.com.br> */
- .name = "Acorp Y878F",
- .video_inputs = 3,
- .audio_inputs = 1,
- .tuner = 0,
- .svhs = 2,
- .gpiomask = 0x01fe00,
- .muxsel = { 2, 3, 1, 1},
- .audiomux = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
- .needs_tvaudio = 1,
- .pll = PLL_28,
- .tuner_type = TUNER_YMEC_TVF66T5_B_DFF,
- .tuner_addr = 0xc1 >>1,
- .has_radio = 1,
-}};
+ },
+
+ /* ---- card 0x60 ---------------------------------- */
+ [BTTV_BOARD_MACHTV] = {
+ .name = "MachTV",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = -1,
+ .gpiomask = 7,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 1, 2, 3, 4},
+ .needs_tvaudio = 1,
+ .tuner_type = 5,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ },
+ [BTTV_BOARD_EURESYS_PICOLO] = {
+ .name = "Euresys Picolo",
+ .video_inputs = 3,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = 2,
+ .gpiomask = 0,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .muxsel = { 2, 0, 1},
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_PV150] = {
+ /* Luc Van Hoeylandt <luc@e-magic.be> */
+ .name = "ProVideo PV150", /* 0x4f */
+ .video_inputs = 2,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .gpiomask = 0,
+ .muxsel = { 2, 3 },
+ .audiomux = { 0 },
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_AD_TVK503] = {
+ /* Hiroshi Takekawa <sian@big.or.jp> */
+ /* This card lacks subsystem ID */
+ .name = "AD-TVK503", /* 0x63 */
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x001e8007,
+ .muxsel = { 2, 3, 1, 0 },
+ /* Tuner, Radio, external, internal, off, on */
+ .audiomux = { 0x08, 0x0f, 0x0a, 0x08, 0x0f, 0x08 },
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = 2,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .audio_hook = adtvk503_audio,
+ },
+
+ /* ---- card 0x64 ---------------------------------- */
+ [BTTV_BOARD_HERCULES_SM_TV] = {
+ .name = "Hercules Smart TV Stereo",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x00,
+ .muxsel = { 2, 3, 1, 1 },
+ .needs_tvaudio = 1,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = 5,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ /* Notes:
+ - card lacks subsystem ID
+ - stereo variant w/ daughter board with tda9874a @0xb0
+ - Audio Routing:
+ always from tda9874 independent of GPIO (?)
+ external line in: unknown
+ - Other chips: em78p156elp @ 0x96 (probably IR remote control)
+ hef4053 (instead 4052) for unknown function
+ */
+ },
+ [BTTV_BOARD_PACETV] = {
+ .name = "Pace TV & Radio Card",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1, 1}, /* Tuner, CVid, SVid, CVid over SVid connector */
+ .gpiomask = 0,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .tuner_type = 1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ .pll = PLL_28,
+ /* Bt878, Bt832, FI1246 tuner; no pci subsystem id
+ only internal line out: (4pin header) RGGL
+ Radio must be decoded by msp3410d (not routed through)*/
+ /*
+ .digital_mode = DIGITAL_MODE_CAMERA, todo!
+ */
+ },
+ [BTTV_BOARD_IVC200] = {
+ /* Chris Willing <chris@vislab.usyd.edu.au> */
+ .name = "IVC-200",
+ .video_inputs = 1,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .svhs = -1,
+ .gpiomask = 0xdf,
+ .muxsel = { 2 },
+ .pll = PLL_28,
+ },
+ [BTTV_BOARD_XGUARD] = {
+ .name = "Grand X-Guard / Trust 814PCI",
+ .video_inputs = 16,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .tuner_type = 4,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask2 = 0xff,
+ .muxsel = { 2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0 },
+ .muxsel_hook = xguard_muxsel,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .pll = PLL_28,
+ },
+
+ /* ---- card 0x68 ---------------------------------- */
+ [BTTV_BOARD_NEBULA_DIGITV] = {
+ .name = "Nebula Electronics DigiTV",
+ .video_inputs = 1,
+ .tuner = -1,
+ .svhs = -1,
+ .muxsel = { 2, 3, 1, 0},
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_dvb = 1,
+ .no_gpioirq = 1,
+ },
+ [BTTV_BOARD_PV143] = {
+ /* Jorge Boncompte - DTI2 <jorge@dti2.net> */
+ .name = "ProVideo PV143",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .gpiomask = 0,
+ .muxsel = { 2, 3, 1, 0 },
+ .audiomux = { 0 },
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_VD009X1_MINIDIN] = {
+ /* M.Klahr@phytec.de */
+ .name = "PHYTEC VD-009-X1 MiniDIN (bt878)",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1, /* card has no tuner */
+ .svhs = 3,
+ .gpiomask = 0x00,
+ .muxsel = { 2, 3, 1, 0},
+ .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_VD009X1_COMBI] = {
+ .name = "PHYTEC VD-009-X1 Combi (bt878)",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1, /* card has no tuner */
+ .svhs = 3,
+ .gpiomask = 0x00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+ /* ---- card 0x6c ---------------------------------- */
+ [BTTV_BOARD_VD009_MINIDIN] = {
+ .name = "PHYTEC VD-009 MiniDIN (bt878)",
+ .video_inputs = 10,
+ .audio_inputs = 0,
+ .tuner = -1, /* card has no tuner */
+ .svhs = 9,
+ .gpiomask = 0x00,
+ .gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
+ via the upper nibble of muxsel. here: used for
+ xternal video-mux */
+ .muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x00 },
+ .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_VD009_COMBI] = {
+ .name = "PHYTEC VD-009 Combi (bt878)",
+ .video_inputs = 10,
+ .audio_inputs = 0,
+ .tuner = -1, /* card has no tuner */
+ .svhs = 9,
+ .gpiomask = 0x00,
+ .gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
+ via the upper nibble of muxsel. here: used for
+ xternal video-mux */
+ .muxsel = { 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 0x01, 0x01 },
+ .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_IVC100] = {
+ .name = "IVC-100",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .svhs = -1,
+ .gpiomask = 0xdf,
+ .muxsel = { 2, 3, 1, 0 },
+ .pll = PLL_28,
+ },
+ [BTTV_BOARD_IVC120] = {
+ /* IVC-120G - Alan Garfield <alan@fromorbit.com> */
+ .name = "IVC-120G",
+ .video_inputs = 16,
+ .audio_inputs = 0, /* card has no audio */
+ .tuner = -1, /* card has no tuner */
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .svhs = -1, /* card has no svhs */
+ .needs_tvaudio = 0,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .gpiomask = 0x00,
+ .muxsel = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
+ .muxsel_hook = ivc120_muxsel,
+ .pll = PLL_28,
+ },
+
+ /* ---- card 0x70 ---------------------------------- */
+ [BTTV_BOARD_PC_HDTV] = {
+ .name = "pcHDTV HD-2000 TV",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1, 0},
+ .tuner_type = TUNER_PHILIPS_ATSC,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_dvb = 1,
+ },
+ [BTTV_BOARD_TWINHAN_DST] = {
+ .name = "Twinhan DST + clones",
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_video = 1,
+ .has_dvb = 1,
+ },
+ [BTTV_BOARD_WINFASTVC100] = {
+ .name = "Winfast VC100",
+ .video_inputs = 3,
+ .audio_inputs = 0,
+ .svhs = 1,
+ .tuner = -1,
+ .muxsel = { 3, 1, 1, 3}, /* Vid In, SVid In, Vid over SVid in connector */
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ },
+ [BTTV_BOARD_TEV560] = {
+ .name = "Teppro TEV-560/InterVision IV-560",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 3,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 1, 1, 1, 1, 0},
+ .needs_tvaudio = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_35,
+ },
+
+ /* ---- card 0x74 ---------------------------------- */
+ [BTTV_BOARD_SIMUS_GVC1100] = {
+ .name = "SIMUS GVC1100",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .muxsel = { 2, 2, 2, 2},
+ .gpiomask = 0x3F,
+ .muxsel_hook = gvc1100_muxsel,
+ },
+ [BTTV_BOARD_NGSTV_PLUS] = {
+ /* Carlos Silva r3pek@r3pek.homelinux.org || card 0x75 */
+ .name = "NGS NGSTV+",
+ .video_inputs = 3,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x008007,
+ .muxsel = {2, 3, 0, 0},
+ .audiomux = {0, 0, 0, 0, 0x000003, 0},
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_LMLBT4] = {
+ /* http://linuxmedialabs.com */
+ .name = "LMLBT4",
+ .video_inputs = 4, /* IN1,IN2,IN3,IN4 */
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .muxsel = { 2, 3, 1, 0 },
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .needs_tvaudio = 0,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_TEKRAM_M205] = {
+ /* Helmroos Harri <harri.helmroos@pp.inet.fi> */
+ .name = "Tekram M205 PRO",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .svhs = 2,
+ .needs_tvaudio = 0,
+ .gpiomask = 0x68,
+ .muxsel = { 2, 3, 1},
+ .audiomux = { 0x68, 0x68, 0x61, 0x61, 0x00 },
+ .pll = PLL_28,
+ },
+
+ /* ---- card 0x78 ---------------------------------- */
+ [BTTV_BOARD_CONTVFMI] = {
+ /* Javier Cendan Ares <jcendan@lycos.es> */
+ /* bt878 TV + FM without subsystem ID */
+ .name = "Conceptronic CONTVFMi",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x008007,
+ .muxsel = { 2, 3, 1, 1 },
+ .audiomux = { 0, 1, 2, 2, 3 },
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_PICOLO_TETRA_CHIP] = {
+ /*Eric DEBIEF <debief@telemsa.com>*/
+ /*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controled*/
+ /* adds picolo_tetra_muxsel(), picolo_tetra_init(), the folowing declaration strucure, and #define BTTV_BOARD_PICOLO_TETRA_CHIP*/
+ /*0x79 in bttv.h*/
+ .name = "Euresys Picolo Tetra",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .gpiomask = 0,
+ .gpiomask2 = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .muxsel = {2,2,2,2},/*878A input is always MUX0, see above.*/
+ .audiomux = { 0, 0, 0, 0, 0, 0 }, /* card has no audio */
+ .pll = PLL_28,
+ .needs_tvaudio = 0,
+ .muxsel_hook = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_SPIRIT_TV] = {
+ /* Spirit TV Tuner from http://spiritmodems.com.au */
+ /* Stafford Goodsell <surge@goliath.homeunix.org> */
+ .name = "Spirit TV Tuner",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x0000000f,
+ .muxsel = { 2, 1, 1 },
+ .audiomux = { 0x02, 0x00, 0x00, 0x00, 0x00},
+ .tuner_type = TUNER_TEMIC_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ },
+ [BTTV_BOARD_AVDVBT_771] = {
+ /* Wolfram Joost <wojo@frokaschwei.de> */
+ .name = "AVerMedia AVerTV DVB-T 771",
+ .video_inputs = 2,
+ .svhs = 1,
+ .tuner = -1,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .muxsel = { 3 , 3 },
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .pll = PLL_28,
+ .has_dvb = 1,
+ .no_gpioirq = 1,
+ .has_remote = 1,
+ },
+ /* ---- card 0x7c ---------------------------------- */
+ [BTTV_BOARD_AVDVBT_761] = {
+ /* Matt Jesson <dvb@jesson.eclipse.co.uk> */
+ /* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */
+ .name = "AverMedia AverTV DVB-T 761",
+ .video_inputs = 2,
+ .tuner = -1,
+ .svhs = 1,
+ .muxsel = { 3, 1, 2, 0}, /* Comp0, S-Video, ?, ? */
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_dvb = 1,
+ .no_gpioirq = 1,
+ .has_remote = 1,
+ },
+ [BTTV_BOARD_MATRIX_VISIONSQ] = {
+ /* andre.schwarz@matrix-vision.de */
+ .name = "MATRIX Vision Sigma-SQ",
+ .video_inputs = 16,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .gpiomask = 0x0,
+ .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3 },
+ .muxsel_hook = sigmaSQ_muxsel,
+ .audiomux = { 0 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_MATRIX_VISIONSLC] = {
+ /* andre.schwarz@matrix-vision.de */
+ .name = "MATRIX Vision Sigma-SLC",
+ .video_inputs = 4,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .gpiomask = 0x0,
+ .muxsel = { 2, 2, 2, 2 },
+ .muxsel_hook = sigmaSLC_muxsel,
+ .audiomux = { 0 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ /* BTTV_BOARD_APAC_VIEWCOMP */
+ [BTTV_BOARD_APAC_VIEWCOMP] = {
+ /* Attila Kondoros <attila.kondoros@chello.hu> */
+ /* bt878 TV + FM 0x00000000 subsystem ID */
+ .name = "APAC Viewcomp 878(AMAX)",
+ .video_inputs = 2,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = -1,
+ .gpiomask = 0xFF,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 2, 0, 0, 0, 10},
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1, /* miniremote works, see ir-kbd-gpio.c */
+ .has_radio = 1, /* not every card has radio */
+ },
+
+ /* ---- card 0x80 ---------------------------------- */
+ [BTTV_BOARD_DVICO_DVBT_LITE] = {
+ /* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
+ .name = "DViCO FusionHDTV DVB-T Lite",
+ .tuner = -1,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .pll = PLL_28,
+ .no_video = 1,
+ .has_dvb = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_VGEAR_MYVCD] = {
+ /* Steven <photon38@pchome.com.tw> */
+ .name = "V-Gear MyVCD",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x3f,
+ .muxsel = {2, 3, 1, 0},
+ .audiomux = {0x31, 0x31, 0x31, 0x31, 0x31, 0x31},
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .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> */
+ .name = "Super TV Tuner",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1, 0},
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x008007,
+ .audiomux = { 0, 0x000001,0,0, 0},
+ .needs_tvaudio = 1,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_TIBET_CS16] = {
+ /* Chris Fanning <video4linux@haydon.net> */
+ .name = "Tibet Systems 'Progress DVR' CS16",
+ .video_inputs = 16,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .svhs = -1,
+ .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+ .pll = PLL_28,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .muxsel_hook = tibetCS16_muxsel,
+ },
+ [BTTV_BOARD_KODICOM_4400R] = {
+ /* Bill Brack <wbrack@mmm.com.hk> */
+ /*
+ * Note that, because of the card's wiring, the "master"
+ * BT878A chip (i.e. the one which controls the analog switch
+ * and must use this card type) is the 2nd one detected. The
+ * other 3 chips should use card type 0x85, whose description
+ * follows this one. There is a EEPROM on the card (which is
+ * connected to the I2C of one of those other chips), but is
+ * not currently handled. There is also a facility for a
+ * "monitor", which is also not currently implemented.
+ */
+ .name = "Kodicom 4400R (master)",
+ .video_inputs = 16,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .svhs = -1,
+ /* GPIO bits 0-9 used for analog switch:
+ * 00 - 03: camera selector
+ * 04 - 06: channel (controller) selector
+ * 07: data (1->on, 0->off)
+ * 08: strobe
+ * 09: reset
+ * bit 16 is input from sync separator for the channel
+ */
+ .gpiomask = 0x0003ff,
+ .no_gpioirq = 1,
+ .muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+ .pll = PLL_28,
+ .no_msp34xx = 1,
+ .no_tda7432 = 1,
+ .no_tda9875 = 1,
+ .muxsel_hook = kodicom4400r_muxsel,
+ },
+ [BTTV_BOARD_KODICOM_4400R_SL] = {
+ /* Bill Brack <wbrack@mmm.com.hk> */
+ /* Note that, for reasons unknown, the "master" BT878A chip (i.e. the
+ * one which controls the analog switch, and must use the card type)
+ * is the 2nd one detected. The other 3 chips should use this card
+ * type
+ */
+ .name = "Kodicom 4400R (slave)",
+ .video_inputs = 16,
+ .audio_inputs = 0,
+ .tuner = -1,
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .svhs = -1,
+ .gpiomask = 0x010000,
+ .no_gpioirq = 1,
+ .muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+ .pll = PLL_28,
+ .no_msp34xx = 1,
+ .no_tda7432 = 1,
+ .no_tda9875 = 1,
+ .muxsel_hook = kodicom4400r_muxsel,
+ },
+ /* ---- card 0x86---------------------------------- */
+ [BTTV_BOARD_ADLINK_RTV24] = {
+ /* Michael Henson <mhenson@clarityvi.com> */
+ /* Adlink RTV24 with special unlock codes */
+ .name = "Adlink RTV24",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1, 0},
+ .tuner_type = -1,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ },
+ /* ---- card 0x87---------------------------------- */
+ [BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE] = {
+ /* Michael Krufky <mkrufky@m1k.net> */
+ .name = "DViCO FusionHDTV 5 Lite",
+ .tuner = 0,
+ .tuner_type = TUNER_LG_TDVS_H062F,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1 },
+ .gpiomask = 0x00e00007,
+ .audiomux = { 0x00400005, 0, 0x00000001, 0, 0x00c00007, 0 },
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .has_dvb = 1,
+ },
+ /* ---- card 0x88---------------------------------- */
+ [BTTV_BOARD_ACORP_Y878F] = {
+ /* Mauro Carvalho Chehab <mchehab@brturbo.com.br> */
+ .name = "Acorp Y878F",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x01fe00,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_YMEC_TVF66T5_B_DFF,
+ .tuner_addr = 0xc1 >>1,
+ .radio_addr = 0xc1 >>1,
+ .has_radio = 1,
+ },
+ /* ---- card 0x89 ---------------------------------- */
+ [BTTV_BOARD_CONCEPTRONIC_CTVFMI2] = {
+ .name = "Conceptronic CTVFMi v2",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x001c0007,
+ .muxsel = { 2, 3, 1, 1 },
+ .audiomux = { 0, 1, 2, 2, 3 },
+ .needs_tvaudio = 0,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TENA_9533_DI,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ .has_radio = 1,
+ },
+ /* ---- card 0x8a ---------------------------------- */
+ [BTTV_BOARD_PV_BT878P_2E] = {
+ .name = "Prolink Pixelview PV-BT878P+ (Rev.2E)",
+ .video_inputs = 5,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 3,
+ .gpiomask = 0x01fe00,
+ .muxsel = { 2,3,1,1,-1 },
+ .digital_mode = DIGITAL_MODE_CAMERA,
+ .audiomux = { 0x00400, 0x10400, 0x04400, 0x80000, 0x12400, 0x46000 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_LG_PAL_FM,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_remote = 1,
+ },
+ /* ---- card 0x8b ---------------------------------- */
+ [BTTV_BOARD_PV_M4900] = {
+ /* Sérgio Fortier <sergiofortier@yahoo.com.br> */
+ .name = "Prolink PixelView PlayTV MPEG2 PV-M4900",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x3f,
+ .muxsel = { 2, 3, 1, 1 },
+ .audiomux = { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_YMEC_TVF_5533MF,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .has_radio = 1,
+ .has_remote = 1,
+ },
+ /* ---- card 0x8c ---------------------------------- */
+ [BTTV_BOARD_OSPREY440] = {
+ .name = "Osprey 440",
+ .video_inputs = 1,
+ .audio_inputs = 1,
+ .tuner = -1,
+ .svhs = 1,
+ .muxsel = { 2 },
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
+ /* ---- card 0x8d ---------------------------------- */
+ [BTTV_BOARD_ASOUND_SKYEYE] = {
+ .name = "Asound Skyeye PCTV",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 15,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = {2,0,0,0,1},
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = 2,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+
+};
static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -2461,7 +2840,7 @@ void __devinit bttv_idcard(struct bttv *btv)
btv->c.nr, btv->cardid & 0xffff,
(btv->cardid >> 16) & 0xffff);
printk(KERN_DEBUG "please mail id, board name and "
- "the correct card= insmod option to kraxel@bytesex.org\n");
+ "the correct card= insmod option to video4linux-list@redhat.com\n");
}
}
@@ -2510,11 +2889,11 @@ void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256])
int type = -1;
if (0 == strncmp(eeprom_data,"GET MM20xPCTV",13))
- type = BTTV_MODTEC_205;
+ type = BTTV_BOARD_MODTEC_205;
else if (0 == strncmp(eeprom_data+20,"Picolo",7))
- type = BTTV_EURESYS_PICOLO;
+ type = BTTV_BOARD_EURESYS_PICOLO;
else if (eeprom_data[0] == 0x84 && eeprom_data[2]== 0)
- type = BTTV_HAUPPAUGE; /* old bt848 */
+ type = BTTV_BOARD_HAUPPAUGE; /* old bt848 */
if (-1 != type) {
btv->c.type = type;
@@ -2548,7 +2927,7 @@ static void flyvideo_gpio(struct bttv *btv)
switch(ttype) {
case 0x0: tuner=2; /* NTSC, e.g. TPI8NSR11P */
break;
- case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */
+ case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */
break;
case 0x4: tuner=5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */
break;
@@ -2564,7 +2943,7 @@ static void flyvideo_gpio(struct bttv *btv)
has_radio = gpio & 0x400000;
/* unknown 0x200000;
* unknown2 0x100000; */
- is_capture_only = !(gpio & 0x008000); /* GPIO15 */
+ is_capture_only = !(gpio & 0x008000); /* GPIO15 */
has_tda9820_tda9821 = !(gpio & 0x004000);
is_lr90 = !(gpio & 0x002000); /* else LR26/LR50 (LR38/LR51 f. capture only) */
/*
@@ -2601,7 +2980,7 @@ static void miro_pinnacle_gpio(struct bttv *btv)
char *info;
gpio_inout(0xffffff, 0);
- gpio = gpio_read();
+ gpio = gpio_read();
id = ((gpio>>10) & 63) -1;
msp = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
if (id < 32) {
@@ -2620,10 +2999,10 @@ static void miro_pinnacle_gpio(struct bttv *btv)
btv->has_radio = 0;
}
if (-1 != msp) {
- if (btv->c.type == BTTV_MIRO)
- btv->c.type = BTTV_MIROPRO;
- if (btv->c.type == BTTV_PINNACLE)
- btv->c.type = BTTV_PINNACLEPRO;
+ if (btv->c.type == BTTV_BOARD_MIRO)
+ btv->c.type = BTTV_BOARD_MIROPRO;
+ if (btv->c.type == BTTV_BOARD_PINNACLE)
+ btv->c.type = BTTV_BOARD_PINNACLEPRO;
}
printk(KERN_INFO
"bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
@@ -2664,7 +3043,7 @@ static void miro_pinnacle_gpio(struct bttv *btv)
break;
}
if (-1 != msp)
- btv->c.type = BTTV_PINNACLEPRO;
+ btv->c.type = BTTV_BOARD_PINNACLEPRO;
printk(KERN_INFO
"bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n",
btv->c.nr, id, info, btv->has_radio ? "yes" : "no");
@@ -2712,7 +3091,7 @@ static void eagle_muxsel(struct bttv *btv, unsigned int input)
static void gvc1100_muxsel(struct bttv *btv, unsigned int input)
{
- static const int masks[] = {0x30, 0x01, 0x12, 0x23};
+ static const int masks[] = {0x30, 0x01, 0x12, 0x23};
gpio_write(masks[input%4]);
}
@@ -2778,26 +3157,27 @@ static void bttv_reset_audio(struct bttv *btv)
void __devinit bttv_init_card1(struct bttv *btv)
{
switch (btv->c.type) {
- case BTTV_HAUPPAUGE:
- case BTTV_HAUPPAUGE878:
- boot_msp34xx(btv,5);
+ case BTTV_BOARD_HAUPPAUGE:
+ case BTTV_BOARD_HAUPPAUGE878:
+ boot_msp34xx(btv,5);
break;
- case BTTV_VOODOOTV_FM:
- boot_msp34xx(btv,20);
+ case BTTV_BOARD_VOODOOTV_FM:
+ boot_msp34xx(btv,20);
break;
- case BTTV_AVERMEDIA98:
+ case BTTV_BOARD_AVERMEDIA98:
boot_msp34xx(btv,11);
break;
- case BTTV_HAUPPAUGEPVR:
+ case BTTV_BOARD_HAUPPAUGEPVR:
pvr_boot(btv);
break;
- case BTTV_TWINHAN_DST:
- case BTTV_AVDVBT_771:
+ case BTTV_BOARD_TWINHAN_DST:
+ case BTTV_BOARD_AVDVBT_771:
+ case BTTV_BOARD_PINNACLESAT:
btv->use_i2c_hw = 1;
break;
- case BTTV_ADLINK_RTV24:
- init_RTV24( btv );
- break;
+ case BTTV_BOARD_ADLINK_RTV24:
+ init_RTV24( btv );
+ break;
}
if (!bttv_tvcards[btv->c.type].has_dvb)
@@ -2810,53 +3190,53 @@ void __devinit bttv_init_card2(struct bttv *btv)
int tda9887;
int addr=ADDR_UNSET;
- btv->tuner_type = -1;
+ btv->tuner_type = -1;
- if (BTTV_UNKNOWN == btv->c.type) {
+ if (BTTV_BOARD_UNKNOWN == btv->c.type) {
bttv_readee(btv,eeprom_data,0xa0);
identify_by_eeprom(btv,eeprom_data);
}
switch (btv->c.type) {
- case BTTV_MIRO:
- case BTTV_MIROPRO:
- case BTTV_PINNACLE:
- case BTTV_PINNACLEPRO:
+ case BTTV_BOARD_MIRO:
+ case BTTV_BOARD_MIROPRO:
+ case BTTV_BOARD_PINNACLE:
+ case BTTV_BOARD_PINNACLEPRO:
/* miro/pinnacle */
miro_pinnacle_gpio(btv);
break;
- case BTTV_FLYVIDEO_98:
- case BTTV_MAXI:
- case BTTV_LIFE_FLYKIT:
- case BTTV_FLYVIDEO:
- case BTTV_TYPHOON_TVIEW:
- case BTTV_CHRONOS_VS2:
- case BTTV_FLYVIDEO_98FM:
- case BTTV_FLYVIDEO2000:
- case BTTV_FLYVIDEO98EZ:
- case BTTV_CONFERENCETV:
- case BTTV_LIFETEC_9415:
+ case BTTV_BOARD_FLYVIDEO_98:
+ case BTTV_BOARD_MAXI:
+ case BTTV_BOARD_LIFE_FLYKIT:
+ case BTTV_BOARD_FLYVIDEO:
+ case BTTV_BOARD_TYPHOON_TVIEW:
+ case BTTV_BOARD_CHRONOS_VS2:
+ case BTTV_BOARD_FLYVIDEO_98FM:
+ case BTTV_BOARD_FLYVIDEO2000:
+ case BTTV_BOARD_FLYVIDEO98EZ:
+ case BTTV_BOARD_CONFERENCETV:
+ case BTTV_BOARD_LIFETEC_9415:
flyvideo_gpio(btv);
break;
- case BTTV_HAUPPAUGE:
- case BTTV_HAUPPAUGE878:
- case BTTV_HAUPPAUGEPVR:
+ case BTTV_BOARD_HAUPPAUGE:
+ case BTTV_BOARD_HAUPPAUGE878:
+ case BTTV_BOARD_HAUPPAUGEPVR:
/* pick up some config infos from the eeprom */
bttv_readee(btv,eeprom_data,0xa0);
- hauppauge_eeprom(btv);
+ hauppauge_eeprom(btv);
break;
- case BTTV_AVERMEDIA98:
- case BTTV_AVPHONE98:
+ case BTTV_BOARD_AVERMEDIA98:
+ case BTTV_BOARD_AVPHONE98:
bttv_readee(btv,eeprom_data,0xa0);
avermedia_eeprom(btv);
break;
- case BTTV_PXC200:
+ case BTTV_BOARD_PXC200:
init_PXC200(btv);
break;
- case BTTV_PICOLO_TETRA_CHIP:
+ case BTTV_BOARD_PICOLO_TETRA_CHIP:
picolo_tetra_init(btv);
break;
- case BTTV_VHX:
+ case BTTV_BOARD_VHX:
btv->has_radio = 1;
btv->has_matchbox = 1;
btv->mbox_we = 0x20;
@@ -2865,58 +3245,58 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->mbox_data = 0x10;
btv->mbox_mask = 0x38;
break;
- case BTTV_VOBIS_BOOSTAR:
- case BTTV_TERRATV:
+ case BTTV_BOARD_VOBIS_BOOSTAR:
+ case BTTV_BOARD_TERRATV:
terratec_active_radio_upgrade(btv);
break;
- case BTTV_MAGICTVIEW061:
+ case BTTV_BOARD_MAGICTVIEW061:
if (btv->cardid == 0x3002144f) {
btv->has_radio=1;
printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr);
}
break;
- case BTTV_STB2:
- if (btv->cardid == 0x3060121a) {
+ case BTTV_BOARD_STB2:
+ if (btv->cardid == 0x3060121a) {
/* Fix up entry for 3DFX VoodooTV 100,
which is an OEM STB card variant. */
btv->has_radio=0;
btv->tuner_type=TUNER_TEMIC_NTSC;
}
break;
- case BTTV_OSPREY1x0:
- case BTTV_OSPREY1x0_848:
- case BTTV_OSPREY101_848:
- case BTTV_OSPREY1x1:
- case BTTV_OSPREY1x1_SVID:
- case BTTV_OSPREY2xx:
- case BTTV_OSPREY2x0_SVID:
- case BTTV_OSPREY2x0:
- case BTTV_OSPREY500:
- case BTTV_OSPREY540:
- case BTTV_OSPREY2000:
+ case BTTV_BOARD_OSPREY1x0:
+ case BTTV_BOARD_OSPREY1x0_848:
+ case BTTV_BOARD_OSPREY101_848:
+ case BTTV_BOARD_OSPREY1x1:
+ case BTTV_BOARD_OSPREY1x1_SVID:
+ case BTTV_BOARD_OSPREY2xx:
+ case BTTV_BOARD_OSPREY2x0_SVID:
+ case BTTV_BOARD_OSPREY2x0:
+ case BTTV_BOARD_OSPREY500:
+ case BTTV_BOARD_OSPREY540:
+ case BTTV_BOARD_OSPREY2000:
bttv_readee(btv,eeprom_data,0xa0);
- osprey_eeprom(btv);
+ osprey_eeprom(btv);
break;
- case BTTV_IDS_EAGLE:
+ case BTTV_BOARD_IDS_EAGLE:
init_ids_eagle(btv);
break;
- case BTTV_MODTEC_205:
+ case BTTV_BOARD_MODTEC_205:
bttv_readee(btv,eeprom_data,0xa0);
modtec_eeprom(btv);
break;
- case BTTV_LMLBT4:
+ case BTTV_BOARD_LMLBT4:
init_lmlbt4x(btv);
break;
- case BTTV_TIBET_CS16:
+ case BTTV_BOARD_TIBET_CS16:
tibetCS16_init(btv);
break;
- case BTTV_KODICOM_4400R:
+ case BTTV_BOARD_KODICOM_4400R:
kodicom4400r_init(btv);
break;
}
/* pll configuration */
- if (!(btv->id==848 && btv->revision==0x11)) {
+ if (!(btv->id==848 && btv->revision==0x11)) {
/* defaults from card list */
if (PLL_28 == bttv_tvcards[btv->c.type].pll) {
btv->pll.pll_ifreq=28636363;
@@ -2927,26 +3307,26 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->pll.pll_crystal=BT848_IFORM_XT1;
}
/* insmod options can override */
- switch (pll[btv->c.nr]) {
- case 0: /* none */
+ switch (pll[btv->c.nr]) {
+ case 0: /* none */
btv->pll.pll_crystal = 0;
btv->pll.pll_ifreq = 0;
btv->pll.pll_ofreq = 0;
- break;
- case 1: /* 28 MHz */
+ break;
+ case 1: /* 28 MHz */
case 28:
- btv->pll.pll_ifreq = 28636363;
+ btv->pll.pll_ifreq = 28636363;
btv->pll.pll_ofreq = 0;
- btv->pll.pll_crystal = BT848_IFORM_XT0;
- break;
- case 2: /* 35 MHz */
+ btv->pll.pll_crystal = BT848_IFORM_XT0;
+ break;
+ case 2: /* 35 MHz */
case 35:
- btv->pll.pll_ifreq = 35468950;
+ btv->pll.pll_ifreq = 35468950;
btv->pll.pll_ofreq = 0;
- btv->pll.pll_crystal = BT848_IFORM_XT1;
- break;
- }
- }
+ btv->pll.pll_crystal = BT848_IFORM_XT1;
+ break;
+ }
+ }
btv->pll.pll_current = -1;
/* tuner configuration (from card list / autodetect / insmod option) */
@@ -2955,23 +3335,26 @@ void __devinit bttv_init_card2(struct bttv *btv)
if (UNSET != bttv_tvcards[btv->c.type].tuner_type)
if(UNSET == btv->tuner_type)
- btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
+ btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
if (UNSET != tuner[btv->c.nr])
btv->tuner_type = tuner[btv->c.nr];
printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type);
- if (btv->pinnacle_id != UNSET)
- bttv_call_i2c_clients(btv, AUDC_CONFIG_PINNACLE,
- &btv->pinnacle_id);
+
if (btv->tuner_type != UNSET) {
- struct tuner_setup tun_setup;
+ struct tuner_setup tun_setup;
- tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+ tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
tun_setup.type = btv->tuner_type;
tun_setup.addr = addr;
bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
}
+ if (btv->pinnacle_id != UNSET) {
+ bttv_call_i2c_clients(btv, AUDC_CONFIG_PINNACLE,
+ &btv->pinnacle_id);
+ }
+
btv->svhs = bttv_tvcards[btv->c.type].svhs;
if (svhs[btv->c.nr] != UNSET)
btv->svhs = svhs[btv->c.nr];
@@ -2982,8 +3365,8 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->has_radio=1;
if (bttv_tvcards[btv->c.type].has_remote)
btv->has_remote=1;
- if (bttv_tvcards[btv->c.type].no_gpioirq)
- btv->gpioirq=0;
+ if (!bttv_tvcards[btv->c.type].no_gpioirq)
+ btv->gpioirq=1;
if (bttv_tvcards[btv->c.type].audio_hook)
btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
@@ -3024,6 +3407,9 @@ void __devinit bttv_init_card2(struct bttv *btv)
if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb &&
bttv_I2CRead(btv, I2C_TDA9887, "TDA9887") >=0)
tda9887 = 1;
+ /* Hybrid DVB card, DOES have a tda9887 */
+ if (btv->c.type == BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE)
+ tda9887 = 1;
if((btv->tuner_type == TUNER_PHILIPS_FM1216ME_MK3) ||
(btv->tuner_type == TUNER_PHILIPS_FM1236_MK3) ||
(btv->tuner_type == TUNER_PHILIPS_FM1256_IH3) ||
@@ -3045,11 +3431,11 @@ static void modtec_eeprom(struct bttv *btv)
} else if (strncmp(&(eeprom_data[0x1e]),"Alps TSBB5",10) ==0) {
btv->tuner_type=TUNER_ALPS_TSBB5_PAL_I;
printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
- btv->c.nr,&eeprom_data[0x1e]);
- } else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) {
- btv->tuner_type=TUNER_PHILIPS_NTSC;
- printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
- btv->c.nr,&eeprom_data[0x1e]);
+ btv->c.nr,&eeprom_data[0x1e]);
+ } else if (strncmp(&(eeprom_data[0x1e]),"Philips FM1246",14) ==0) {
+ btv->tuner_type=TUNER_PHILIPS_NTSC;
+ printk("bttv%d: Modtec: Tuner autodetected by eeprom: %s\n",
+ btv->c.nr,&eeprom_data[0x1e]);
} else {
printk("bttv%d: Modtec: Unknown TunerString: %s\n",
btv->c.nr,&eeprom_data[0x1e]);
@@ -3114,7 +3500,7 @@ static int terratec_active_radio_upgrade(struct bttv *btv)
static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen)
{
u32 n;
- u8 bits;
+ u8 bits;
int i;
gpio_inout(0xffffff,BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG);
@@ -3150,19 +3536,19 @@ static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen)
static int __devinit pvr_boot(struct bttv *btv)
{
- const struct firmware *fw_entry;
+ const struct firmware *fw_entry;
int rc;
rc = request_firmware(&fw_entry, "hcwamc.rbf", &btv->c.pci->dev);
if (rc != 0) {
printk(KERN_WARNING "bttv%d: no altera firmware [via hotplug]\n",
btv->c.nr);
- return rc;
- }
+ return rc;
+ }
rc = pvr_altera_load(btv, fw_entry->data, fw_entry->size);
printk(KERN_INFO "bttv%d: altera firmware upload %s\n",
btv->c.nr, (rc < 0) ? "failed" : "ok");
- release_firmware(fw_entry);
+ release_firmware(fw_entry);
return rc;
}
@@ -3176,33 +3562,33 @@ static void __devinit osprey_eeprom(struct bttv *btv)
unsigned long serial = 0;
if (btv->c.type == 0) {
- /* this might be an antique... check for MMAC label in eeprom */
- if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) {
- unsigned char checksum = 0;
- for (i =0; i<21; i++)
+ /* this might be an antique... check for MMAC label in eeprom */
+ if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) {
+ unsigned char checksum = 0;
+ for (i =0; i<21; i++)
checksum += ee[i];
- if (checksum != ee[21])
+ if (checksum != ee[21])
return;
- btv->c.type = BTTV_OSPREY1x0_848;
+ btv->c.type = BTTV_BOARD_OSPREY1x0_848;
for (i = 12; i < 21; i++)
serial *= 10, serial += ee[i] - '0';
- }
+ }
} else {
unsigned short type;
- int offset = 4*16;
-
- for(; offset < 8*16; offset += 16) {
- unsigned short checksum = 0;
- /* verify the checksum */
- for(i = 0; i<14; i++) checksum += ee[i+offset];
- checksum = ~checksum; /* no idea why */
- if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
- ((checksum & 0x0FF) == ee[offset+15])) {
- break;
- }
- }
-
- if (offset >= 8*16)
+ int offset = 4*16;
+
+ for(; offset < 8*16; offset += 16) {
+ unsigned short checksum = 0;
+ /* verify the checksum */
+ for(i = 0; i<14; i++) checksum += ee[i+offset];
+ checksum = ~checksum; /* no idea why */
+ if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
+ ((checksum & 0x0FF) == ee[offset+15])) {
+ break;
+ }
+ }
+
+ if (offset >= 8*16)
return;
/* found a valid descriptor */
@@ -3212,47 +3598,47 @@ static void __devinit osprey_eeprom(struct bttv *btv)
/* 848 based */
case 0x0004:
- btv->c.type = BTTV_OSPREY1x0_848;
+ btv->c.type = BTTV_BOARD_OSPREY1x0_848;
break;
case 0x0005:
- btv->c.type = BTTV_OSPREY101_848;
+ btv->c.type = BTTV_BOARD_OSPREY101_848;
break;
- /* 878 based */
+ /* 878 based */
case 0x0012:
case 0x0013:
- btv->c.type = BTTV_OSPREY1x0;
+ btv->c.type = BTTV_BOARD_OSPREY1x0;
break;
case 0x0014:
case 0x0015:
- btv->c.type = BTTV_OSPREY1x1;
+ btv->c.type = BTTV_BOARD_OSPREY1x1;
break;
case 0x0016:
case 0x0017:
case 0x0020:
- btv->c.type = BTTV_OSPREY1x1_SVID;
+ btv->c.type = BTTV_BOARD_OSPREY1x1_SVID;
break;
case 0x0018:
case 0x0019:
case 0x001E:
case 0x001F:
- btv->c.type = BTTV_OSPREY2xx;
+ btv->c.type = BTTV_BOARD_OSPREY2xx;
break;
case 0x001A:
case 0x001B:
- btv->c.type = BTTV_OSPREY2x0_SVID;
+ btv->c.type = BTTV_BOARD_OSPREY2x0_SVID;
break;
case 0x0040:
- btv->c.type = BTTV_OSPREY500;
+ btv->c.type = BTTV_BOARD_OSPREY500;
break;
case 0x0050:
case 0x0056:
- btv->c.type = BTTV_OSPREY540;
+ btv->c.type = BTTV_BOARD_OSPREY540;
/* bttv_osprey_540_init(btv); */
break;
case 0x0060:
case 0x0070:
- btv->c.type = BTTV_OSPREY2x0;
+ btv->c.type = BTTV_BOARD_OSPREY2x0;
/* enable output on select control lines */
gpio_inout(0xffffff,0x000303);
break;
@@ -3274,27 +3660,27 @@ static void __devinit osprey_eeprom(struct bttv *btv)
/* AVermedia specific stuff, from bktr_card.c */
static int tuner_0_table[] = {
- TUNER_PHILIPS_NTSC, TUNER_PHILIPS_PAL /* PAL-BG*/,
- TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL /* PAL-I*/,
- TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL,
- TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM,
- TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL,
+ TUNER_PHILIPS_NTSC, TUNER_PHILIPS_PAL /* PAL-BG*/,
+ TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL /* PAL-I*/,
+ TUNER_PHILIPS_PAL, TUNER_PHILIPS_PAL,
+ TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM,
+ TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL,
TUNER_PHILIPS_FM1216ME_MK3 };
static int tuner_1_table[] = {
- TUNER_TEMIC_NTSC, TUNER_TEMIC_PAL,
+ TUNER_TEMIC_NTSC, TUNER_TEMIC_PAL,
TUNER_TEMIC_PAL, TUNER_TEMIC_PAL,
TUNER_TEMIC_PAL, TUNER_TEMIC_PAL,
- TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */
- TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL};
+ TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */
+ TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL};
static void __devinit avermedia_eeprom(struct bttv *btv)
{
- int tuner_make,tuner_tv_fm,tuner_format,tuner=0;
+ int tuner_make,tuner_tv_fm,tuner_format,tuner=0;
tuner_make = (eeprom_data[0x41] & 0x7);
- tuner_tv_fm = (eeprom_data[0x41] & 0x18) >> 3;
- tuner_format = (eeprom_data[0x42] & 0xf0) >> 4;
+ tuner_tv_fm = (eeprom_data[0x41] & 0x18) >> 3;
+ tuner_format = (eeprom_data[0x42] & 0xf0) >> 4;
btv->has_remote = (eeprom_data[0x42] & 0x01);
if (tuner_make == 0 || tuner_make == 2)
@@ -3325,13 +3711,13 @@ void bttv_tda9880_setnorm(struct bttv *btv, int norm)
{
/* fix up our card entry */
if(norm==VIDEO_MODE_NTSC) {
- bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[0]=0x957fff;
- bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[4]=0x957fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[0]=0x957fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[4]=0x957fff;
dprintk("bttv_tda9880_setnorm to NTSC\n");
}
else {
- bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[0]=0x947fff;
- bttv_tvcards[BTTV_VOODOOTV_FM].audiomux[4]=0x947fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[0]=0x947fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].audiomux[4]=0x947fff;
dprintk("bttv_tda9880_setnorm to PAL\n");
}
/* set GPIO according */
@@ -3342,7 +3728,7 @@ void bttv_tda9880_setnorm(struct bttv *btv, int norm)
/*
* reset/enable the MSP on some Hauppauge cards
- * Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)!
+ * Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)!
*
* Hauppauge: pin 5
* Voodoo: pin 20
@@ -3353,7 +3739,7 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin)
gpio_inout(mask,mask);
gpio_bits(mask,0);
- udelay(2500);
+ udelay(2500);
gpio_bits(mask,mask);
if (bttv_gpio)
@@ -3429,7 +3815,7 @@ static void __devinit init_PXC200(struct bttv *btv)
udelay(10);
gpio_write(1<<2);
- for (i = 0; i < ARRAY_SIZE(vals); i++) {
+ for (i = 0; i < ARRAY_SIZE(vals); i++) {
tmp=bttv_I2CWrite(btv,0x1E,0,vals[i],1);
if (tmp != -1) {
printk(KERN_INFO
@@ -3872,30 +4258,30 @@ avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set)
static void
lt9415_audio(struct bttv *btv, struct video_audio *v, int set)
{
- int val = 0;
+ int val = 0;
- if (gpio_read() & 0x4000) {
+ if (gpio_read() & 0x4000) {
v->mode = VIDEO_SOUND_MONO;
return;
}
- if (set) {
- if (v->mode & VIDEO_SOUND_LANG2) /* A2 SAP */
- val = 0x0080;
+ if (set) {
+ if (v->mode & VIDEO_SOUND_LANG2) /* A2 SAP */
+ val = 0x0080;
if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */
- val = 0x0880;
- if ((v->mode & VIDEO_SOUND_LANG1) ||
+ val = 0x0880;
+ if ((v->mode & VIDEO_SOUND_LANG1) ||
(v->mode & VIDEO_SOUND_MONO))
val = 0;
gpio_bits(0x0880, val);
- if (bttv_gpio)
- bttv_gpio_tracking(btv,"lt9415");
- } else {
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"lt9415");
+ } else {
/* autodetect doesn't work with this card :-( */
- v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+ v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
- return;
- }
+ return;
+ }
}
/* TDA9821 on TerraTV+ Bt848, Bt878 */
@@ -4018,26 +4404,26 @@ fv2000s_audio(struct bttv *btv, struct video_audio *v, int set)
static void
windvr_audio(struct bttv *btv, struct video_audio *v, int set)
{
- unsigned long val = 0;
-
- if (set) {
- if (v->mode & VIDEO_SOUND_MONO)
- val = 0x040000;
- if (v->mode & VIDEO_SOUND_LANG1)
- val = 0;
- if (v->mode & VIDEO_SOUND_LANG2)
- val = 0x100000;
- if (v->mode & VIDEO_SOUND_STEREO)
- val = 0;
- if (val) {
+ unsigned long val = 0;
+
+ if (set) {
+ if (v->mode & VIDEO_SOUND_MONO)
+ val = 0x040000;
+ if (v->mode & VIDEO_SOUND_LANG1)
+ val = 0;
+ if (v->mode & VIDEO_SOUND_LANG2)
+ val = 0x100000;
+ if (v->mode & VIDEO_SOUND_STEREO)
+ val = 0;
+ if (val) {
gpio_bits(0x140000, val);
- if (bttv_gpio)
- bttv_gpio_tracking(btv,"windvr");
- }
- } else {
- v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
- VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
- }
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"windvr");
+ }
+ } else {
+ v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+ VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+ }
}
/*
@@ -4280,10 +4666,10 @@ static void kodicom4400r_init(struct bttv *btv)
static void xguard_muxsel(struct bttv *btv, unsigned int input)
{
static const int masks[] = {
- ENB0, ENB0|IN00, ENB0|IN10, ENB0|IN00|IN10,
- ENA0, ENA0|IN00, ENA0|IN10, ENA0|IN00|IN10,
- ENB1, ENB1|IN01, ENB1|IN11, ENB1|IN01|IN11,
- ENA1, ENA1|IN01, ENA1|IN11, ENA1|IN01|IN11,
+ ENB0, ENB0|IN00, ENB0|IN10, ENB0|IN00|IN10,
+ ENA0, ENA0|IN00, ENA0|IN10, ENA0|IN00|IN10,
+ ENB1, ENB1|IN01, ENB1|IN11, ENB1|IN01|IN11,
+ ENA1, ENA1|IN01, ENA1|IN11, ENA1|IN01|IN11,
};
gpio_write(masks[input%16]);
}
@@ -4388,10 +4774,10 @@ static void ivc120_muxsel(struct bttv *btv, unsigned int input)
static void PXC200_muxsel(struct bttv *btv, unsigned int input)
{
- int rc;
+ int rc;
long mux;
int bitmask;
- unsigned char buf[2];
+ unsigned char buf[2];
/* Read PIC config to determine if this is a PXC200F */
/* PX_I2C_CMD_CFG*/
@@ -4421,14 +4807,14 @@ static void PXC200_muxsel(struct bttv *btv, unsigned int input)
/* bitmask=0x30f; */
bitmask=0x302;
/* check whether we have a PXC200A */
- if (btv->cardid == PX_PXC200A_CARDID) {
+ if (btv->cardid == PX_PXC200A_CARDID) {
bitmask ^= 0x180; /* use 7 and 9, not 8 and 9 */
bitmask |= 7<<4; /* the DAC */
}
btwrite(bitmask, BT848_GPIO_OUT_EN);
bitmask = btread(BT848_GPIO_DATA);
- if (btv->cardid == PX_PXC200A_CARDID)
+ if (btv->cardid == PX_PXC200A_CARDID)
bitmask = (bitmask & ~0x280) | ((mux & 2) << 8) | ((mux & 1) << 7);
else /* older device */
bitmask = (bitmask & ~0x300) | ((mux & 3) << 8);
@@ -4441,7 +4827,7 @@ static void PXC200_muxsel(struct bttv *btv, unsigned int input)
*
* needed because bttv-driver sets mux before calling this function
*/
- if (btv->cardid == PX_PXC200A_CARDID)
+ if (btv->cardid == PX_PXC200A_CARDID)
btaor(2<<5, ~BT848_IFORM_MUXSEL, BT848_IFORM);
else /* older device */
btand(~BT848_IFORM_MUXSEL,BT848_IFORM);
@@ -4485,10 +4871,9 @@ void __devinit bttv_check_chipset(void)
}
if (UNSET != latency)
printk(KERN_INFO "bttv: pci latency fixup [%d]\n",latency);
-
- while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+ while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82441, dev))) {
- unsigned char b;
+ unsigned char b;
pci_read_config_byte(dev, 0x53, &b);
if (bttv_debug)
printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, "
@@ -4498,7 +4883,7 @@ void __devinit bttv_check_chipset(void)
int __devinit bttv_handle_chipset(struct bttv *btv)
{
- unsigned char command;
+ unsigned char command;
if (!triton1 && !vsfx && UNSET == latency)
return 0;
@@ -4519,13 +4904,13 @@ int __devinit bttv_handle_chipset(struct bttv *btv)
btv->triton1 = BT848_INT_ETBF;
} else {
/* bt878 has a bit in the pci config space for it */
- pci_read_config_byte(btv->c.pci, BT878_DEVCTRL, &command);
+ pci_read_config_byte(btv->c.pci, BT878_DEVCTRL, &command);
if (triton1)
command |= BT878_EN_TBFX;
if (vsfx)
command |= BT878_EN_VSFX;
- pci_write_config_byte(btv->c.pci, BT878_DEVCTRL, command);
- }
+ pci_write_config_byte(btv->c.pci, BT878_DEVCTRL, command);
+ }
if (UNSET != latency)
pci_write_config_byte(btv->c.pci, PCI_LATENCY_TIMER, latency);
return 0;
diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c
index d538a994ff0..0005741d551 100644
--- a/drivers/media/video/bttv-driver.c
+++ b/drivers/media/video/bttv-driver.c
@@ -3,7 +3,7 @@
bttv - Bt848 frame grabber driver
Copyright (C) 1996,97,98 Ralph Metzler <rjkm@thp.uni-koeln.de>
- & Marcus Metzler <mocm@thp.uni-koeln.de>
+ & Marcus Metzler <mocm@thp.uni-koeln.de>
(c) 1999-2002 Gerd Knorr <kraxel@bytesex.org>
some v4l2 code lines are taken from Justin's bttv2 driver which is
@@ -192,8 +192,8 @@ static u8 SRAM_Table[][60] =
const struct bttv_tvnorm bttv_tvnorms[] = {
/* PAL-BDGHI */
- /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
- /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
+ /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
+ /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
{
.v4l2_id = V4L2_STD_PAL,
.name = "PAL",
@@ -806,9 +806,9 @@ static void bt848A_set_timing(struct bttv *btv)
btv->c.nr,table_idx);
/* timing change...reset timing generator address */
- btwrite(0x00, BT848_TGCTRL);
- btwrite(0x02, BT848_TGCTRL);
- btwrite(0x00, BT848_TGCTRL);
+ btwrite(0x00, BT848_TGCTRL);
+ btwrite(0x02, BT848_TGCTRL);
+ btwrite(0x00, BT848_TGCTRL);
len=SRAM_Table[table_idx][0];
for(i = 1; i <= len; i++)
@@ -847,7 +847,7 @@ static void bt848_hue(struct bttv *btv, int hue)
/* -128 to 127 */
value = (hue >> 8) - 128;
- btwrite(value & 0xff, BT848_HUE);
+ btwrite(value & 0xff, BT848_HUE);
}
static void bt848_contrast(struct bttv *btv, int cont)
@@ -859,9 +859,9 @@ static void bt848_contrast(struct bttv *btv, int cont)
/* 0-511 */
value = (cont >> 7);
hibit = (value >> 6) & 4;
- btwrite(value & 0xff, BT848_CONTRAST_LO);
- btaor(hibit, ~4, BT848_E_CONTROL);
- btaor(hibit, ~4, BT848_O_CONTROL);
+ btwrite(value & 0xff, BT848_CONTRAST_LO);
+ btaor(hibit, ~4, BT848_E_CONTROL);
+ btaor(hibit, ~4, BT848_O_CONTROL);
}
static void bt848_sat(struct bttv *btv, int color)
@@ -873,12 +873,12 @@ static void bt848_sat(struct bttv *btv, int color)
/* 0-511 for the color */
val_u = ((color * btv->opt_uv_ratio) / 50) >> 7;
val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
- hibits = (val_u >> 7) & 2;
+ hibits = (val_u >> 7) & 2;
hibits |= (val_v >> 8) & 1;
- btwrite(val_u & 0xff, BT848_SAT_U_LO);
- btwrite(val_v & 0xff, BT848_SAT_V_LO);
- btaor(hibits, ~3, BT848_E_CONTROL);
- btaor(hibits, ~3, BT848_O_CONTROL);
+ btwrite(val_u & 0xff, BT848_SAT_U_LO);
+ btwrite(val_v & 0xff, BT848_SAT_V_LO);
+ btaor(hibits, ~3, BT848_E_CONTROL);
+ btaor(hibits, ~3, BT848_O_CONTROL);
}
/* ----------------------------------------------------------------------- */
@@ -891,7 +891,7 @@ video_mux(struct bttv *btv, unsigned int input)
if (input >= bttv_tvcards[btv->c.type].video_inputs)
return -EINVAL;
- /* needed by RemoteVideo MX */
+ /* needed by RemoteVideo MX */
mask2 = bttv_tvcards[btv->c.type].gpiomask2;
if (mask2)
gpio_inout(mask2,mask2);
@@ -964,7 +964,7 @@ i2c_vidiocschan(struct bttv *btv)
c.norm = btv->tvnorm;
c.channel = btv->input;
bttv_call_i2c_clients(btv,VIDIOCSCHAN,&c);
- if (btv->c.type == BTTV_VOODOOTV_FM)
+ if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
bttv_tda9880_setnorm(btv,c.norm);
}
@@ -988,7 +988,7 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
bt848A_set_timing(btv);
switch (btv->c.type) {
- case BTTV_VOODOOTV_FM:
+ case BTTV_BOARD_VOODOOTV_FM:
bttv_tda9880_setnorm(btv,norm);
break;
}
@@ -1055,22 +1055,22 @@ static void init_bt848(struct bttv *btv)
btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
- /* set planar and packed mode trigger points and */
- /* set rising edge of inverted GPINTR pin as irq trigger */
- btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
- BT848_GPIO_DMA_CTL_PLTP1_16|
- BT848_GPIO_DMA_CTL_PLTP23_16|
- BT848_GPIO_DMA_CTL_GPINTC|
- BT848_GPIO_DMA_CTL_GPINTI,
- BT848_GPIO_DMA_CTL);
+ /* set planar and packed mode trigger points and */
+ /* set rising edge of inverted GPINTR pin as irq trigger */
+ btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
+ BT848_GPIO_DMA_CTL_PLTP1_16|
+ BT848_GPIO_DMA_CTL_PLTP23_16|
+ BT848_GPIO_DMA_CTL_GPINTC|
+ BT848_GPIO_DMA_CTL_GPINTI,
+ BT848_GPIO_DMA_CTL);
val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
- btwrite(val, BT848_E_SCLOOP);
- btwrite(val, BT848_O_SCLOOP);
+ btwrite(val, BT848_E_SCLOOP);
+ btwrite(val, BT848_O_SCLOOP);
- btwrite(0x20, BT848_E_VSCALE_HI);
- btwrite(0x20, BT848_O_VSCALE_HI);
- btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
+ btwrite(0x20, BT848_E_VSCALE_HI);
+ btwrite(0x20, BT848_O_VSCALE_HI);
+ btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
BT848_ADC);
btwrite(whitecrush_upper, BT848_WC_UP);
@@ -1089,7 +1089,7 @@ static void init_bt848(struct bttv *btv)
bt848_contrast(btv, btv->contrast);
bt848_sat(btv, btv->saturation);
- /* interrupt */
+ /* interrupt */
init_irqreg(btv);
}
@@ -1105,7 +1105,7 @@ static void bttv_reinit_bt848(struct bttv *btv)
spin_unlock_irqrestore(&btv->s_lock,flags);
init_bt848(btv);
- btv->pll.pll_current = -1;
+ btv->pll.pll_current = -1;
set_input(btv,btv->input);
}
@@ -1398,7 +1398,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
/* video4linux (1) interface */
static int bttv_prepare_buffer(struct bttv *btv, struct bttv_buffer *buf,
- const struct bttv_format *fmt,
+ const struct bttv_format *fmt,
unsigned int width, unsigned int height,
enum v4l2_field field)
{
@@ -1521,8 +1521,8 @@ static const char *v4l1_ioctls[] = {
static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
{
switch (cmd) {
- case BTTV_VERSION:
- return BTTV_VERSION_CODE;
+ case BTTV_VERSION:
+ return BTTV_VERSION_CODE;
/* *** v4l1 *** ************************************************ */
case VIDIOCGFREQ:
@@ -1576,32 +1576,32 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
return 0;
}
- case VIDIOCGCHAN:
- {
- struct video_channel *v = arg;
+ case VIDIOCGCHAN:
+ {
+ struct video_channel *v = arg;
unsigned int channel = v->channel;
- if (channel >= bttv_tvcards[btv->c.type].video_inputs)
- return -EINVAL;
- v->tuners=0;
- v->flags = VIDEO_VC_AUDIO;
- v->type = VIDEO_TYPE_CAMERA;
- v->norm = btv->tvnorm;
+ if (channel >= bttv_tvcards[btv->c.type].video_inputs)
+ return -EINVAL;
+ v->tuners=0;
+ v->flags = VIDEO_VC_AUDIO;
+ v->type = VIDEO_TYPE_CAMERA;
+ v->norm = btv->tvnorm;
if (channel == bttv_tvcards[btv->c.type].tuner) {
- strcpy(v->name,"Television");
- v->flags|=VIDEO_VC_TUNER;
- v->type=VIDEO_TYPE_TV;
- v->tuners=1;
- } else if (channel == btv->svhs) {
- strcpy(v->name,"S-Video");
- } else {
- sprintf(v->name,"Composite%d",channel);
+ strcpy(v->name,"Television");
+ v->flags|=VIDEO_VC_TUNER;
+ v->type=VIDEO_TYPE_TV;
+ v->tuners=1;
+ } else if (channel == btv->svhs) {
+ strcpy(v->name,"S-Video");
+ } else {
+ sprintf(v->name,"Composite%d",channel);
}
return 0;
- }
- case VIDIOCSCHAN:
- {
- struct video_channel *v = arg;
+ }
+ case VIDIOCSCHAN:
+ {
+ struct video_channel *v = arg;
unsigned int channel = v->channel;
if (channel >= bttv_tvcards[btv->c.type].video_inputs)
@@ -1623,7 +1623,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
return 0;
}
- case VIDIOCGAUDIO:
+ case VIDIOCGAUDIO:
{
struct video_audio *v = arg;
@@ -1728,7 +1728,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
} else if (i->index == btv->svhs) {
sprintf(i->name, "S-Video");
} else {
- sprintf(i->name,"Composite%d",i->index);
+ sprintf(i->name,"Composite%d",i->index);
}
if (i->index == btv->input) {
__u32 dstatus = btread(BT848_DSTATUS);
@@ -1851,6 +1851,11 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
up(&btv->lock);
return 0;
}
+ case VIDIOC_LOG_STATUS:
+ {
+ bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, 0);
+ return 0;
+ }
default:
return -ENOIOCTLCMD;
@@ -2163,7 +2168,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
if (0 != retval)
return retval;
if (locked_btres(fh->btv, RESOURCE_VBI))
- return -EBUSY;
+ return -EBUSY;
bttv_vbi_try_fmt(fh,f);
bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
bttv_vbi_get_fmt(fh,f);
@@ -2201,9 +2206,9 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
bttv_reinit_bt848(btv);
switch (cmd) {
- case VIDIOCSFREQ:
- case VIDIOCSTUNER:
- case VIDIOCSCHAN:
+ case VIDIOCSFREQ:
+ case VIDIOCSTUNER:
+ case VIDIOCSCHAN:
case VIDIOC_S_CTRL:
case VIDIOC_S_STD:
case VIDIOC_S_INPUT:
@@ -2219,10 +2224,10 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
/* *** v4l1 *** ************************************************ */
case VIDIOCGCAP:
{
- struct video_capability *cap = arg;
+ struct video_capability *cap = arg;
memset(cap,0,sizeof(*cap));
- strcpy(cap->name,btv->video_dev->name);
+ strcpy(cap->name,btv->video_dev->name);
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
/* vbi */
cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
@@ -2242,7 +2247,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
}
cap->channels = bttv_tvcards[btv->c.type].video_inputs;
cap->audios = bttv_tvcards[btv->c.type].audio_inputs;
- return 0;
+ return 0;
}
case VIDIOCGPICT:
@@ -2291,7 +2296,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
bt848_hue(btv,pic->hue);
bt848_sat(btv,pic->colour);
up(&fh->cap.lock);
- return 0;
+ return 0;
}
case VIDIOCGWIN:
@@ -2352,8 +2357,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
unsigned long end;
if(!capable(CAP_SYS_ADMIN) &&
- !capable(CAP_SYS_RAWIO))
- return -EPERM;
+ !capable(CAP_SYS_RAWIO))
+ return -EPERM;
end = (unsigned long)fbuf->base +
fbuf->height * fbuf->bytesperline;
down(&fh->cap.lock);
@@ -2427,7 +2432,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
}
/* switch over */
- retval = bttv_switch_overlay(btv,fh,new);
+ retval = bttv_switch_overlay(btv,fh,new);
up(&fh->cap.lock);
return retval;
}
@@ -2566,13 +2571,13 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
- case BTTV_VERSION:
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- case VIDIOCGTUNER:
- case VIDIOCSTUNER:
- case VIDIOCGCHAN:
- case VIDIOCSCHAN:
+ case BTTV_VERSION:
+ case VIDIOCGFREQ:
+ case VIDIOCSFREQ:
+ case VIDIOCGTUNER:
+ case VIDIOCSTUNER:
+ case VIDIOCGCHAN:
+ case VIDIOCSCHAN:
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
return bttv_common_ioctls(btv,cmd,arg);
@@ -2584,8 +2589,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (0 == v4l2)
return -EINVAL;
- strcpy(cap->driver,"bttv");
- strlcpy(cap->card,btv->video_dev->name,sizeof(cap->card));
+ strcpy(cap->driver,"bttv");
+ strlcpy(cap->card,btv->video_dev->name,sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s",pci_name(btv->c.pci));
cap->version = BTTV_VERSION_CODE;
cap->capabilities =
@@ -2856,6 +2861,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_S_TUNER:
case VIDIOC_G_FREQUENCY:
case VIDIOC_S_FREQUENCY:
+ case VIDIOC_LOG_STATUS:
return bttv_common_ioctls(btv,cmd,arg);
default:
@@ -3091,7 +3097,7 @@ static struct video_device bttv_video_template =
{
.name = "UNSET",
.type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
- VID_TYPE_CLIPPING|VID_TYPE_SCALES,
+ VID_TYPE_CLIPPING|VID_TYPE_SCALES,
.hardware = VID_HARDWARE_BT848,
.fops = &bttv_fops,
.minor = -1,
@@ -3137,7 +3143,7 @@ static int radio_open(struct inode *inode, struct file *file)
audio_mux(btv,AUDIO_RADIO);
up(&btv->lock);
- return 0;
+ return 0;
}
static int radio_release(struct inode *inode, struct file *file)
@@ -3160,34 +3166,34 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case VIDIOCGCAP:
{
- struct video_capability *cap = arg;
+ struct video_capability *cap = arg;
memset(cap,0,sizeof(*cap));
- strcpy(cap->name,btv->radio_dev->name);
- cap->type = VID_TYPE_TUNER;
+ strcpy(cap->name,btv->radio_dev->name);
+ cap->type = VID_TYPE_TUNER;
cap->channels = 1;
cap->audios = 1;
- return 0;
+ return 0;
}
- case VIDIOCGTUNER:
- {
- struct video_tuner *v = arg;
+ case VIDIOCGTUNER:
+ {
+ struct video_tuner *v = arg;
- if(v->tuner)
- return -EINVAL;
+ if(v->tuner)
+ return -EINVAL;
memset(v,0,sizeof(*v));
- strcpy(v->name, "Radio");
- bttv_call_i2c_clients(btv,cmd,v);
- return 0;
- }
- case VIDIOCSTUNER:
+ strcpy(v->name, "Radio");
+ bttv_call_i2c_clients(btv,cmd,v);
+ return 0;
+ }
+ case VIDIOCSTUNER:
/* nothing to do */
return 0;
case BTTV_VERSION:
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
+ case VIDIOCGFREQ:
+ case VIDIOCSFREQ:
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
return bttv_common_ioctls(btv,cmd,arg);
@@ -3693,7 +3699,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
}
if (astat&BT848_INT_VSYNC)
- btv->field_count++;
+ btv->field_count++;
if (astat & BT848_INT_GPINT) {
wake_up(&btv->gpioq);
@@ -3705,13 +3711,13 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
wake_up(&btv->i2c_queue);
}
- if ((astat & BT848_INT_RISCI) && (stat & (4<<28)))
+ if ((astat & BT848_INT_RISCI) && (stat & (4<<28)))
bttv_irq_switch_vbi(btv);
- if ((astat & BT848_INT_RISCI) && (stat & (2<<28)))
+ if ((astat & BT848_INT_RISCI) && (stat & (2<<28)))
bttv_irq_wakeup_top(btv);
- if ((astat & BT848_INT_RISCI) && (stat & (1<<28)))
+ if ((astat & BT848_INT_RISCI) && (stat & (1<<28)))
bttv_irq_switch_video(btv);
if ((astat & BT848_INT_HLOCK) && btv->opt_automute)
@@ -3736,10 +3742,22 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
count++;
if (count > 4) {
- btwrite(0, BT848_INT_MASK);
- printk(KERN_ERR
- "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
+
+ if (count > 8 || !(astat & BT848_INT_GPINT)) {
+ btwrite(0, BT848_INT_MASK);
+
+ printk(KERN_ERR
+ "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
+ } else {
+ printk(KERN_ERR
+ "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);
+
+ btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
+ BT848_INT_MASK);
+ };
+
bttv_print_irqbits(stat,astat);
+
printk("]\n");
}
}
@@ -3808,7 +3826,7 @@ static int __devinit bttv_register_video(struct bttv *btv)
/* video */
btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
- if (NULL == btv->video_dev)
+ if (NULL == btv->video_dev)
goto err;
if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
goto err;
@@ -3818,18 +3836,18 @@ static int __devinit bttv_register_video(struct bttv *btv)
/* vbi */
btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
- if (NULL == btv->vbi_dev)
+ if (NULL == btv->vbi_dev)
goto err;
- if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
+ if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
goto err;
printk(KERN_INFO "bttv%d: registered device vbi%d\n",
btv->c.nr,btv->vbi_dev->minor & 0x1f);
- if (!btv->has_radio)
+ if (!btv->has_radio)
return 0;
/* radio */
btv->radio_dev = vdev_init(btv, &radio_template, "radio");
- if (NULL == btv->radio_dev)
+ if (NULL == btv->radio_dev)
goto err;
if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
goto err;
@@ -3850,11 +3868,11 @@ static int __devinit bttv_register_video(struct bttv *btv)
static void pci_set_command(struct pci_dev *dev)
{
#if defined(__powerpc__)
- unsigned int cmd;
+ unsigned int cmd;
- pci_read_config_dword(dev, PCI_COMMAND, &cmd);
- cmd = (cmd | PCI_COMMAND_MEMORY );
- pci_write_config_dword(dev, PCI_COMMAND, cmd);
+ pci_read_config_dword(dev, PCI_COMMAND, &cmd);
+ cmd = (cmd | PCI_COMMAND_MEMORY );
+ pci_write_config_dword(dev, PCI_COMMAND, cmd);
#endif
}
@@ -3868,63 +3886,62 @@ static int __devinit bttv_probe(struct pci_dev *dev,
if (bttv_num == BTTV_MAX)
return -ENOMEM;
printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
- btv=&bttvs[bttv_num];
+ btv=&bttvs[bttv_num];
memset(btv,0,sizeof(*btv));
btv->c.nr = bttv_num;
sprintf(btv->c.name,"bttv%d",btv->c.nr);
/* initialize structs / fill in defaults */
- init_MUTEX(&btv->lock);
- init_MUTEX(&btv->reslock);
- spin_lock_init(&btv->s_lock);
- spin_lock_init(&btv->gpio_lock);
- init_waitqueue_head(&btv->gpioq);
- init_waitqueue_head(&btv->i2c_queue);
- INIT_LIST_HEAD(&btv->c.subs);
- INIT_LIST_HEAD(&btv->capture);
- INIT_LIST_HEAD(&btv->vcapture);
+ init_MUTEX(&btv->lock);
+ init_MUTEX(&btv->reslock);
+ spin_lock_init(&btv->s_lock);
+ spin_lock_init(&btv->gpio_lock);
+ init_waitqueue_head(&btv->gpioq);
+ init_waitqueue_head(&btv->i2c_queue);
+ INIT_LIST_HEAD(&btv->c.subs);
+ INIT_LIST_HEAD(&btv->capture);
+ INIT_LIST_HEAD(&btv->vcapture);
v4l2_prio_init(&btv->prio);
init_timer(&btv->timeout);
btv->timeout.function = bttv_irq_timeout;
btv->timeout.data = (unsigned long)btv;
- btv->i2c_rc = -1;
- btv->tuner_type = UNSET;
- btv->pinnacle_id = UNSET;
+ btv->i2c_rc = -1;
+ btv->tuner_type = UNSET;
+ btv->pinnacle_id = UNSET;
btv->new_input = UNSET;
- btv->gpioirq = 1;
btv->has_radio=radio[btv->c.nr];
/* pci stuff (init, get irq/mmio, ... */
btv->c.pci = dev;
- btv->id = dev->device;
+ btv->id = dev->device;
if (pci_enable_device(dev)) {
- printk(KERN_WARNING "bttv%d: Can't enable device.\n",
+ printk(KERN_WARNING "bttv%d: Can't enable device.\n",
btv->c.nr);
return -EIO;
}
- if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
- printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
+ if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
+ printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
btv->c.nr);
return -EIO;
- }
+ }
if (!request_mem_region(pci_resource_start(dev,0),
pci_resource_len(dev,0),
btv->c.name)) {
- printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
+ printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
btv->c.nr, pci_resource_start(dev,0));
return -EBUSY;
}
- pci_set_master(dev);
+ pci_set_master(dev);
pci_set_command(dev);
pci_set_drvdata(dev,btv);
- pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
- pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
- printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
- bttv_num,btv->id, btv->revision, pci_name(dev));
- printk("irq: %d, latency: %d, mmio: 0x%lx\n",
+ pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+ printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
+ bttv_num,btv->id, btv->revision, pci_name(dev));
+ printk("irq: %d, latency: %d, mmio: 0x%lx\n",
btv->c.pci->irq, lat, pci_resource_start(dev,0));
schedule();
@@ -3935,23 +3952,23 @@ static int __devinit bttv_probe(struct pci_dev *dev,
goto fail1;
}
- /* identify card */
+ /* identify card */
bttv_idcard(btv);
- /* disable irqs, register irq handler */
+ /* disable irqs, register irq handler */
btwrite(0, BT848_INT_MASK);
- result = request_irq(btv->c.pci->irq, bttv_irq,
- SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv);
- if (result < 0) {
- printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
+ result = request_irq(btv->c.pci->irq, bttv_irq,
+ SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv);
+ if (result < 0) {
+ printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
bttv_num,btv->c.pci->irq);
goto fail1;
- }
+ }
if (0 != bttv_handle_chipset(btv)) {
result = -EIO;
goto fail2;
- }
+ }
/* init options from insmod args */
btv->opt_combfilter = combfilter;
@@ -3977,29 +3994,29 @@ static int __devinit bttv_probe(struct pci_dev *dev,
btv->input = 0;
/* initialize hardware */
- if (bttv_gpio)
- bttv_gpio_tracking(btv,"pre-init");
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"pre-init");
bttv_risc_init_main(btv);
init_bt848(btv);
/* gpio */
- btwrite(0x00, BT848_GPIO_REG_INP);
- btwrite(0x00, BT848_GPIO_OUT_EN);
- if (bttv_verbose)
- bttv_gpio_tracking(btv,"init");
+ btwrite(0x00, BT848_GPIO_REG_INP);
+ btwrite(0x00, BT848_GPIO_OUT_EN);
+ if (bttv_verbose)
+ bttv_gpio_tracking(btv,"init");
- /* needs to be done before i2c is registered */
- bttv_init_card1(btv);
+ /* needs to be done before i2c is registered */
+ bttv_init_card1(btv);
- /* register i2c + gpio */
- init_bttv_i2c(btv);
+ /* register i2c + gpio */
+ init_bttv_i2c(btv);
- /* some card-specific stuff (needs working i2c) */
- bttv_init_card2(btv);
+ /* some card-specific stuff (needs working i2c) */
+ bttv_init_card2(btv);
init_irqreg(btv);
- /* register video4linux + input */
+ /* register video4linux + input */
if (!bttv_tvcards[btv->c.type].no_video) {
bttv_register_video(btv);
bt848_bright(btv,32768);
@@ -4018,10 +4035,10 @@ static int __devinit bttv_probe(struct pci_dev *dev,
/* everything is fine */
bttv_num++;
- return 0;
+ return 0;
fail2:
- free_irq(btv->c.pci->irq,btv);
+ free_irq(btv->c.pci->irq,btv);
fail1:
if (btv->bt848_mmio)
@@ -4034,12 +4051,12 @@ static int __devinit bttv_probe(struct pci_dev *dev,
static void __devexit bttv_remove(struct pci_dev *pci_dev)
{
- struct bttv *btv = pci_get_drvdata(pci_dev);
+ struct bttv *btv = pci_get_drvdata(pci_dev);
if (bttv_verbose)
printk("bttv%d: unloading\n",btv->c.nr);
- /* shutdown everything (DMA+IRQs) */
+ /* shutdown everything (DMA+IRQs) */
btand(~15, BT848_GPIO_DMA_CTL);
btwrite(0, BT848_INT_MASK);
btwrite(~0x0, BT848_INT_STAT);
@@ -4052,7 +4069,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
wake_up(&btv->gpioq);
bttv_sub_del_devices(&btv->c);
- /* unregister i2c_bus + input */
+ /* unregister i2c_bus + input */
fini_bttv_i2c(btv);
/* unregister video4linux */
@@ -4062,18 +4079,18 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
btcx_riscmem_free(btv->c.pci,&btv->main);
/* free ressources */
- free_irq(btv->c.pci->irq,btv);
+ free_irq(btv->c.pci->irq,btv);
iounmap(btv->bt848_mmio);
- release_mem_region(pci_resource_start(btv->c.pci,0),
- pci_resource_len(btv->c.pci,0));
+ release_mem_region(pci_resource_start(btv->c.pci,0),
+ pci_resource_len(btv->c.pci,0));
pci_set_drvdata(pci_dev, NULL);
- return;
+ return;
}
static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
{
- struct bttv *btv = pci_get_drvdata(pci_dev);
+ struct bttv *btv = pci_get_drvdata(pci_dev);
struct bttv_buffer_set idle;
unsigned long flags;
@@ -4108,7 +4125,7 @@ static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
static int bttv_resume(struct pci_dev *pci_dev)
{
- struct bttv *btv = pci_get_drvdata(pci_dev);
+ struct bttv *btv = pci_get_drvdata(pci_dev);
unsigned long flags;
int err;
@@ -4153,24 +4170,24 @@ static int bttv_resume(struct pci_dev *pci_dev)
}
static struct pci_device_id bttv_pci_tbl[] = {
- {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {0,}
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0,}
};
MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
static struct pci_driver bttv_pci_driver = {
- .name = "bttv",
- .id_table = bttv_pci_tbl,
- .probe = bttv_probe,
- .remove = __devexit_p(bttv_remove),
+ .name = "bttv",
+ .id_table = bttv_pci_tbl,
+ .probe = bttv_probe,
+ .remove = __devexit_p(bttv_remove),
.suspend = bttv_suspend,
.resume = bttv_resume,
};
diff --git a/drivers/media/video/bttv-gpio.c b/drivers/media/video/bttv-gpio.c
index 6b280c03e39..575ce8b8e71 100644
--- a/drivers/media/video/bttv-gpio.c
+++ b/drivers/media/video/bttv-gpio.c
@@ -7,7 +7,7 @@
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
- & Marcus Metzler (mocm@thp.uni-koeln.de)
+ & Marcus Metzler (mocm@thp.uni-koeln.de)
(c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
This program is free software; you can redistribute it and/or modify
diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c
index e684df37eb0..77619eb131f 100644
--- a/drivers/media/video/bttv-i2c.c
+++ b/drivers/media/video/bttv-i2c.c
@@ -5,7 +5,7 @@
bttv - Bt848 frame grabber driver
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
- & Marcus Metzler (mocm@thp.uni-koeln.de)
+ & Marcus Metzler (mocm@thp.uni-koeln.de)
(c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
This program is free software; you can redistribute it and/or modify
@@ -237,7 +237,7 @@ bttv_i2c_readbytes(struct bttv *btv, const struct i2c_msg *msg, int last)
err:
if (i2c_debug)
printk(" ERR: %d\n",retval);
- return retval;
+ return retval;
}
static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
@@ -290,7 +290,13 @@ static struct i2c_adapter bttv_i2c_adap_hw_template = {
static int attach_inform(struct i2c_client *client)
{
- struct bttv *btv = i2c_get_adapdata(client->adapter);
+ struct bttv *btv = i2c_get_adapdata(client->adapter);
+ int addr=ADDR_UNSET;
+
+
+ if (ADDR_UNSET != bttv_tvcards[btv->c.type].tuner_addr)
+ addr = bttv_tvcards[btv->c.type].tuner_addr;
+
if (bttv_debug)
printk(KERN_DEBUG "bttv%d: %s i2c attach [addr=0x%x,client=%s]\n",
@@ -300,19 +306,20 @@ static int attach_inform(struct i2c_client *client)
return 0;
if (btv->tuner_type != UNSET) {
- struct tuner_setup tun_setup;
+ struct tuner_setup tun_setup;
+
+ if ((addr==ADDR_UNSET) ||
+ (addr==client->addr)) {
- tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
- tun_setup.type = btv->tuner_type;
- tun_setup.addr = ADDR_UNSET;
+ tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV | T_RADIO;
+ tun_setup.type = btv->tuner_type;
+ tun_setup.addr = addr;
+ bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
- client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
}
- if (btv->pinnacle_id != UNSET)
- client->driver->command(client,AUDC_CONFIG_PINNACLE,
- &btv->pinnacle_id);
- return 0;
+ return 0;
}
void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
@@ -330,43 +337,43 @@ static struct i2c_client bttv_i2c_client_template = {
/* read I2C */
int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
{
- unsigned char buffer = 0;
+ unsigned char buffer = 0;
if (0 != btv->i2c_rc)
return -1;
if (bttv_verbose && NULL != probe_for)
printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ",
btv->c.nr,probe_for,addr);
- btv->i2c_client.addr = addr >> 1;
- if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
+ btv->i2c_client.addr = addr >> 1;
+ if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) {
if (NULL != probe_for) {
if (bttv_verbose)
printk("not found\n");
} else
printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n",
btv->c.nr,addr);
- return -1;
+ return -1;
}
if (bttv_verbose && NULL != probe_for)
printk("found\n");
- return buffer;
+ return buffer;
}
/* write I2C */
int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
- unsigned char b2, int both)
+ unsigned char b2, int both)
{
- unsigned char buffer[2];
- int bytes = both ? 2 : 1;
+ unsigned char buffer[2];
+ int bytes = both ? 2 : 1;
if (0 != btv->i2c_rc)
return -1;
- btv->i2c_client.addr = addr >> 1;
- buffer[0] = b1;
- buffer[1] = b2;
- if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes))
+ btv->i2c_client.addr = addr >> 1;
+ buffer[0] = b1;
+ buffer[1] = b2;
+ if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes))
return -1;
- return 0;
+ return 0;
}
/* read EEPROM content */
@@ -431,8 +438,8 @@ int __devinit init_bttv_i2c(struct bttv *btv)
"bt%d #%d [%s]", btv->id, btv->c.nr,
btv->use_i2c_hw ? "hw" : "sw");
- i2c_set_adapdata(&btv->c.i2c_adap, btv);
- btv->i2c_client.adapter = &btv->c.i2c_adap;
+ i2c_set_adapdata(&btv->c.i2c_adap, btv);
+ btv->i2c_client.adapter = &btv->c.i2c_adap;
#ifdef I2C_CLASS_TV_ANALOG
if (bttv_tvcards[btv->c.type].no_video)
diff --git a/drivers/media/video/bttv-if.c b/drivers/media/video/bttv-if.c
index e8aada772b8..19b564ab0e9 100644
--- a/drivers/media/video/bttv-if.c
+++ b/drivers/media/video/bttv-if.c
@@ -1,13 +1,13 @@
/*
bttv-if.c -- old gpio interface to other kernel modules
- don't use in new code, will go away in 2.7
+ don't use in new code, will go away in 2.7
have a look at bttv-gpio.c instead.
bttv - Bt848 frame grabber driver
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
- & Marcus Metzler (mocm@thp.uni-koeln.de)
+ & Marcus Metzler (mocm@thp.uni-koeln.de)
(c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
This program is free software; you can redistribute it and/or modify
diff --git a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c
index a5ed99b8944..b40e9734bf0 100644
--- a/drivers/media/video/bttv-risc.c
+++ b/drivers/media/video/bttv-risc.c
@@ -74,27 +74,27 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
}
if (bpl <= sg_dma_len(sg)-offset) {
/* fits into current chunk */
- *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
+ *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
BT848_RISC_EOL|bpl);
- *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
- offset+=bpl;
+ *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+ offset+=bpl;
} else {
/* scanline needs to be splitted */
- todo = bpl;
- *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
+ todo = bpl;
+ *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
(sg_dma_len(sg)-offset));
- *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
- todo -= (sg_dma_len(sg)-offset);
- offset = 0;
- sg++;
- while (todo > sg_dma_len(sg)) {
- *(rp++)=cpu_to_le32(BT848_RISC_WRITE|
+ *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+ todo -= (sg_dma_len(sg)-offset);
+ offset = 0;
+ sg++;
+ while (todo > sg_dma_len(sg)) {
+ *(rp++)=cpu_to_le32(BT848_RISC_WRITE|
sg_dma_len(sg));
- *(rp++)=cpu_to_le32(sg_dma_address(sg));
+ *(rp++)=cpu_to_le32(sg_dma_address(sg));
todo -= sg_dma_len(sg);
sg++;
}
- *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
+ *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
todo);
*(rp++)=cpu_to_le32(sg_dma_address(sg));
offset += todo;
@@ -201,8 +201,8 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
ri |= BT848_RISC_EOL;
/* write risc instruction */
- *(rp++)=cpu_to_le32(ri | ylen);
- *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
+ *(rp++)=cpu_to_le32(ri | ylen);
+ *(rp++)=cpu_to_le32(((ylen >> hshift) << 16) |
(ylen >> hshift));
*(rp++)=cpu_to_le32(sg_dma_address(ysg)+yoffset);
yoffset += ylen;
@@ -319,7 +319,7 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
int width, int height, int interleaved, int norm)
{
const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm];
- u32 xsf, sr;
+ u32 xsf, sr;
int vdelay;
int swidth = tvnorm->swidth;
@@ -334,52 +334,52 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
vdelay = tvnorm->vdelay;
- xsf = (width*scaledtwidth)/swidth;
- geo->hscale = ((totalwidth*4096UL)/xsf-4096);
- geo->hdelay = tvnorm->hdelayx1;
- geo->hdelay = (geo->hdelay*width)/swidth;
- geo->hdelay &= 0x3fe;
- sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
- geo->vscale = (0x10000UL-sr) & 0x1fff;
- geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
- ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
- geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
- geo->vdelay = vdelay;
- geo->width = width;
- geo->sheight = tvnorm->sheight;
+ xsf = (width*scaledtwidth)/swidth;
+ geo->hscale = ((totalwidth*4096UL)/xsf-4096);
+ geo->hdelay = tvnorm->hdelayx1;
+ geo->hdelay = (geo->hdelay*width)/swidth;
+ geo->hdelay &= 0x3fe;
+ sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512;
+ geo->vscale = (0x10000UL-sr) & 0x1fff;
+ geo->crop = ((width>>8)&0x03) | ((geo->hdelay>>6)&0x0c) |
+ ((tvnorm->sheight>>4)&0x30) | ((vdelay>>2)&0xc0);
+ geo->vscale |= interleaved ? (BT848_VSCALE_INT<<8) : 0;
+ geo->vdelay = vdelay;
+ geo->width = width;
+ geo->sheight = tvnorm->sheight;
geo->vtotal = tvnorm->vtotal;
- 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;
- }
+ 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;
+ int off = odd ? 0x80 : 0x00;
if (geo->comb)
btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
else
btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI+off);
- btwrite(geo->vtc, BT848_E_VTC+off);
- btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off);
- btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off);
- btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
- btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off);
- btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off);
- btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off);
- btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off);
- btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off);
- btwrite(geo->crop, BT848_E_CROP+off);
+ btwrite(geo->vtc, BT848_E_VTC+off);
+ btwrite(geo->hscale >> 8, BT848_E_HSCALE_HI+off);
+ btwrite(geo->hscale & 0xff, BT848_E_HSCALE_LO+off);
+ btaor((geo->vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
+ btwrite(geo->vscale & 0xff, BT848_E_VSCALE_LO+off);
+ btwrite(geo->width & 0xff, BT848_E_HACTIVE_LO+off);
+ btwrite(geo->hdelay & 0xff, BT848_E_HDELAY_LO+off);
+ btwrite(geo->sheight & 0xff, BT848_E_VACTIVE_LO+off);
+ btwrite(geo->vdelay & 0xff, BT848_E_VDELAY_LO+off);
+ btwrite(geo->crop, BT848_E_CROP+off);
btwrite(geo->vtotal>>8, BT848_VTOTAL_HI);
- btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO);
+ btwrite(geo->vtotal & 0xff, BT848_VTOTAL_LO);
}
/* ---------------------------------------------------------- */
@@ -420,7 +420,7 @@ bttv_set_dma(struct bttv *btv, int override)
} else {
del_timer(&btv->timeout);
}
- btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
+ btv->main.cpu[RISC_SLOT_LOOP] = cpu_to_le32(cmd);
btaor(capctl, ~0x0f, BT848_CAP_CTL);
if (capctl) {
@@ -432,7 +432,7 @@ bttv_set_dma(struct bttv *btv, int override)
} else {
if (!btv->dma_on)
return;
- btand(~3, BT848_GPIO_DMA_CTL);
+ btand(~3, BT848_GPIO_DMA_CTL);
btv->dma_on = 0;
}
return;
@@ -460,19 +460,19 @@ bttv_risc_init_main(struct bttv *btv)
btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP);
btv->main.cpu[7] = cpu_to_le32(btv->main.dma + (8<<2));
- btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
+ btv->main.cpu[8] = cpu_to_le32(BT848_RISC_SYNC | BT848_RISC_RESYNC |
BT848_FIFO_STATUS_VRO);
- btv->main.cpu[9] = cpu_to_le32(0);
+ btv->main.cpu[9] = cpu_to_le32(0);
/* bottom field */
- btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
+ btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP);
btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2));
- btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
+ btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP);
btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2));
/* jump back to top field */
btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP);
- btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
+ btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2));
return 0;
}
diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h
index d254e90e3bb..124ea41dada 100644
--- a/drivers/media/video/bttv.h
+++ b/drivers/media/video/bttv.h
@@ -20,123 +20,148 @@
/* ---------------------------------------------------------- */
/* exported by bttv-cards.c */
-#define BTTV_UNKNOWN 0x00
-#define BTTV_MIRO 0x01
-#define BTTV_HAUPPAUGE 0x02
-#define BTTV_STB 0x03
-#define BTTV_INTEL 0x04
-#define BTTV_DIAMOND 0x05
-#define BTTV_AVERMEDIA 0x06
-#define BTTV_MATRIX_VISION 0x07
-#define BTTV_FLYVIDEO 0x08
-#define BTTV_TURBOTV 0x09
-#define BTTV_HAUPPAUGE878 0x0a
-#define BTTV_MIROPRO 0x0b
-#define BTTV_ADSTECH_TV 0x0c
-#define BTTV_AVERMEDIA98 0x0d
-#define BTTV_VHX 0x0e
-#define BTTV_ZOLTRIX 0x0f
-#define BTTV_PIXVIEWPLAYTV 0x10
-#define BTTV_WINVIEW_601 0x11
-#define BTTV_AVEC_INTERCAP 0x12
-#define BTTV_LIFE_FLYKIT 0x13
-#define BTTV_CEI_RAFFLES 0x14
-#define BTTV_CONFERENCETV 0x15
-#define BTTV_PHOEBE_TVMAS 0x16
-#define BTTV_MODTEC_205 0x17
-#define BTTV_MAGICTVIEW061 0x18
-#define BTTV_VOBIS_BOOSTAR 0x19
-#define BTTV_HAUPPAUG_WCAM 0x1a
-#define BTTV_MAXI 0x1b
-#define BTTV_TERRATV 0x1c
-#define BTTV_PXC200 0x1d
-#define BTTV_FLYVIDEO_98 0x1e
-#define BTTV_IPROTV 0x1f
-#define BTTV_INTEL_C_S_PCI 0x20
-#define BTTV_TERRATVALUE 0x21
-#define BTTV_WINFAST2000 0x22
-#define BTTV_CHRONOS_VS2 0x23
-#define BTTV_TYPHOON_TVIEW 0x24
-#define BTTV_PXELVWPLTVPRO 0x25
-#define BTTV_MAGICTVIEW063 0x26
-#define BTTV_PINNACLE 0x27
-#define BTTV_STB2 0x28
-#define BTTV_AVPHONE98 0x29
-#define BTTV_PV951 0x2a
-#define BTTV_ONAIR_TV 0x2b
-#define BTTV_SIGMA_TVII_FM 0x2c
-#define BTTV_MATRIX_VISION2 0x2d
-#define BTTV_ZOLTRIX_GENIE 0x2e
-#define BTTV_TERRATVRADIO 0x2f
-#define BTTV_DYNALINK 0x30
-#define BTTV_GVBCTV3PCI 0x31
-#define BTTV_PXELVWPLTVPAK 0x32
-#define BTTV_EAGLE 0x33
-#define BTTV_PINNACLEPRO 0x34
-#define BTTV_TVIEW_RDS_FM 0x35
-#define BTTV_LIFETEC_9415 0x36
-#define BTTV_BESTBUY_EASYTV 0x37
-#define BTTV_FLYVIDEO_98FM 0x38
-#define BTTV_GMV1 0x3d
-#define BTTV_BESTBUY_EASYTV2 0x3e
-#define BTTV_ATI_TVWONDER 0x3f
-#define BTTV_ATI_TVWONDERVE 0x40
-#define BTTV_FLYVIDEO2000 0x41
-#define BTTV_TERRATVALUER 0x42
-#define BTTV_GVBCTV4PCI 0x43
-#define BTTV_VOODOOTV_FM 0x44
-#define BTTV_AIMMS 0x45
-#define BTTV_PV_BT878P_PLUS 0x46
-#define BTTV_FLYVIDEO98EZ 0x47
-#define BTTV_PV_BT878P_9B 0x48
-#define BTTV_SENSORAY311 0x49
-#define BTTV_RV605 0x4a
-#define BTTV_WINDVR 0x4c
-#define BTTV_GRANDTEC 0x4d
-#define BTTV_KWORLD 0x4e
-#define BTTV_HAUPPAUGEPVR 0x50
-#define BTTV_GVBCTV5PCI 0x51
-#define BTTV_OSPREY1x0 0x52
-#define BTTV_OSPREY1x0_848 0x53
-#define BTTV_OSPREY101_848 0x54
-#define BTTV_OSPREY1x1 0x55
-#define BTTV_OSPREY1x1_SVID 0x56
-#define BTTV_OSPREY2xx 0x57
-#define BTTV_OSPREY2x0_SVID 0x58
-#define BTTV_OSPREY2x0 0x59
-#define BTTV_OSPREY500 0x5a
-#define BTTV_OSPREY540 0x5b
-#define BTTV_OSPREY2000 0x5c
-#define BTTV_IDS_EAGLE 0x5d
-#define BTTV_PINNACLESAT 0x5e
-#define BTTV_FORMAC_PROTV 0x5f
-#define BTTV_EURESYS_PICOLO 0x61
-#define BTTV_PV150 0x62
-#define BTTV_AD_TVK503 0x63
-#define BTTV_IVC200 0x66
-#define BTTV_XGUARD 0x67
-#define BTTV_NEBULA_DIGITV 0x68
-#define BTTV_PV143 0x69
-#define BTTV_IVC100 0x6e
-#define BTTV_IVC120 0x6f
-#define BTTV_PC_HDTV 0x70
-#define BTTV_TWINHAN_DST 0x71
-#define BTTV_WINFASTVC100 0x72
-#define BTTV_SIMUS_GVC1100 0x74
-#define BTTV_NGSTV_PLUS 0x75
-#define BTTV_LMLBT4 0x76
-#define BTTV_PICOLO_TETRA_CHIP 0x79
-#define BTTV_AVDVBT_771 0x7b
-#define BTTV_AVDVBT_761 0x7c
-#define BTTV_MATRIX_VISIONSQ 0x7d
-#define BTTV_MATRIX_VISIONSLC 0x7e
-#define BTTV_APAC_VIEWCOMP 0x7f
-#define BTTV_DVICO_DVBT_LITE 0x80
-#define BTTV_TIBET_CS16 0x83
-#define BTTV_KODICOM_4400R 0x84
-#define BTTV_ADLINK_RTV24 0x86
-#define BTTV_DVICO_FUSIONHDTV_5_LITE 0x87
-#define BTTV_ACORP_Y878F 0x88
+#define BTTV_BOARD_UNKNOWN 0x00
+#define BTTV_BOARD_MIRO 0x01
+#define BTTV_BOARD_HAUPPAUGE 0x02
+#define BTTV_BOARD_STB 0x03
+#define BTTV_BOARD_INTEL 0x04
+#define BTTV_BOARD_DIAMOND 0x05
+#define BTTV_BOARD_AVERMEDIA 0x06
+#define BTTV_BOARD_MATRIX_VISION 0x07
+#define BTTV_BOARD_FLYVIDEO 0x08
+#define BTTV_BOARD_TURBOTV 0x09
+#define BTTV_BOARD_HAUPPAUGE878 0x0a
+#define BTTV_BOARD_MIROPRO 0x0b
+#define BTTV_BOARD_ADSTECH_TV 0x0c
+#define BTTV_BOARD_AVERMEDIA98 0x0d
+#define BTTV_BOARD_VHX 0x0e
+#define BTTV_BOARD_ZOLTRIX 0x0f
+#define BTTV_BOARD_PIXVIEWPLAYTV 0x10
+#define BTTV_BOARD_WINVIEW_601 0x11
+#define BTTV_BOARD_AVEC_INTERCAP 0x12
+#define BTTV_BOARD_LIFE_FLYKIT 0x13
+#define BTTV_BOARD_CEI_RAFFLES 0x14
+#define BTTV_BOARD_CONFERENCETV 0x15
+#define BTTV_BOARD_PHOEBE_TVMAS 0x16
+#define BTTV_BOARD_MODTEC_205 0x17
+#define BTTV_BOARD_MAGICTVIEW061 0x18
+#define BTTV_BOARD_VOBIS_BOOSTAR 0x19
+#define BTTV_BOARD_HAUPPAUG_WCAM 0x1a
+#define BTTV_BOARD_MAXI 0x1b
+#define BTTV_BOARD_TERRATV 0x1c
+#define BTTV_BOARD_PXC200 0x1d
+#define BTTV_BOARD_FLYVIDEO_98 0x1e
+#define BTTV_BOARD_IPROTV 0x1f
+#define BTTV_BOARD_INTEL_C_S_PCI 0x20
+#define BTTV_BOARD_TERRATVALUE 0x21
+#define BTTV_BOARD_WINFAST2000 0x22
+#define BTTV_BOARD_CHRONOS_VS2 0x23
+#define BTTV_BOARD_TYPHOON_TVIEW 0x24
+#define BTTV_BOARD_PXELVWPLTVPRO 0x25
+#define BTTV_BOARD_MAGICTVIEW063 0x26
+#define BTTV_BOARD_PINNACLE 0x27
+#define BTTV_BOARD_STB2 0x28
+#define BTTV_BOARD_AVPHONE98 0x29
+#define BTTV_BOARD_PV951 0x2a
+#define BTTV_BOARD_ONAIR_TV 0x2b
+#define BTTV_BOARD_SIGMA_TVII_FM 0x2c
+#define BTTV_BOARD_MATRIX_VISION2 0x2d
+#define BTTV_BOARD_ZOLTRIX_GENIE 0x2e
+#define BTTV_BOARD_TERRATVRADIO 0x2f
+#define BTTV_BOARD_DYNALINK 0x30
+#define BTTV_BOARD_GVBCTV3PCI 0x31
+#define BTTV_BOARD_PXELVWPLTVPAK 0x32
+#define BTTV_BOARD_EAGLE 0x33
+#define BTTV_BOARD_PINNACLEPRO 0x34
+#define BTTV_BOARD_TVIEW_RDS_FM 0x35
+#define BTTV_BOARD_LIFETEC_9415 0x36
+#define BTTV_BOARD_BESTBUY_EASYTV 0x37
+#define BTTV_BOARD_FLYVIDEO_98FM 0x38
+#define BTTV_BOARD_GRANDTEC 0x39
+#define BTTV_BOARD_ASKEY_CPH060 0x3a
+#define BTTV_BOARD_ASKEY_CPH03X 0x3b
+#define BTTV_BOARD_MM100PCTV 0x3c
+#define BTTV_BOARD_GMV1 0x3d
+#define BTTV_BOARD_BESTBUY_EASYTV2 0x3e
+#define BTTV_BOARD_ATI_TVWONDER 0x3f
+#define BTTV_BOARD_ATI_TVWONDERVE 0x40
+#define BTTV_BOARD_FLYVIDEO2000 0x41
+#define BTTV_BOARD_TERRATVALUER 0x42
+#define BTTV_BOARD_GVBCTV4PCI 0x43
+#define BTTV_BOARD_VOODOOTV_FM 0x44
+#define BTTV_BOARD_AIMMS 0x45
+#define BTTV_BOARD_PV_BT878P_PLUS 0x46
+#define BTTV_BOARD_FLYVIDEO98EZ 0x47
+#define BTTV_BOARD_PV_BT878P_9B 0x48
+#define BTTV_BOARD_SENSORAY311 0x49
+#define BTTV_BOARD_RV605 0x4a
+#define BTTV_BOARD_POWERCLR_MTV878 0x4b
+#define BTTV_BOARD_WINDVR 0x4c
+#define BTTV_BOARD_GRANDTEC_MULTI 0x4d
+#define BTTV_BOARD_KWORLD 0x4e
+#define BTTV_BOARD_DSP_TCVIDEO 0x4f
+#define BTTV_BOARD_HAUPPAUGEPVR 0x50
+#define BTTV_BOARD_GVBCTV5PCI 0x51
+#define BTTV_BOARD_OSPREY1x0 0x52
+#define BTTV_BOARD_OSPREY1x0_848 0x53
+#define BTTV_BOARD_OSPREY101_848 0x54
+#define BTTV_BOARD_OSPREY1x1 0x55
+#define BTTV_BOARD_OSPREY1x1_SVID 0x56
+#define BTTV_BOARD_OSPREY2xx 0x57
+#define BTTV_BOARD_OSPREY2x0_SVID 0x58
+#define BTTV_BOARD_OSPREY2x0 0x59
+#define BTTV_BOARD_OSPREY500 0x5a
+#define BTTV_BOARD_OSPREY540 0x5b
+#define BTTV_BOARD_OSPREY2000 0x5c
+#define BTTV_BOARD_IDS_EAGLE 0x5d
+#define BTTV_BOARD_PINNACLESAT 0x5e
+#define BTTV_BOARD_FORMAC_PROTV 0x5f
+#define BTTV_BOARD_MACHTV 0x60
+#define BTTV_BOARD_EURESYS_PICOLO 0x61
+#define BTTV_BOARD_PV150 0x62
+#define BTTV_BOARD_AD_TVK503 0x63
+#define BTTV_BOARD_HERCULES_SM_TV 0x64
+#define BTTV_BOARD_PACETV 0x65
+#define BTTV_BOARD_IVC200 0x66
+#define BTTV_BOARD_XGUARD 0x67
+#define BTTV_BOARD_NEBULA_DIGITV 0x68
+#define BTTV_BOARD_PV143 0x69
+#define BTTV_BOARD_VD009X1_MINIDIN 0x6a
+#define BTTV_BOARD_VD009X1_COMBI 0x6b
+#define BTTV_BOARD_VD009_MINIDIN 0x6c
+#define BTTV_BOARD_VD009_COMBI 0x6d
+#define BTTV_BOARD_IVC100 0x6e
+#define BTTV_BOARD_IVC120 0x6f
+#define BTTV_BOARD_PC_HDTV 0x70
+#define BTTV_BOARD_TWINHAN_DST 0x71
+#define BTTV_BOARD_WINFASTVC100 0x72
+#define BTTV_BOARD_TEV560 0x73
+#define BTTV_BOARD_SIMUS_GVC1100 0x74
+#define BTTV_BOARD_NGSTV_PLUS 0x75
+#define BTTV_BOARD_LMLBT4 0x76
+#define BTTV_BOARD_TEKRAM_M205 0x77
+#define BTTV_BOARD_CONTVFMI 0x78
+#define BTTV_BOARD_PICOLO_TETRA_CHIP 0x79
+#define BTTV_BOARD_SPIRIT_TV 0x7a
+#define BTTV_BOARD_AVDVBT_771 0x7b
+#define BTTV_BOARD_AVDVBT_761 0x7c
+#define BTTV_BOARD_MATRIX_VISIONSQ 0x7d
+#define BTTV_BOARD_MATRIX_VISIONSLC 0x7e
+#define BTTV_BOARD_APAC_VIEWCOMP 0x7f
+#define BTTV_BOARD_DVICO_DVBT_LITE 0x80
+#define BTTV_BOARD_VGEAR_MYVCD 0x81
+#define BTTV_BOARD_SUPER_TV 0x82
+#define BTTV_BOARD_TIBET_CS16 0x83
+#define BTTV_BOARD_KODICOM_4400R 0x84
+#define BTTV_BOARD_KODICOM_4400R_SL 0x85
+#define BTTV_BOARD_ADLINK_RTV24 0x86
+#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87
+#define BTTV_BOARD_ACORP_Y878F 0x88
+#define BTTV_BOARD_CONCEPTRONIC_CTVFMI2 0x89
+#define BTTV_BOARD_PV_BT878P_2E 0x8a
+#define BTTV_BOARD_PV_M4900 0x8b
+#define BTTV_BOARD_OSPREY440 0x8c
+#define BTTV_BOARD_ASOUND_SKYEYE 0x8d
/* i2c address list */
#define I2C_TSA5522 0xc2
@@ -177,7 +202,7 @@ struct bttv_core {
struct list_head subs; /* struct bttv_sub_device */
/* device config */
- unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */
+ unsigned int nr; /* dev nr (for printk("bttv%d: ..."); */
unsigned int type; /* card type (pointer into tvcards[]) */
char name[8]; /* dev name */
};
@@ -186,16 +211,16 @@ struct bttv;
struct tvcard
{
- char *name;
- unsigned int video_inputs;
- unsigned int audio_inputs;
- unsigned int tuner;
- unsigned int svhs;
+ char *name;
+ unsigned int video_inputs;
+ unsigned int audio_inputs;
+ unsigned int tuner;
+ unsigned int svhs;
unsigned int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO
- u32 gpiomask;
- u32 muxsel[16];
- u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
- u32 gpiomask2; /* GPIO MUX mask */
+ u32 gpiomask;
+ u32 muxsel[16];
+ u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
+ u32 gpiomask2; /* GPIO MUX mask */
/* i2c audio flags */
unsigned int no_msp34xx:1;
@@ -218,6 +243,7 @@ struct tvcard
unsigned int tuner_type;
unsigned int tuner_addr;
+ unsigned int radio_addr;
unsigned int has_radio;
void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
@@ -246,7 +272,7 @@ extern int bttv_handle_chipset(struct bttv *btv);
interface below for new code */
/* returns card type + card ID (for bt878-based ones)
- for possible values see lines below beginning with #define BTTV_UNKNOWN
+ for possible values see lines below beginning with #define BTTV_BOARD_UNKNOWN
returns negative value if error occurred
*/
extern int bttv_get_cardinfo(unsigned int card, int *type,
diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h
index e0e7c7a84bc..386f546f7d1 100644
--- a/drivers/media/video/bttvp.h
+++ b/drivers/media/video/bttvp.h
@@ -77,14 +77,14 @@
struct bttv_tvnorm {
int v4l2_id;
char *name;
- u32 Fsc;
- u16 swidth, sheight; /* scaled standard width, height */
+ u32 Fsc;
+ u16 swidth, sheight; /* scaled standard width, height */
u16 totalwidth;
u8 adelay, bdelay, iform;
u32 scaledtwidth;
u16 hdelayx1, hactivex1;
u16 vdelay;
- u8 vbipack;
+ u8 vbipack;
u16 vtotal;
int sram;
};
@@ -267,8 +267,8 @@ struct bttv {
/* card configuration info */
unsigned int cardid; /* pci subsystem id (bt878 based ones) */
- unsigned int tuner_type; /* tuner chip type */
- unsigned int pinnacle_id;
+ unsigned int tuner_type; /* tuner chip type */
+ unsigned int pinnacle_id;
unsigned int svhs;
struct bttv_pll_info pll;
int triton1;
@@ -301,9 +301,9 @@ struct bttv {
/* locking */
spinlock_t s_lock;
- struct semaphore lock;
+ struct semaphore lock;
int resources;
- struct semaphore reslock;
+ struct semaphore reslock;
#ifdef VIDIOC_G_PRIORITY
struct v4l2_prio_state prio;
#endif
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
new file mode 100644
index 00000000000..780b352ec11
--- /dev/null
+++ b/drivers/media/video/cs53l32a.c
@@ -0,0 +1,240 @@
+/*
+ * cs53l32a (Adaptec AVC-2010 and AVC-2410) i2c ivtv driver.
+ * Copyright (C) 2005 Martin Vaughan
+ *
+ * Audio source switching for Adaptec AVC-2410 added by Trev Jackson
+ *
+ * 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/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/videodev.h>
+#include <media/audiochip.h>
+
+MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
+MODULE_AUTHOR("Martin Vaughan");
+MODULE_LICENSE("GPL");
+
+static int debug = 0;
+
+module_param(debug, bool, 0644);
+
+MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On");
+
+#define cs53l32a_dbg(fmt, arg...) \
+ do { \
+ if (debug) \
+ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); \
+ } while (0)
+
+#define cs53l32a_err(fmt, arg...) do { \
+ printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define cs53l32a_info(fmt, arg...) do { \
+ printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+static int cs53l32a_write(struct i2c_client *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int cs53l32a_read(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ int *input = arg;
+
+ switch (cmd) {
+ case AUDC_SET_INPUT:
+ switch (*input) {
+ case AUDIO_TUNER:
+ cs53l32a_write(client, 0x01, 0x01);
+ break;
+ case AUDIO_EXTERN:
+ cs53l32a_write(client, 0x01, 0x21);
+ break;
+ case AUDIO_MUTE:
+ cs53l32a_write(client, 0x03, 0xF0);
+ break;
+ case AUDIO_UNMUTE:
+ cs53l32a_write(client, 0x03, 0x30);
+ break;
+ default:
+ cs53l32a_err("Invalid input %d.\n", *input);
+ return -EINVAL;
+ }
+ break;
+
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+
+ if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+ return -EINVAL;
+ if (ctrl->value > 12 || ctrl->value < -90)
+ return -EINVAL;
+ cs53l32a_write(client, 0x04, (u8) ctrl->value);
+ cs53l32a_write(client, 0x05, (u8) ctrl->value);
+ break;
+ }
+
+ case VIDIOC_LOG_STATUS:
+ {
+ u8 v = cs53l32a_read(client, 0x01);
+ u8 m = cs53l32a_read(client, 0x03);
+
+ cs53l32a_info("Input: %s%s\n",
+ v == 0x21 ? "external line in" : "tuner",
+ (m & 0xC0) ? " (muted)" : "");
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static struct i2c_driver i2c_driver;
+
+static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ int i;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+
+ memset(client, 0, sizeof(struct i2c_client));
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver;
+ client->flags = I2C_CLIENT_ALLOW_USE;
+ snprintf(client->name, sizeof(client->name) - 1, "cs53l32a");
+
+ cs53l32a_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+
+ for (i = 1; i <= 7; i++) {
+ u8 v = cs53l32a_read(client, i);
+
+ cs53l32a_dbg("Read Reg %d %02x\n", i, v);
+ }
+
+ /* Set cs53l32a internal register for Adaptec 2010/2410 setup */
+
+ cs53l32a_write(client, 0x01, (u8) 0x21);
+ cs53l32a_write(client, 0x02, (u8) 0x29);
+ cs53l32a_write(client, 0x03, (u8) 0x30);
+ cs53l32a_write(client, 0x04, (u8) 0x00);
+ cs53l32a_write(client, 0x05, (u8) 0x00);
+ cs53l32a_write(client, 0x06, (u8) 0x00);
+ cs53l32a_write(client, 0x07, (u8) 0x00);
+
+ /* Display results, should be 0x21,0x29,0x30,0x00,0x00,0x00,0x00 */
+
+ for (i = 1; i <= 7; i++) {
+ u8 v = cs53l32a_read(client, i);
+
+ cs53l32a_dbg("Read Reg %d %02x\n", i, v);
+ }
+
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+static int cs53l32a_probe(struct i2c_adapter *adapter)
+{
+#ifdef I2C_CLASS_TV_ANALOG
+ if (adapter->class & I2C_CLASS_TV_ANALOG)
+#else
+ if (adapter->id == I2C_HW_B_BT848)
+#endif
+ return i2c_probe(adapter, &addr_data, cs53l32a_attach);
+ return 0;
+}
+
+static int cs53l32a_detach(struct i2c_client *client)
+{
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ return err;
+ }
+ kfree(client);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver = {
+ .name = "cs53l32a",
+ .id = I2C_DRIVERID_CS53L32A,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = cs53l32a_probe,
+ .detach_client = cs53l32a_detach,
+ .command = cs53l32a_command,
+ .owner = THIS_MODULE,
+};
+
+
+static int __init cs53l32a_init_module(void)
+{
+ return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit cs53l32a_cleanup_module(void)
+{
+ i2c_del_driver(&i2c_driver);
+}
+
+module_init(cs53l32a_init_module);
+module_exit(cs53l32a_cleanup_module);
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
new file mode 100644
index 00000000000..41818b6205b
--- /dev/null
+++ b/drivers/media/video/cx88/Kconfig
@@ -0,0 +1,91 @@
+config VIDEO_CX88
+ tristate "Conexant 2388x (bt878 successor) support"
+ depends on VIDEO_DEV && PCI && I2C
+ select I2C_ALGOBIT
+ select FW_LOADER
+ select VIDEO_BTCX
+ select VIDEO_BUF
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_IR
+ ---help---
+ This is a video4linux driver for Conexant 2388x based
+ TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx8800
+
+config VIDEO_CX88_DVB
+ tristate "DVB/ATSC Support for cx2388x based TV cards"
+ depends on VIDEO_CX88 && DVB_CORE
+ select VIDEO_BUF_DVB
+ ---help---
+ This adds support for DVB/ATSC cards based on the
+ Connexant 2388x chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx88-dvb.
+
+ You must also select one or more DVB/ATSC demodulators.
+ If you are unsure which you need, choose all of them.
+
+config VIDEO_CX88_DVB_ALL_FRONTENDS
+ bool "Build all supported frontends for cx2388x based TV cards"
+ default y
+ depends on VIDEO_CX88_DVB
+ select DVB_MT352
+ select DVB_OR51132
+ select DVB_CX22702
+ select DVB_LGDT330X
+ select DVB_NXT200X
+ ---help---
+ This builds cx88-dvb with all currently supported frontend
+ demodulators. If you wish to tweak your configuration, and
+ only include support for the hardware that you need, choose N here.
+
+ If you are unsure, choose Y.
+
+config VIDEO_CX88_DVB_MT352
+ tristate "Zarlink MT352 DVB-T Support"
+ default m
+ depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+ select DVB_MT352
+ ---help---
+ This adds DVB-T support for cards based on the
+ Connexant 2388x chip and the MT352 demodulator.
+
+config VIDEO_CX88_DVB_OR51132
+ tristate "OR51132 ATSC Support"
+ default m
+ depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+ select DVB_OR51132
+ ---help---
+ This adds ATSC 8VSB and QAM64/256 support for cards based on the
+ Connexant 2388x chip and the OR51132 demodulator.
+
+config VIDEO_CX88_DVB_CX22702
+ tristate "Conexant CX22702 DVB-T Support"
+ default m
+ depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+ select DVB_CX22702
+ ---help---
+ This adds DVB-T support for cards based on the
+ Connexant 2388x chip and the CX22702 demodulator.
+
+config VIDEO_CX88_DVB_LGDT330X
+ tristate "LG Electronics DT3302/DT3303 ATSC Support"
+ default m
+ depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+ select DVB_LGDT330X
+ ---help---
+ This adds ATSC 8VSB and QAM64/256 support for cards based on the
+ Connexant 2388x chip and the LGDT3302/LGDT3303 demodulator.
+
+config VIDEO_CX88_DVB_NXT200X
+ tristate "NXT2002/NXT2004 ATSC Support"
+ default m
+ depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
+ select DVB_NXT200X
+ ---help---
+ This adds ATSC 8VSB and QAM64/256 support for cards based on the
+ Connexant 2388x chip and the NXT2002/NXT2004 demodulator.
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
index 107e48645e3..0df40b77345 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -9,6 +9,9 @@ obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
EXTRA_CFLAGS += -I$(src)/..
EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends
+ifneq ($(CONFIG_VIDEO_BUF_DVB),n)
+ EXTRA_CFLAGS += -DHAVE_VIDEO_BUF_DVB=1
+endif
ifneq ($(CONFIG_DVB_CX22702),n)
EXTRA_CFLAGS += -DHAVE_CX22702=1
endif
@@ -21,3 +24,6 @@ endif
ifneq ($(CONFIG_DVB_MT352),n)
EXTRA_CFLAGS += -DHAVE_MT352=1
endif
+ifneq ($(CONFIG_DVB_NXT200X),n)
+ EXTRA_CFLAGS += -DHAVE_NXT200X=1
+endif
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index 0c0c59e9477..4ae3f78cccf 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -38,7 +38,7 @@ MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
-static unsigned int mpegbufs = 8;
+static unsigned int mpegbufs = 32;
module_param(mpegbufs,int,0644);
MODULE_PARM_DESC(mpegbufs,"number of mpeg buffers, range 2-32");
@@ -436,7 +436,7 @@ static int memory_write(struct cx88_core *core, u32 address, u32 value)
static int memory_read(struct cx88_core *core, u32 address, u32 *value)
{
- int retval;
+ int retval;
u32 val;
/* Warning: address is dword address (4 bytes) */
@@ -605,11 +605,11 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
u32 *dataptr;
retval = register_write(dev->core, IVTV_REG_VPU, 0xFFFFFFED);
- retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
- retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_REFRESH, 0x80000640);
- retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
+ retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+ retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_REFRESH, 0x80000640);
+ retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
msleep(1);
- retval |= register_write(dev->core, IVTV_REG_APU, 0);
+ retval |= register_write(dev->core, IVTV_REG_APU, 0);
if (retval < 0)
dprintk(0, "Error with register_write\n");
@@ -657,13 +657,13 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
release_firmware(firmware);
dprintk(0, "Firmware upload successful.\n");
- retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
- retval |= register_read(dev->core, IVTV_REG_SPU, &value);
- retval |= register_write(dev->core, IVTV_REG_SPU, value & 0xFFFFFFFE);
+ retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+ retval |= register_read(dev->core, IVTV_REG_SPU, &value);
+ retval |= register_write(dev->core, IVTV_REG_SPU, value & 0xFFFFFFFE);
msleep(1);
retval |= register_read(dev->core, IVTV_REG_VPU, &value);
- retval |= register_write(dev->core, IVTV_REG_VPU, value & 0xFFFFFFE8);
+ retval |= register_write(dev->core, IVTV_REG_VPU, value & 0xFFFFFFE8);
if (retval < 0)
dprintk(0, "Error with register_write\n");
@@ -683,84 +683,560 @@ DB* DVD | MPEG2 | 720x576PAL | CBR | 600 :Good | 6000 Kbps | 25fps | M
=================================================================================================================
*DB: "DirectBurn"
*/
-static void blackbird_codec_settings(struct cx8802_dev *dev)
+
+static struct blackbird_dnr default_dnr_params = {
+ .mode = BLACKBIRD_DNR_BITS_MANUAL,
+ .type = BLACKBIRD_MEDIAN_FILTER_DISABLED,
+ .spatial = 0,
+ .temporal = 0
+};
+static struct v4l2_mpeg_compression default_mpeg_params = {
+ .st_type = V4L2_MPEG_PS_2,
+ .st_bitrate = {
+ .mode = V4L2_BITRATE_CBR,
+ .min = 0,
+ .target = 0,
+ .max = 0
+ },
+ .ts_pid_pmt = 16,
+ .ts_pid_audio = 260,
+ .ts_pid_video = 256,
+ .ts_pid_pcr = 259,
+ .ps_size = 0,
+ .au_type = V4L2_MPEG_AU_2_II,
+ .au_bitrate = {
+ .mode = V4L2_BITRATE_CBR,
+ .min = 224,
+ .target = 224,
+ .max = 224
+ },
+ .au_sample_rate = 44100,
+ .au_pesid = 0,
+ .vi_type = V4L2_MPEG_VI_2,
+ .vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3,
+ .vi_bitrate = {
+ .mode = V4L2_BITRATE_CBR,
+ .min = 4000,
+ .target = 4500,
+ .max = 6000
+ },
+ .vi_frame_rate = 25,
+ .vi_frames_per_gop = 15,
+ .vi_bframes_count = 2,
+ .vi_pesid = 0,
+ .closed_gops = 0,
+ .pulldown = 0
+};
+
+static enum blackbird_stream_type mpeg_stream_types[] = {
+ [V4L2_MPEG_SS_1] = BLACKBIRD_STREAM_MPEG1,
+ [V4L2_MPEG_PS_2] = BLACKBIRD_STREAM_PROGRAM,
+ [V4L2_MPEG_TS_2] = BLACKBIRD_STREAM_TRANSPORT,
+ [V4L2_MPEG_PS_DVD] = BLACKBIRD_STREAM_DVD,
+};
+static enum blackbird_aspect_ratio mpeg_stream_ratios[] = {
+ [V4L2_MPEG_ASPECT_SQUARE] = BLACKBIRD_ASPECT_RATIO_1_1_SQUARE,
+ [V4L2_MPEG_ASPECT_4_3] = BLACKBIRD_ASPECT_RATIO_4_3,
+ [V4L2_MPEG_ASPECT_16_9] = BLACKBIRD_ASPECT_RATIO_16_9,
+ [V4L2_MPEG_ASPECT_1_221] = BLACKBIRD_ASPECT_RATIO_221_100,
+};
+static enum blackbird_video_bitrate_type mpeg_video_bitrates[] = {
+ [V4L2_BITRATE_NONE] = BLACKBIRD_VIDEO_CBR,
+ [V4L2_BITRATE_CBR] = BLACKBIRD_VIDEO_CBR,
+ [V4L2_BITRATE_VBR] = BLACKBIRD_VIDEO_VBR,
+};
+/* find the best layer I/II bitrate to fit a given numeric value */
+struct bitrate_bits {
+ u32 bits; /* layer bits for the best fit */
+ u32 rate; /* actual numeric value for the layer best fit */
+};
+struct bitrate_approximation {
+ u32 target; /* numeric value of the rate we want */
+ struct bitrate_bits layer[2];
+};
+static struct bitrate_approximation mpeg_audio_bitrates[] = {
+ /* target layer[0].bits layer[0].rate layer[1].bits layer[1].rate */
+ { 0, { { 0, 0, }, { 0, 0, }, }, },
+ { 32, { { BLACKBIRD_AUDIO_BITS_LAYER_1_32 , 32, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_32 , 32, }, }, },
+ { 48, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 , 64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_48 , 48, }, }, },
+ { 56, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 , 64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_56 , 56, }, }, },
+ { 64, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 , 64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_64 , 64, }, }, },
+ { 80, { { BLACKBIRD_AUDIO_BITS_LAYER_1_96 , 96, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_80 , 80, }, }, },
+ { 96, { { BLACKBIRD_AUDIO_BITS_LAYER_1_96 , 96, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_96 , 96, }, }, },
+ { 112, { { BLACKBIRD_AUDIO_BITS_LAYER_1_128, 128, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_112, 112, }, }, },
+ { 128, { { BLACKBIRD_AUDIO_BITS_LAYER_1_128, 128, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_128, 128, }, }, },
+ { 160, { { BLACKBIRD_AUDIO_BITS_LAYER_1_160, 160, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_160, 160, }, }, },
+ { 192, { { BLACKBIRD_AUDIO_BITS_LAYER_1_192, 192, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_192, 192, }, }, },
+ { 224, { { BLACKBIRD_AUDIO_BITS_LAYER_1_224, 224, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_224, 224, }, }, },
+ { 256, { { BLACKBIRD_AUDIO_BITS_LAYER_1_256, 256, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_256, 256, }, }, },
+ { 288, { { BLACKBIRD_AUDIO_BITS_LAYER_1_288, 288, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_320, 320, }, }, },
+ { 320, { { BLACKBIRD_AUDIO_BITS_LAYER_1_320, 320, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_320, 320, }, }, },
+ { 352, { { BLACKBIRD_AUDIO_BITS_LAYER_1_352, 352, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
+ { 384, { { BLACKBIRD_AUDIO_BITS_LAYER_1_384, 384, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
+ { 416, { { BLACKBIRD_AUDIO_BITS_LAYER_1_416, 416, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
+ { 448, { { BLACKBIRD_AUDIO_BITS_LAYER_1_448, 448, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
+};
+static const int BITRATES_SIZE = ARRAY_SIZE(mpeg_audio_bitrates);
+
+static void blackbird_set_default_params(struct cx8802_dev *dev)
{
- int bitrate_mode = 1;
- int bitrate = 7500000;
- int bitrate_peak = 7500000;
- bitrate_mode = BLACKBIRD_VIDEO_CBR;
- bitrate = 4000*1024;
- bitrate_peak = 4000*1024;
+ struct v4l2_mpeg_compression *params = &dev->params;
+ u32 au_params;
/* assign stream type */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, BLACKBIRD_STREAM_PROGRAM);
-
- /* assign output port */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_OUTPUT_PORT, 1, 0, BLACKBIRD_OUTPUT_PORT_STREAMING); /* Host */
+ if( params->st_type >= ARRAY_SIZE(mpeg_stream_types) )
+ params->st_type = V4L2_MPEG_PS_2;
+ if( params->st_type == V4L2_MPEG_SS_1 )
+ params->vi_type = V4L2_MPEG_VI_1;
+ else
+ params->vi_type = V4L2_MPEG_VI_2;
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, mpeg_stream_types[params->st_type]);
/* assign framerate */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
-
- /* assign frame size */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_RESOLUTION, 2, 0,
- dev->height, dev->width);
+ if( params->vi_frame_rate <= 25 )
+ {
+ params->vi_frame_rate = 25;
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
+ }
+ else
+ {
+ params->vi_frame_rate = 30;
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_NTSC_30);
+ }
/* assign aspect ratio */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, BLACKBIRD_ASPECT_RATIO_4_3);
-
- /* assign bitrates */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 5, 0,
- bitrate_mode, /* mode */
- bitrate, /* bps */
- bitrate_peak / BLACKBIRD_PEAK_RATE_DIVISOR, /* peak/400 */
- BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/); /* encoding buffer, ckennedy */
+ if( params->vi_aspect_ratio >= ARRAY_SIZE(mpeg_stream_ratios) )
+ params->vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3;
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, mpeg_stream_ratios[params->vi_aspect_ratio]);
/* assign gop properties */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, 15, 3);
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, params->vi_frames_per_gop, params->vi_bframes_count+1);
+
+ /* assign gop closure */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, params->closed_gops);
/* assign 3 2 pulldown */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, BLACKBIRD_3_2_PULLDOWN_DISABLED);
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, params->pulldown);
+
+ /* make sure the params are within bounds */
+ if( params->st_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+ params->vi_bitrate.mode = V4L2_BITRATE_NONE;
+ if( params->vi_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+ params->vi_bitrate.mode = V4L2_BITRATE_NONE;
+ if( params->au_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+ params->au_bitrate.mode = V4L2_BITRATE_NONE;
/* assign audio properties */
/* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
- /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, (2<<2) | (8<<4));
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, 0 | (2 << 2) | (14 << 4)); */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0,
- BLACKBIRD_AUDIO_BITS_44100HZ |
- BLACKBIRD_AUDIO_BITS_LAYER_2 |
- BLACKBIRD_AUDIO_BITS_LAYER_2_224 |
- BLACKBIRD_AUDIO_BITS_STEREO |
+ au_params = BLACKBIRD_AUDIO_BITS_STEREO |
/* BLACKBIRD_AUDIO_BITS_BOUND_4 | */
BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE |
BLACKBIRD_AUDIO_BITS_CRC_OFF |
BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF |
- BLACKBIRD_AUDIO_BITS_COPY
- );
+ BLACKBIRD_AUDIO_BITS_COPY |
+ 0;
+ if( params->au_sample_rate <= 32000 )
+ {
+ params->au_sample_rate = 32000;
+ au_params |= BLACKBIRD_AUDIO_BITS_32000HZ;
+ }
+ else if( params->au_sample_rate <= 44100 )
+ {
+ params->au_sample_rate = 44100;
+ au_params |= BLACKBIRD_AUDIO_BITS_44100HZ;
+ }
+ else
+ {
+ params->au_sample_rate = 48000;
+ au_params |= BLACKBIRD_AUDIO_BITS_48000HZ;
+ }
+ if( params->au_type == V4L2_MPEG_AU_2_I )
+ {
+ au_params |= BLACKBIRD_AUDIO_BITS_LAYER_1;
+ }
+ else
+ {
+ /* TODO: try to handle the other formats more gracefully */
+ params->au_type = V4L2_MPEG_AU_2_II;
+ au_params |= BLACKBIRD_AUDIO_BITS_LAYER_2;
+ }
+ if( params->au_bitrate.mode )
+ {
+ int layer;
+
+ if( params->au_bitrate.mode == V4L2_BITRATE_CBR )
+ params->au_bitrate.max = params->vi_bitrate.target;
+ else
+ params->au_bitrate.target = params->vi_bitrate.max;
+
+ layer = params->au_type;
+ if( params->au_bitrate.target == 0 )
+ {
+ /* TODO: use the minimum possible bitrate instead of 0 ? */
+ au_params |= 0;
+ }
+ else if( params->au_bitrate.target >=
+ mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate )
+ {
+ /* clamp the bitrate to the max supported by the standard */
+ params->au_bitrate.target = mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate;
+ params->au_bitrate.max = params->au_bitrate.target;
+ au_params |= mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].bits;
+ }
+ else
+ {
+ /* round up to the nearest supported bitrate */
+ int i;
+ for(i = 1; i < BITRATES_SIZE; i++)
+ {
+ if( params->au_bitrate.target > mpeg_audio_bitrates[i-1].layer[layer].rate &&
+ params->au_bitrate.target <= mpeg_audio_bitrates[i].layer[layer].rate )
+ {
+ params->au_bitrate.target = mpeg_audio_bitrates[i].layer[layer].rate;
+ params->au_bitrate.max = params->au_bitrate.target;
+ au_params |= mpeg_audio_bitrates[i].layer[layer].bits;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* TODO: ??? */
+ params->au_bitrate.target = params->au_bitrate.max = 0;
+ au_params |= 0;
+ }
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0, au_params );
+
+ /* assign bitrates */
+ if( params->vi_bitrate.mode )
+ {
+ /* bitrate is set, let's figure out the cbr/vbr mess */
+ if( params->vi_bitrate.max < params->vi_bitrate.target )
+ {
+ if( params->vi_bitrate.mode == V4L2_BITRATE_CBR )
+ params->vi_bitrate.max = params->vi_bitrate.target;
+ else
+ params->vi_bitrate.target = params->vi_bitrate.max;
+ }
+ }
+ else
+ {
+ if( params->st_bitrate.max < params->st_bitrate.target )
+ {
+ if( params->st_bitrate.mode == V4L2_BITRATE_VBR )
+ params->st_bitrate.target = params->st_bitrate.max;
+ else
+ params->st_bitrate.max = params->st_bitrate.target;
+ }
+ /* calculate vi_bitrate = st_bitrate - au_bitrate */
+ params->vi_bitrate.max = params->st_bitrate.max - params->au_bitrate.max;
+ params->vi_bitrate.target = params->st_bitrate.target - params->au_bitrate.target;
+ }
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 4, 0,
+ mpeg_video_bitrates[params->vi_bitrate.mode],
+ params->vi_bitrate.target * 1000, /* kbps -> bps */
+ params->vi_bitrate.max * 1000 / BLACKBIRD_PEAK_RATE_DIVISOR, /* peak/400 */
+ BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/); /* encoding buffer, ckennedy */
+
+ /* TODO: implement the stream ID stuff:
+ ts_pid_pmt, ts_pid_audio, ts_pid_video, ts_pid_pcr,
+ ps_size, au_pesid, vi_pesid
+ */
+}
+#define CHECK_PARAM( name ) ( dev->params.name != params->name )
+#define IF_PARAM( name ) if( CHECK_PARAM( name ) )
+#define UPDATE_PARAM( name ) dev->params.name = params->name
+void blackbird_set_params(struct cx8802_dev *dev, struct v4l2_mpeg_compression *params)
+{
+ u32 au_params;
+
+ /* assign stream type */
+ if( params->st_type >= ARRAY_SIZE(mpeg_stream_types) )
+ params->st_type = V4L2_MPEG_PS_2;
+ if( params->st_type == V4L2_MPEG_SS_1 )
+ params->vi_type = V4L2_MPEG_VI_1;
+ else
+ params->vi_type = V4L2_MPEG_VI_2;
+ if( CHECK_PARAM( st_type ) || CHECK_PARAM( vi_type ) )
+ {
+ UPDATE_PARAM( st_type );
+ UPDATE_PARAM( vi_type );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, mpeg_stream_types[params->st_type]);
+ }
+
+ /* assign framerate */
+ if( params->vi_frame_rate <= 25 )
+ params->vi_frame_rate = 25;
+ else
+ params->vi_frame_rate = 30;
+ IF_PARAM( vi_frame_rate )
+ {
+ UPDATE_PARAM( vi_frame_rate );
+ if( params->vi_frame_rate == 25 )
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
+ else
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_NTSC_30);
+ }
+
+ /* assign aspect ratio */
+ if( params->vi_aspect_ratio >= ARRAY_SIZE(mpeg_stream_ratios) )
+ params->vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3;
+ IF_PARAM( vi_aspect_ratio )
+ {
+ UPDATE_PARAM( vi_aspect_ratio );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, mpeg_stream_ratios[params->vi_aspect_ratio]);
+ }
+
+ /* assign gop properties */
+ if( CHECK_PARAM( vi_frames_per_gop ) || CHECK_PARAM( vi_bframes_count ) )
+ {
+ UPDATE_PARAM( vi_frames_per_gop );
+ UPDATE_PARAM( vi_bframes_count );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, params->vi_frames_per_gop, params->vi_bframes_count+1);
+ }
/* assign gop closure */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, BLACKBIRD_GOP_CLOSURE_OFF);
+ IF_PARAM( closed_gops )
+ {
+ UPDATE_PARAM( closed_gops );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, params->closed_gops);
+ }
+
+ /* assign 3 2 pulldown */
+ IF_PARAM( pulldown )
+ {
+ UPDATE_PARAM( pulldown );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, params->pulldown);
+ }
+
+ /* make sure the params are within bounds */
+ if( params->st_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+ params->vi_bitrate.mode = V4L2_BITRATE_NONE;
+ if( params->vi_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+ params->vi_bitrate.mode = V4L2_BITRATE_NONE;
+ if( params->au_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
+ params->au_bitrate.mode = V4L2_BITRATE_NONE;
+
+ /* assign audio properties */
+ /* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
+ au_params = BLACKBIRD_AUDIO_BITS_STEREO |
+ /* BLACKBIRD_AUDIO_BITS_BOUND_4 | */
+ BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE |
+ BLACKBIRD_AUDIO_BITS_CRC_OFF |
+ BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF |
+ BLACKBIRD_AUDIO_BITS_COPY |
+ 0;
+ if( params->au_sample_rate < 32000 )
+ {
+ params->au_sample_rate = 32000;
+ au_params |= BLACKBIRD_AUDIO_BITS_32000HZ;
+ }
+ else if( params->au_sample_rate < 44100 )
+ {
+ params->au_sample_rate = 44100;
+ au_params |= BLACKBIRD_AUDIO_BITS_44100HZ;
+ }
+ else
+ {
+ params->au_sample_rate = 48000;
+ au_params |= BLACKBIRD_AUDIO_BITS_48000HZ;
+ }
+ if( params->au_type == V4L2_MPEG_AU_2_I )
+ {
+ au_params |= BLACKBIRD_AUDIO_BITS_LAYER_1;
+ }
+ else
+ {
+ /* TODO: try to handle the other formats more gracefully */
+ params->au_type = V4L2_MPEG_AU_2_II;
+ au_params |= BLACKBIRD_AUDIO_BITS_LAYER_2;
+ }
+ if( params->au_bitrate.mode )
+ {
+ int layer;
+
+ if( params->au_bitrate.mode == V4L2_BITRATE_CBR )
+ params->au_bitrate.max = params->vi_bitrate.target;
+ else
+ params->au_bitrate.target = params->vi_bitrate.max;
+
+ layer = params->au_type;
+ if( params->au_bitrate.target == 0 )
+ {
+ /* TODO: use the minimum possible bitrate instead of 0 ? */
+ au_params |= 0;
+ }
+ else if( params->au_bitrate.target >=
+ mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate )
+ {
+ /* clamp the bitrate to the max supported by the standard */
+ params->au_bitrate.target = mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate;
+ params->au_bitrate.max = params->au_bitrate.target;
+ au_params |= mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].bits;
+ }
+ else
+ {
+ /* round up to the nearest supported bitrate */
+ int i;
+ for(i = 1; i < BITRATES_SIZE; i++)
+ {
+ if( params->au_bitrate.target > mpeg_audio_bitrates[i-1].layer[layer].rate &&
+ params->au_bitrate.target <= mpeg_audio_bitrates[i].layer[layer].rate )
+ {
+ params->au_bitrate.target = mpeg_audio_bitrates[i].layer[layer].rate;
+ params->au_bitrate.max = params->au_bitrate.target;
+ au_params |= mpeg_audio_bitrates[i].layer[layer].bits;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* TODO: ??? */
+ params->au_bitrate.target = params->au_bitrate.max = 0;
+ au_params |= 0;
+ }
+ if( CHECK_PARAM( au_type ) || CHECK_PARAM( au_sample_rate )
+ || CHECK_PARAM( au_bitrate.mode ) || CHECK_PARAM( au_bitrate.max )
+ || CHECK_PARAM( au_bitrate.target )
+ )
+ {
+ UPDATE_PARAM( au_type );
+ UPDATE_PARAM( au_sample_rate );
+ UPDATE_PARAM( au_bitrate );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0, au_params );
+ }
+
+ /* assign bitrates */
+ if( params->vi_bitrate.mode )
+ {
+ /* bitrate is set, let's figure out the cbr/vbr mess */
+ if( params->vi_bitrate.max < params->vi_bitrate.target )
+ {
+ if( params->vi_bitrate.mode == V4L2_BITRATE_CBR )
+ params->vi_bitrate.max = params->vi_bitrate.target;
+ else
+ params->vi_bitrate.target = params->vi_bitrate.max;
+ }
+ }
+ else
+ {
+ if( params->st_bitrate.max < params->st_bitrate.target )
+ {
+ if( params->st_bitrate.mode == V4L2_BITRATE_VBR )
+ params->st_bitrate.target = params->st_bitrate.max;
+ else
+ params->st_bitrate.max = params->st_bitrate.target;
+ }
+ /* calculate vi_bitrate = st_bitrate - au_bitrate */
+ params->vi_bitrate.max = params->st_bitrate.max - params->au_bitrate.max;
+ params->vi_bitrate.target = params->st_bitrate.target - params->au_bitrate.target;
+ }
+ UPDATE_PARAM( st_bitrate );
+ if( CHECK_PARAM( vi_bitrate.mode ) || CHECK_PARAM( vi_bitrate.max )
+ || CHECK_PARAM( vi_bitrate.target )
+ )
+ {
+ UPDATE_PARAM( vi_bitrate );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 4, 0,
+ mpeg_video_bitrates[params->vi_bitrate.mode],
+ params->vi_bitrate.target * 1000, /* kbps -> bps */
+ params->vi_bitrate.max * 1000 / BLACKBIRD_PEAK_RATE_DIVISOR, /* peak/400 */
+ BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/); /* encoding buffer, ckennedy */
+ }
+ /* TODO: implement the stream ID stuff:
+ ts_pid_pmt, ts_pid_audio, ts_pid_video, ts_pid_pcr,
+ ps_size, au_pesid, vi_pesid
+ */
+ UPDATE_PARAM( ts_pid_pmt );
+ UPDATE_PARAM( ts_pid_audio );
+ UPDATE_PARAM( ts_pid_video );
+ UPDATE_PARAM( ts_pid_pcr );
+ UPDATE_PARAM( ps_size );
+ UPDATE_PARAM( au_pesid );
+ UPDATE_PARAM( vi_pesid );
+}
+static void blackbird_set_default_dnr_params(struct cx8802_dev *dev)
+{
/* assign dnr filter mode */
+ if( dev->dnr_params.mode > BLACKBIRD_DNR_BITS_AUTO )
+ dev->dnr_params.mode = BLACKBIRD_DNR_BITS_MANUAL;
+ if( dev->dnr_params.type > BLACKBIRD_MEDIAN_FILTER_DIAGONAL )
+ dev->dnr_params.type = BLACKBIRD_MEDIAN_FILTER_DISABLED;
blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MODE, 2, 0,
- BLACKBIRD_DNR_BITS_MANUAL,
- BLACKBIRD_MEDIAN_FILTER_DISABLED
- );
+ dev->dnr_params.mode,
+ dev->dnr_params.type
+ );
/* assign dnr filter props*/
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0, 0, 0);
+ if( dev->dnr_params.spatial > 15 )
+ dev->dnr_params.spatial = 15;
+ if( dev->dnr_params.temporal > 31 )
+ dev->dnr_params.temporal = 31;
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0,
+ dev->dnr_params.spatial,
+ dev->dnr_params.temporal
+ );
+}
+#define CHECK_DNR_PARAM( name ) ( dev->dnr_params.name != dnr_params->name )
+#define UPDATE_DNR_PARAM( name ) dev->dnr_params.name = dnr_params->name
+void blackbird_set_dnr_params(struct cx8802_dev *dev, struct blackbird_dnr* dnr_params)
+{
+ /* assign dnr filter mode */
+ /* clamp values */
+ if( dnr_params->mode > BLACKBIRD_DNR_BITS_AUTO )
+ dnr_params->mode = BLACKBIRD_DNR_BITS_MANUAL;
+ if( dnr_params->type > BLACKBIRD_MEDIAN_FILTER_DIAGONAL )
+ dnr_params->type = BLACKBIRD_MEDIAN_FILTER_DISABLED;
+ /* check if the params actually changed */
+ if( CHECK_DNR_PARAM( mode ) || CHECK_DNR_PARAM( type ) )
+ {
+ UPDATE_DNR_PARAM( mode );
+ UPDATE_DNR_PARAM( type );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MODE, 2, 0, dnr_params->mode, dnr_params->type);
+ }
+
+ /* assign dnr filter props*/
+ if( dnr_params->spatial > 15 )
+ dnr_params->spatial = 15;
+ if( dnr_params->temporal > 31 )
+ dnr_params->temporal = 31;
+ if( CHECK_DNR_PARAM( spatial ) || CHECK_DNR_PARAM( temporal ) )
+ {
+ UPDATE_DNR_PARAM( spatial );
+ UPDATE_DNR_PARAM( temporal );
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0, dnr_params->spatial, dnr_params->temporal);
+ }
+}
+
+static void blackbird_codec_settings(struct cx8802_dev *dev)
+{
+
+ /* assign output port */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_OUTPUT_PORT, 1, 0, BLACKBIRD_OUTPUT_PORT_STREAMING); /* Host */
+
+ /* assign frame size */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_RESOLUTION, 2, 0,
+ dev->height, dev->width);
/* assign coring levels (luma_h, luma_l, chroma_h, chroma_l) */
blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MEDIAN, 4, 0, 0, 255, 0, 255);
/* assign spatial filter type: luma_t: horiz_only, chroma_t: horiz_only */
blackbird_api_cmd(dev, BLACKBIRD_API_SET_SPATIAL_FILTER, 2, 0,
- BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
- BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ
- );
+ BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
+ BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ
+ );
/* assign frame drop rate */
/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_DROP_RATE, 1, 0, 0); */
+
+ blackbird_set_default_params(dev);
+ blackbird_set_default_dnr_params(dev);
}
static int blackbird_initialize_codec(struct cx8802_dev *dev)
@@ -851,15 +1327,10 @@ static int bb_buf_setup(struct videobuf_queue *q,
struct cx8802_fh *fh = q->priv_data;
fh->dev->ts_packet_size = 188 * 4; /* was: 512 */
- fh->dev->ts_packet_count = 32; /* was: 100 */
+ fh->dev->ts_packet_count = mpegbufs; /* was: 100 */
*size = fh->dev->ts_packet_size * fh->dev->ts_packet_count;
- if (0 == *count)
- *count = mpegbufs;
- if (*count < 2)
- *count = 2;
- if (*count > 32)
- *count = 32;
+ *count = fh->dev->ts_packet_count;
return 0;
}
@@ -868,7 +1339,7 @@ bb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
enum v4l2_field field)
{
struct cx8802_fh *fh = q->priv_data;
- return cx8802_buf_prepare(fh->dev, (struct cx88_buffer*)vb);
+ return cx8802_buf_prepare(fh->dev, (struct cx88_buffer*)vb, field);
}
static void
@@ -920,8 +1391,6 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
- V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_VIDEO_OVERLAY |
0;
if (UNSET != core->tuner_type)
cap->capabilities |= V4L2_CAP_TUNER;
@@ -941,27 +1410,52 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
memset(f,0,sizeof(*f));
f->index = index;
- strlcpy(f->description, "MPEG TS", sizeof(f->description));
+ 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:
- case VIDIOC_S_FMT:
- case VIDIOC_TRY_FMT:
{
- /* FIXME -- quick'n'dirty for exactly one size ... */
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.field = V4L2_FIELD_NONE;
f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = 188 * 4 * 1024; /* 1024 * 512 */ /* FIXME: BUFFER_SIZE */;
+ 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;
}
@@ -985,6 +1479,22 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_STREAMOFF:
return videobuf_streamoff(&fh->mpegq);
+ /* --- mpeg compression -------------------------------------- */
+ case VIDIOC_G_MPEGCOMP:
+ {
+ struct v4l2_mpeg_compression *f = arg;
+
+ memcpy(f,&dev->params,sizeof(*f));
+ return 0;
+ }
+ case VIDIOC_S_MPEGCOMP:
+ {
+ struct v4l2_mpeg_compression *f = arg;
+
+ blackbird_set_params(dev, f);
+ return 0;
+ }
+
default:
return cx88_do_ioctl( inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook );
}
@@ -1034,16 +1544,17 @@ static int mpeg_open(struct inode *inode, struct file *file)
file->private_data = fh;
fh->dev = dev;
- /* FIXME: locking against other video device */
- cx88_set_scale(dev->core, dev->width, dev->height,
- V4L2_FIELD_INTERLACED);
-
videobuf_queue_init(&fh->mpegq, &blackbird_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_TOP,
+ V4L2_FIELD_INTERLACED,
sizeof(struct cx88_buffer),
fh);
+
+ /* FIXME: locking against other video device */
+ cx88_set_scale(dev->core, dev->width, dev->height,
+ fh->mpegq.field);
+
return 0;
}
@@ -1173,6 +1684,8 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev,
dev->core = core;
dev->width = 720;
dev->height = 576;
+ memcpy(&dev->params,&default_mpeg_params,sizeof(default_mpeg_params));
+ memcpy(&dev->dnr_params,&default_dnr_params,sizeof(default_dnr_params));
err = cx8802_init_common(dev);
if (0 != err)
@@ -1199,7 +1712,7 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev,
static void __devexit blackbird_remove(struct pci_dev *pci_dev)
{
- struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+ struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
/* blackbird */
blackbird_unregister_video(dev);
@@ -1215,8 +1728,8 @@ static struct pci_device_id cx8802_pci_tbl[] = {
{
.vendor = 0x14f1,
.device = 0x8802,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
},{
/* --- end of list --- */
}
@@ -1224,10 +1737,10 @@ static struct pci_device_id cx8802_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
static struct pci_driver blackbird_pci_driver = {
- .name = "cx88-blackbird",
- .id_table = cx8802_pci_tbl,
- .probe = blackbird_probe,
- .remove = __devexit_p(blackbird_remove),
+ .name = "cx88-blackbird",
+ .id_table = cx8802_pci_tbl,
+ .probe = blackbird_probe,
+ .remove = __devexit_p(blackbird_remove),
.suspend = cx8802_suspend_common,
.resume = cx8802_resume_common,
};
@@ -1257,6 +1770,8 @@ module_exit(blackbird_fini);
EXPORT_SYMBOL(cx88_ioctl_hook);
EXPORT_SYMBOL(cx88_ioctl_translator);
+EXPORT_SYMBOL(blackbird_set_params);
+EXPORT_SYMBOL(blackbird_set_dnr_params);
/* ----------------------------------------------------------- */
/*
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 4da91d535a5..f2268631b7c 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -126,27 +126,27 @@ struct cx88_board cx88_boards[] = {
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
- .gpio0 = 0x03ff,
+ .gpio0 = 0x03ff,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
- .gpio0 = 0x03fe,
+ .gpio0 = 0x03fe,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
- .gpio0 = 0x03fe,
+ .gpio0 = 0x03fe,
}},
},
- [CX88_BOARD_WINFAST2000XP_EXPERT] = {
- .name = "Leadtek Winfast 2000XP Expert",
- .tuner_type = TUNER_PHILIPS_4IN1,
+ [CX88_BOARD_WINFAST2000XP_EXPERT] = {
+ .name = "Leadtek Winfast 2000XP Expert",
+ .tuner_type = TUNER_PHILIPS_4IN1,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
- .type = CX88_VMUX_TELEVISION,
- .vmux = 0,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
.gpio0 = 0x00F5e700,
.gpio1 = 0x00003004,
.gpio2 = 0x00F5e700,
@@ -165,16 +165,16 @@ struct cx88_board cx88_boards[] = {
.gpio1 = 0x00003004,
.gpio2 = 0x00F5c700,
.gpio3 = 0x02000000,
- }},
- .radio = {
- .type = CX88_RADIO,
+ }},
+ .radio = {
+ .type = CX88_RADIO,
.gpio0 = 0x00F5d700,
.gpio1 = 0x00003004,
.gpio2 = 0x00F5d700,
.gpio3 = 0x02000000,
- },
- },
- [CX88_BOARD_AVERTV_303] = {
+ },
+ },
+ [CX88_BOARD_AVERTV_STUDIO_303] = {
.name = "AverTV Studio 303 (M126)",
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
.radio_type = UNSET,
@@ -206,7 +206,7 @@ struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tda9887_conf = TDA9887_PRESENT,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER_NTSC,
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
@@ -214,32 +214,32 @@ struct cx88_board cx88_boards[] = {
.gpio1 = 0x000080c0,
.gpio2 = 0x0000ff40,
},{
- .type = CX88_VMUX_COMPOSITE1,
- .vmux = 1,
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
.gpio0 = 0x000040bf,
.gpio1 = 0x000080c0,
.gpio2 = 0x0000ff40,
},{
- .type = CX88_VMUX_SVIDEO,
- .vmux = 2,
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
.gpio0 = 0x000040bf,
.gpio1 = 0x000080c0,
.gpio2 = 0x0000ff40,
- }},
- .radio = {
+ }},
+ .radio = {
.type = CX88_RADIO,
- },
+ },
},
[CX88_BOARD_WINFAST_DV2000] = {
- .name = "Leadtek Winfast DV2000",
- .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .name = "Leadtek Winfast DV2000",
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
- .type = CX88_VMUX_TELEVISION,
- .vmux = 0,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
.gpio0 = 0x0035e700,
.gpio1 = 0x00003004,
.gpio2 = 0x0035e700,
@@ -260,14 +260,14 @@ struct cx88_board cx88_boards[] = {
.gpio2 = 0x02000000,
.gpio3 = 0x02000000,
}},
- .radio = {
+ .radio = {
.type = CX88_RADIO,
.gpio0 = 0x0035d700,
.gpio1 = 0x00007004,
.gpio2 = 0x0035d700,
.gpio3 = 0x02000000,
},
- },
+ },
[CX88_BOARD_LEADTEK_PVR2000] = {
// gpio values for PAL version from regspy by DScaler
.name = "Leadtek PVR 2000",
@@ -296,25 +296,25 @@ struct cx88_board cx88_boards[] = {
.blackbird = 1,
},
[CX88_BOARD_IODATA_GVVCP3PCI] = {
- .name = "IODATA GV-VCP3/PCI",
+ .name = "IODATA GV-VCP3/PCI",
.tuner_type = TUNER_ABSENT,
- .radio_type = UNSET,
+ .radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.input = {{
- .type = CX88_VMUX_COMPOSITE1,
- .vmux = 0,
- },{
- .type = CX88_VMUX_COMPOSITE2,
- .vmux = 1,
- },{
- .type = CX88_VMUX_SVIDEO,
- .vmux = 2,
- }},
- },
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 0,
+ },{
+ .type = CX88_VMUX_COMPOSITE2,
+ .vmux = 1,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ }},
+ },
[CX88_BOARD_PROLINK_PLAYTVPVR] = {
- .name = "Prolink PlayTV PVR",
- .tuner_type = TUNER_PHILIPS_FM1236_MK3,
+ .name = "Prolink PlayTV PVR",
+ .tuner_type = TUNER_PHILIPS_FM1236_MK3,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -348,15 +348,15 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x0000fde6,
- },{
+ },{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
}},
- .radio = {
- .type = CX88_RADIO,
+ .radio = {
+ .type = CX88_RADIO,
.gpio0 = 0x0000fde2,
- },
+ },
.blackbird = 1,
},
[CX88_BOARD_MSI_TVANYWHERE] = {
@@ -372,34 +372,34 @@ struct cx88_board cx88_boards[] = {
.gpio0 = 0x00000fbf,
.gpio2 = 0x0000fc08,
},{
- .type = CX88_VMUX_COMPOSITE1,
- .vmux = 1,
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
.gpio0 = 0x00000fbf,
.gpio2 = 0x0000fc68,
},{
- .type = CX88_VMUX_SVIDEO,
- .vmux = 2,
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
.gpio0 = 0x00000fbf,
.gpio2 = 0x0000fc68,
- }},
+ }},
},
- [CX88_BOARD_KWORLD_DVB_T] = {
- .name = "KWorld/VStream XPert DVB-T",
+ [CX88_BOARD_KWORLD_DVB_T] = {
+ .name = "KWorld/VStream XPert DVB-T",
.tuner_type = TUNER_ABSENT,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
- .type = CX88_VMUX_COMPOSITE1,
- .vmux = 1,
+ .input = {{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
.gpio0 = 0x0700,
.gpio2 = 0x0101,
- },{
- .type = CX88_VMUX_SVIDEO,
- .vmux = 2,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
.gpio0 = 0x0700,
.gpio2 = 0x0101,
- }},
+ }},
.dvb = 1,
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
@@ -425,27 +425,27 @@ struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
- .type = CX88_VMUX_TELEVISION,
- .vmux = 0,
- .gpio0 = 0x07f8,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x07f8,
},{
.type = CX88_VMUX_DEBUG,
.vmux = 0,
.gpio0 = 0x07f9, // mono from tuner chip
- },{
- .type = CX88_VMUX_COMPOSITE1,
- .vmux = 1,
- .gpio0 = 0x000007fa,
- },{
- .type = CX88_VMUX_SVIDEO,
- .vmux = 2,
- .gpio0 = 0x000007fa,
- }},
- .radio = {
- .type = CX88_RADIO,
- .gpio0 = 0x000007f8,
- },
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x000007fa,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x000007fa,
+ }},
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x000007f8,
+ },
},
[CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q] = {
.name = "DViCO FusionHDTV 3 Gold-Q",
@@ -489,28 +489,28 @@ struct cx88_board cx88_boards[] = {
}},
.dvb = 1,
},
- [CX88_BOARD_HAUPPAUGE_DVB_T1] = {
+ [CX88_BOARD_HAUPPAUGE_DVB_T1] = {
.name = "Hauppauge Nova-T DVB-T",
.tuner_type = TUNER_ABSENT,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.input = {{
- .type = CX88_VMUX_DVB,
- .vmux = 0,
- }},
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ }},
.dvb = 1,
},
- [CX88_BOARD_CONEXANT_DVB_T1] = {
+ [CX88_BOARD_CONEXANT_DVB_T1] = {
.name = "Conexant DVB-T reference design",
.tuner_type = TUNER_ABSENT,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
- .type = CX88_VMUX_DVB,
- .vmux = 0,
- }},
+ .input = {{
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ }},
.dvb = 1,
},
[CX88_BOARD_PROVIDEO_PV259] = {
@@ -543,12 +543,12 @@ struct cx88_board cx88_boards[] = {
.dvb = 1,
},
[CX88_BOARD_DNTV_LIVE_DVB_T] = {
- .name = "digitalnow DNTV Live! DVB-T",
+ .name = "digitalnow DNTV Live! DVB-T",
.tuner_type = TUNER_ABSENT,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = {{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x00000700,
@@ -705,44 +705,44 @@ struct cx88_board cx88_boards[] = {
.gpio0 = 0xbf60,
},
},
- [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = {
+ [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = {
.name = "DViCO FusionHDTV 3 Gold-T",
.tuner_type = TUNER_THOMSON_DTT7611,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.input = {{
- .type = CX88_VMUX_TELEVISION,
- .vmux = 0,
- .gpio0 = 0x97ed,
- },{
- .type = CX88_VMUX_COMPOSITE1,
- .vmux = 1,
- .gpio0 = 0x97e9,
- },{
- .type = CX88_VMUX_SVIDEO,
- .vmux = 2,
- .gpio0 = 0x97e9,
- }},
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x97ed,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x97e9,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x97e9,
+ }},
.dvb = 1,
- },
- [CX88_BOARD_ADSTECH_DVB_T_PCI] = {
- .name = "ADS Tech Instant TV DVB-T PCI",
+ },
+ [CX88_BOARD_ADSTECH_DVB_T_PCI] = {
+ .name = "ADS Tech Instant TV DVB-T PCI",
.tuner_type = TUNER_ABSENT,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.input = {{
- .type = CX88_VMUX_COMPOSITE1,
- .vmux = 1,
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
.gpio0 = 0x0700,
.gpio2 = 0x0101,
- },{
- .type = CX88_VMUX_SVIDEO,
- .vmux = 2,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
.gpio0 = 0x0700,
.gpio2 = 0x0101,
- }},
+ }},
.dvb = 1,
},
[CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = {
@@ -762,20 +762,139 @@ struct cx88_board cx88_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.input = {{
- .type = CX88_VMUX_TELEVISION,
- .vmux = 0,
- .gpio0 = 0x87fd,
- },{
- .type = CX88_VMUX_COMPOSITE1,
- .vmux = 1,
- .gpio0 = 0x87f9,
- },{
- .type = CX88_VMUX_SVIDEO,
- .vmux = 2,
- .gpio0 = 0x87f9,
- }},
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x87fd,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x87f9,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x87f9,
+ }},
+ .dvb = 1,
+ },
+ [CX88_BOARD_AVERMEDIA_ULTRATV_MC_550] = {
+ .name = "AverMedia UltraTV Media Center PCI 550",
+ .tuner_type = TUNER_PHILIPS_FM1236_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .blackbird = 1,
+ .input = {{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .gpio0 = 0x0000cd73,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 1,
+ .gpio0 = 0x0000cd73,
+ },{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 3,
+ .gpio0 = 0x0000cdb3,
+ }},
+ .radio = {
+ .type = CX88_RADIO,
+ .vmux = 2,
+ .gpio0 = 0x0000cdf3,
+ },
+ },
+ [CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD] = {
+ /* Alexander Wold <awold@bigfoot.com> */
+ .name = "Kworld V-Stream Xpert DVD",
+ .tuner_type = UNSET,
+ .input = {{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x03000000,
+ .gpio1 = 0x01000000,
+ .gpio2 = 0x02000000,
+ .gpio3 = 0x00100000,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x03000000,
+ .gpio1 = 0x01000000,
+ .gpio2 = 0x02000000,
+ .gpio3 = 0x00100000,
+ }},
+ },
+ [CX88_BOARD_ATI_HDTVWONDER] = {
+ .name = "ATI HDTV Wonder",
+ .tuner_type = TUNER_PHILIPS_TUV1236D,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x00000ff7,
+ .gpio1 = 0x000000ff,
+ .gpio2 = 0x00000001,
+ .gpio3 = 0x00000000,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x00000ffe,
+ .gpio1 = 0x000000ff,
+ .gpio2 = 0x00000001,
+ .gpio3 = 0x00000000,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x00000ffe,
+ .gpio1 = 0x000000ff,
+ .gpio2 = 0x00000001,
+ .gpio3 = 0x00000000,
+ }},
.dvb = 1,
},
+ [CX88_BOARD_WINFAST_DTV1000] = {
+ .name = "WinFast DTV1000-T",
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ }},
+ .dvb = 1,
+ },
+ [CX88_BOARD_AVERTV_303] = {
+ .name = "AVerTV 303 (M126)",
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x00ff,
+ .gpio1 = 0xe09f,
+ .gpio2 = 0x0010,
+ .gpio3 = 0x0000,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x00ff,
+ .gpio1 = 0xe05f,
+ .gpio2 = 0x0010,
+ .gpio3 = 0x0000,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x00ff,
+ .gpio1 = 0xe05f,
+ .gpio2 = 0x0010,
+ .gpio3 = 0x0000,
+ }},
+ },
};
const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
@@ -804,41 +923,41 @@ struct cx88_subid cx88_subids[] = {
.subdevice = 0x00f8,
.card = CX88_BOARD_ATI_WONDER_PRO,
},{
- .subvendor = 0x107d,
- .subdevice = 0x6611,
- .card = CX88_BOARD_WINFAST2000XP_EXPERT,
+ .subvendor = 0x107d,
+ .subdevice = 0x6611,
+ .card = CX88_BOARD_WINFAST2000XP_EXPERT,
+ },{
+ .subvendor = 0x107d,
+ .subdevice = 0x6613, /* NTSC */
+ .card = CX88_BOARD_WINFAST2000XP_EXPERT,
},{
- .subvendor = 0x107d,
- .subdevice = 0x6613, /* NTSC */
- .card = CX88_BOARD_WINFAST2000XP_EXPERT,
+ .subvendor = 0x107d,
+ .subdevice = 0x6620,
+ .card = CX88_BOARD_WINFAST_DV2000,
+ },{
+ .subvendor = 0x107d,
+ .subdevice = 0x663b,
+ .card = CX88_BOARD_LEADTEK_PVR2000,
},{
.subvendor = 0x107d,
- .subdevice = 0x6620,
- .card = CX88_BOARD_WINFAST_DV2000,
- },{
- .subvendor = 0x107d,
- .subdevice = 0x663b,
- .card = CX88_BOARD_LEADTEK_PVR2000,
- },{
- .subvendor = 0x107d,
- .subdevice = 0x663C,
- .card = CX88_BOARD_LEADTEK_PVR2000,
- },{
+ .subdevice = 0x663C,
+ .card = CX88_BOARD_LEADTEK_PVR2000,
+ },{
.subvendor = 0x1461,
.subdevice = 0x000b,
- .card = CX88_BOARD_AVERTV_303,
+ .card = CX88_BOARD_AVERTV_STUDIO_303,
},{
.subvendor = 0x1462,
.subdevice = 0x8606,
.card = CX88_BOARD_MSI_TVANYWHERE_MASTER,
},{
- .subvendor = 0x10fc,
- .subdevice = 0xd003,
- .card = CX88_BOARD_IODATA_GVVCP3PCI,
+ .subvendor = 0x10fc,
+ .subdevice = 0xd003,
+ .card = CX88_BOARD_IODATA_GVVCP3PCI,
},{
- .subvendor = 0x1043,
- .subdevice = 0x4823, /* with mpeg encoder */
- .card = CX88_BOARD_ASUS_PVR_416,
+ .subvendor = 0x1043,
+ .subdevice = 0x4823, /* with mpeg encoder */
+ .card = CX88_BOARD_ASUS_PVR_416,
},{
.subvendor = 0x17de,
.subdevice = 0x08a6,
@@ -852,43 +971,43 @@ struct cx88_subid cx88_subids[] = {
.subdevice = 0xd820,
.card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T,
},{
- .subvendor = 0x18AC,
- .subdevice = 0xDB00,
+ .subvendor = 0x18ac,
+ .subdevice = 0xdb00,
.card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1,
- },{
+ },{
.subvendor = 0x0070,
.subdevice = 0x9002,
.card = CX88_BOARD_HAUPPAUGE_DVB_T1,
- },{
+ },{
.subvendor = 0x14f1,
.subdevice = 0x0187,
.card = CX88_BOARD_CONEXANT_DVB_T1,
- },{
+ },{
.subvendor = 0x1540,
.subdevice = 0x2580,
.card = CX88_BOARD_PROVIDEO_PV259,
},{
- .subvendor = 0x18AC,
- .subdevice = 0xDB10,
+ .subvendor = 0x18ac,
+ .subdevice = 0xdb10,
.card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
},{
- .subvendor = 0x1554,
- .subdevice = 0x4811,
- .card = CX88_BOARD_PIXELVIEW,
+ .subvendor = 0x1554,
+ .subdevice = 0x4811,
+ .card = CX88_BOARD_PIXELVIEW,
},{
.subvendor = 0x7063,
.subdevice = 0x3000, /* HD-3000 card */
.card = CX88_BOARD_PCHDTV_HD3000,
},{
- .subvendor = 0x17DE,
- .subdevice = 0xA8A6,
+ .subvendor = 0x17de,
+ .subdevice = 0xa8a6,
.card = CX88_BOARD_DNTV_LIVE_DVB_T,
},{
.subvendor = 0x0070,
.subdevice = 0x2801,
.card = CX88_BOARD_HAUPPAUGE_ROSLYN,
},{
- .subvendor = 0x14F1,
+ .subvendor = 0x14f1,
.subdevice = 0x0342,
.card = CX88_BOARD_DIGITALLOGIC_MEC,
},{
@@ -899,14 +1018,30 @@ struct cx88_subid cx88_subids[] = {
.subvendor = 0x1421,
.subdevice = 0x0334,
.card = CX88_BOARD_ADSTECH_DVB_T_PCI,
- },{
+ },{
.subvendor = 0x153b,
.subdevice = 0x1166,
.card = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1,
- },{
+ },{
.subvendor = 0x18ac,
.subdevice = 0xd500,
.card = CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD,
+ },{
+ .subvendor = 0x1461,
+ .subdevice = 0x8011,
+ .card = CX88_BOARD_AVERMEDIA_ULTRATV_MC_550,
+ },{
+ .subvendor = PCI_VENDOR_ID_ATI,
+ .subdevice = 0xa101,
+ .card = CX88_BOARD_ATI_HDTVWONDER,
+ },{
+ .subvendor = 0x107d,
+ .subdevice = 0x665f,
+ .card = CX88_BOARD_WINFAST_DTV1000,
+ },{
+ .subvendor = 0x1461,
+ .subdevice = 0x000a,
+ .card = CX88_BOARD_AVERTV_303,
},
};
const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -1108,6 +1243,19 @@ void cx88_card_setup(struct cx88_core *core)
cx_clear(MO_GP0_IO, 0x00000007);
cx_set(MO_GP2_IO, 0x00000101);
break;
+ case CX88_BOARD_ATI_HDTVWONDER:
+ if (0 == core->i2c_rc) {
+ /* enable tuner */
+ int i;
+ u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
+ core->i2c_client.addr = 0x0a;
+
+ for (i = 0; i < 5; i++)
+ if (2 != i2c_master_send(&core->i2c_client,&buffer[i*2],2))
+ printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n",
+ core->name, i);
+ }
+ break;
}
if (cx88_boards[core->board].radio.type == CX88_RADIO)
core->has_radio = 1;
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index dc5c5c1f346..eb806af1718 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -31,7 +31,7 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/delay.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include "cx88.h"
@@ -153,26 +153,26 @@ static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
}
if (bpl <= sg_dma_len(sg)-offset) {
/* fits into current chunk */
- *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
- *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
- offset+=bpl;
+ *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
+ *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+ offset+=bpl;
} else {
/* scanline needs to be splitted */
- todo = bpl;
- *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
+ todo = bpl;
+ *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
(sg_dma_len(sg)-offset));
- *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
- todo -= (sg_dma_len(sg)-offset);
- offset = 0;
- sg++;
- while (todo > sg_dma_len(sg)) {
- *(rp++)=cpu_to_le32(RISC_WRITE|
+ *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+ todo -= (sg_dma_len(sg)-offset);
+ offset = 0;
+ sg++;
+ while (todo > sg_dma_len(sg)) {
+ *(rp++)=cpu_to_le32(RISC_WRITE|
sg_dma_len(sg));
- *(rp++)=cpu_to_le32(sg_dma_address(sg));
+ *(rp++)=cpu_to_le32(sg_dma_address(sg));
todo -= sg_dma_len(sg);
sg++;
}
- *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
+ *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
*(rp++)=cpu_to_le32(sg_dma_address(sg));
offset += todo;
}
@@ -309,7 +309,7 @@ struct sram_channel cx88_sram_channels[] = {
.name = "video y / packed",
.cmds_start = 0x180040,
.ctrl_start = 0x180400,
- .cdt = 0x180400 + 64,
+ .cdt = 0x180400 + 64,
.fifo_start = 0x180c00,
.fifo_size = 0x002800,
.ptr1_reg = MO_DMA21_PTR1,
@@ -321,7 +321,7 @@ struct sram_channel cx88_sram_channels[] = {
.name = "video u",
.cmds_start = 0x180080,
.ctrl_start = 0x1804a0,
- .cdt = 0x1804a0 + 64,
+ .cdt = 0x1804a0 + 64,
.fifo_start = 0x183400,
.fifo_size = 0x000800,
.ptr1_reg = MO_DMA22_PTR1,
@@ -333,7 +333,7 @@ struct sram_channel cx88_sram_channels[] = {
.name = "video v",
.cmds_start = 0x1800c0,
.ctrl_start = 0x180540,
- .cdt = 0x180540 + 64,
+ .cdt = 0x180540 + 64,
.fifo_start = 0x183c00,
.fifo_size = 0x000800,
.ptr1_reg = MO_DMA23_PTR1,
@@ -345,7 +345,7 @@ struct sram_channel cx88_sram_channels[] = {
.name = "vbi",
.cmds_start = 0x180100,
.ctrl_start = 0x1805e0,
- .cdt = 0x1805e0 + 64,
+ .cdt = 0x1805e0 + 64,
.fifo_start = 0x184400,
.fifo_size = 0x001000,
.ptr1_reg = MO_DMA24_PTR1,
@@ -357,7 +357,7 @@ struct sram_channel cx88_sram_channels[] = {
.name = "audio from",
.cmds_start = 0x180140,
.ctrl_start = 0x180680,
- .cdt = 0x180680 + 64,
+ .cdt = 0x180680 + 64,
.fifo_start = 0x185400,
.fifo_size = 0x000200,
.ptr1_reg = MO_DMA25_PTR1,
@@ -369,7 +369,7 @@ struct sram_channel cx88_sram_channels[] = {
.name = "audio to",
.cmds_start = 0x180180,
.ctrl_start = 0x180720,
- .cdt = 0x180680 + 64, /* same as audio IN */
+ .cdt = 0x180680 + 64, /* same as audio IN */
.fifo_start = 0x185400, /* same as audio IN */
.fifo_size = 0x000200, /* same as audio IN */
.ptr1_reg = MO_DMA26_PTR1,
@@ -431,7 +431,7 @@ int cx88_sram_channel_setup(struct cx88_core *core,
/* ------------------------------------------------------------------ */
/* debug helper code */
-int cx88_risc_decode(u32 risc)
+static int cx88_risc_decode(u32 risc)
{
static char *instr[16] = {
[ RISC_SYNC >> 28 ] = "sync",
@@ -845,19 +845,19 @@ static int set_tvaudio(struct cx88_core *core)
return 0;
if (V4L2_STD_PAL_BG & norm->id) {
- core->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_BG;
+ core->tvaudio = WW_BG;
} else if (V4L2_STD_PAL_DK & norm->id) {
- core->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_DK;
+ core->tvaudio = WW_DK;
} else if (V4L2_STD_PAL_I & norm->id) {
- core->tvaudio = WW_NICAM_I;
+ core->tvaudio = WW_I;
} else if (V4L2_STD_SECAM_L & norm->id) {
- core->tvaudio = WW_SYSTEM_L_AM;
+ core->tvaudio = WW_L;
} else if (V4L2_STD_SECAM_DK & norm->id) {
- core->tvaudio = WW_A2_DK;
+ core->tvaudio = WW_DK;
} else if ((V4L2_STD_NTSC_M & norm->id) ||
(V4L2_STD_PAL_M & norm->id)) {
@@ -1137,7 +1137,7 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci)
if (!core->radio_addr)
core->radio_addr = cx88_boards[core->board].radio_addr;
- printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
+ printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
core->tuner_type, core->tuner_addr<<1,
core->radio_type, core->radio_addr<<1);
@@ -1146,6 +1146,7 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci)
/* init hardware */
cx88_reset(core);
cx88_i2c_init(core,pci);
+ cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
cx88_card_setup(core);
cx88_ir_init(core,pci);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 4334744652d..9cce91ec334 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -29,7 +29,6 @@
#include <linux/file.h>
#include <linux/suspend.h>
-
#include "cx88.h"
#include "dvb-pll.h"
@@ -46,6 +45,9 @@
#ifdef HAVE_LGDT330X
# include "lgdt330x.h"
#endif
+#ifdef HAVE_NXT200X
+# include "nxt200x.h"
+#endif
MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -78,7 +80,7 @@ static int dvb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
enum v4l2_field field)
{
struct cx8802_dev *dev = q->priv_data;
- return cx8802_buf_prepare(dev, (struct cx88_buffer*)vb);
+ return cx8802_buf_prepare(dev, (struct cx88_buffer*)vb,field);
}
static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
@@ -129,7 +131,7 @@ static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
static u8 reset [] = { 0x50, 0x80 };
static u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
static u8 agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
- 0x00, 0xFF, 0x00, 0x40, 0x40 };
+ 0x00, 0xFF, 0x00, 0x40, 0x40 };
static u8 dntv_extra[] = { 0xB5, 0x7A };
static u8 capt_range_cfg[] = { 0x75, 0x32 };
@@ -285,6 +287,33 @@ static struct lgdt330x_config fusionhdtv_5_gold = {
};
#endif
+#ifdef HAVE_NXT200X
+static int nxt200x_set_ts_param(struct dvb_frontend* fe,
+ int is_punctured)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
+ return 0;
+}
+
+static int nxt200x_set_pll_input(u8* buf, int input)
+{
+ if (input)
+ buf[3] |= 0x08;
+ else
+ buf[3] &= ~0x08;
+ return 0;
+}
+
+static struct nxt200x_config ati_hdtvwonder = {
+ .demod_address = 0x0a,
+ .pll_address = 0x61,
+ .pll_desc = &dvb_pll_tuv1236d,
+ .set_pll_input = nxt200x_set_pll_input,
+ .set_ts_params = nxt200x_set_ts_param,
+};
+#endif
+
static int dvb_register(struct cx8802_dev *dev)
{
/* init struct videobuf_dvb */
@@ -300,6 +329,7 @@ static int dvb_register(struct cx8802_dev *dev)
break;
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
case CX88_BOARD_CONEXANT_DVB_T1:
+ case CX88_BOARD_WINFAST_DTV1000:
dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
&dev->core->i2c_adap);
break;
@@ -385,6 +415,12 @@ static int dvb_register(struct cx8802_dev *dev)
}
break;
#endif
+#ifdef HAVE_NXT200X
+ case CX88_BOARD_ATI_HDTVWONDER:
+ dev->dvb.frontend = nxt200x_attach(&ati_hdtvwonder,
+ &dev->core->i2c_adap);
+ break;
+#endif
default:
printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
dev->core->name);
@@ -403,6 +439,9 @@ static int dvb_register(struct cx8802_dev *dev)
/* Put the analog decoder in standby to keep it quiet */
cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+ /* Put the analog decoder in standby to keep it quiet */
+ cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+
/* register everything */
return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
}
@@ -461,7 +500,7 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev,
static void __devexit dvb_remove(struct pci_dev *pci_dev)
{
- struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+ struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
/* dvb */
videobuf_dvb_unregister(&dev->dvb);
@@ -476,8 +515,8 @@ static struct pci_device_id cx8802_pci_tbl[] = {
{
.vendor = 0x14f1,
.device = 0x8802,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
},{
/* --- end of list --- */
}
@@ -485,10 +524,10 @@ static struct pci_device_id cx8802_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
static struct pci_driver dvb_pci_driver = {
- .name = "cx88-dvb",
- .id_table = cx8802_pci_tbl,
- .probe = dvb_probe,
- .remove = __devexit_p(dvb_remove),
+ .name = "cx88-dvb",
+ .id_table = cx8802_pci_tbl,
+ .probe = dvb_probe,
+ .remove = __devexit_p(dvb_remove),
.suspend = cx8802_suspend_common,
.resume = cx8802_resume_common,
};
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 761cebd40db..9790d412f19 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -3,7 +3,7 @@
cx88-i2c.c -- all the i2c code is here
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
- & Marcus Metzler (mocm@thp.uni-koeln.de)
+ & Marcus Metzler (mocm@thp.uni-koeln.de)
(c) 2002 Yurij Sysoev <yurij@naturesoft.net>
(c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
@@ -90,7 +90,7 @@ static int cx8800_bit_getsda(void *data)
static int attach_inform(struct i2c_client *client)
{
- struct tuner_setup tun_setup;
+ struct tuner_setup tun_setup;
struct cx88_core *core = i2c_get_adapdata(client->adapter);
dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
@@ -98,7 +98,7 @@ static int attach_inform(struct i2c_client *client)
if (!client->driver->command)
return 0;
- if (core->radio_type != UNSET) {
+ if (core->radio_type != UNSET) {
if ((core->radio_addr==ADDR_UNSET)||(core->radio_addr==client->addr)) {
tun_setup.mode_mask = T_RADIO;
tun_setup.type = core->radio_type;
@@ -106,8 +106,8 @@ static int attach_inform(struct i2c_client *client)
client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
}
- }
- if (core->tuner_type != UNSET) {
+ }
+ if (core->tuner_type != UNSET) {
if ((core->tuner_addr==ADDR_UNSET)||(core->tuner_addr==client->addr)) {
tun_setup.mode_mask = T_ANALOG_TV;
@@ -116,7 +116,7 @@ static int attach_inform(struct i2c_client *client)
client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup);
}
- }
+ }
if (core->tda9887_conf)
client->driver->command(client, TDA9887_SET_CONFIG, &core->tda9887_conf);
@@ -159,7 +159,7 @@ static struct i2c_adapter cx8800_i2c_adap_template = {
};
static struct i2c_client cx8800_i2c_client_template = {
- .name = "cx88xx internal",
+ .name = "cx88xx internal",
};
static char *i2c_devs[128] = {
@@ -202,10 +202,10 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
core->i2c_adap.dev.parent = &pci->dev;
strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
- core->i2c_algo.data = core;
- i2c_set_adapdata(&core->i2c_adap,core);
- core->i2c_adap.algo_data = &core->i2c_algo;
- core->i2c_client.adapter = &core->i2c_adap;
+ core->i2c_algo.data = core;
+ i2c_set_adapdata(&core->i2c_adap,core);
+ core->i2c_adap.algo_data = &core->i2c_algo;
+ core->i2c_client.adapter = &core->i2c_adap;
cx8800_bit_setscl(core,1);
cx8800_bit_setsda(core,1);
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index c27fe4c36f6..38b12ebaa49 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -553,7 +553,7 @@ void cx88_ir_irq(struct cx88_core *core)
if ((ircode & 0xffff) != 0xeb04) { /* wrong address */
ir_dprintk("pulse distance decoded wrong address\n");
- break;
+ break;
}
if (((~ircode >> 24) & 0xff) != ((ircode >> 16) & 0xff)) { /* wrong checksum */
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index ee2300e1ae0..35e6d0c2b87 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -54,7 +54,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
{
struct cx88_core *core = dev->core;
- dprintk(0, "cx8802_start_dma %d\n", buf->vb.width);
+ dprintk(0, "cx8802_start_dma w: %d, h: %d, f: %d\n", dev->width, dev->height, buf->vb.field);
/* setup fifo + format */
cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28],
@@ -158,7 +158,8 @@ static int cx8802_restart_queue(struct cx8802_dev *dev,
/* ------------------------------------------------------------------ */
-int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf)
+int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf,
+ enum v4l2_field field)
{
int size = dev->ts_packet_size * dev->ts_packet_count;
int rc;
@@ -171,7 +172,7 @@ int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf)
buf->vb.width = dev->ts_packet_size;
buf->vb.height = dev->ts_packet_count;
buf->vb.size = size;
- buf->vb.field = V4L2_FIELD_TOP;
+ buf->vb.field = field /*V4L2_FIELD_TOP*/;
if (0 != (rc = videobuf_iolock(dev->pci,&buf->vb,NULL)))
goto fail;
@@ -315,14 +316,14 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev)
spin_unlock(&dev->slock);
}
- /* other general errors */
- if (status & 0x1f0100) {
+ /* other general errors */
+ if (status & 0x1f0100) {
dprintk( 0, "general errors: 0x%08x\n", status & 0x1f0100 );
- spin_lock(&dev->slock);
+ spin_lock(&dev->slock);
cx8802_stop_dma(dev);
- cx8802_restart_queue(dev,&dev->mpegq);
- spin_unlock(&dev->slock);
- }
+ cx8802_restart_queue(dev,&dev->mpegq);
+ spin_unlock(&dev->slock);
+ }
}
#define MAX_IRQ_LOOP 10
@@ -378,8 +379,8 @@ int cx8802_init_common(struct cx8802_dev *dev)
}
pci_read_config_byte(dev->pci, PCI_CLASS_REVISION, &dev->pci_rev);
- pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER, &dev->pci_lat);
- printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, "
+ pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER, &dev->pci_lat);
+ printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%lx\n", dev->core->name,
pci_name(dev->pci), dev->pci_rev, dev->pci->irq,
dev->pci_lat,pci_resource_start(dev->pci,0));
@@ -429,7 +430,7 @@ void cx8802_fini_common(struct cx8802_dev *dev)
int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
{
- struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
+ struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core;
/* stop mpeg dma */
diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/video/cx88/cx88-reg.h
index 0a3a62fc9bb..d3bf5b17b1d 100644
--- a/drivers/media/video/cx88/cx88-reg.h
+++ b/drivers/media/video/cx88/cx88-reg.h
@@ -3,9 +3,9 @@
cx88x-hw.h - CX2388x register offsets
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
- 2001 Michael Eskin
- 2002 Yurij Sysoev <yurij@naturesoft.net>
- 2003 Gerd Knorr <kraxel@bytesex.org>
+ 2001 Michael Eskin
+ 2002 Yurij Sysoev <yurij@naturesoft.net>
+ 2003 Gerd Knorr <kraxel@bytesex.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
@@ -728,13 +728,13 @@
#define ColorFormatGamma 0x1000
#define Interlaced 0x1
-#define NonInterlaced 0x0
+#define NonInterlaced 0x0
#define FieldEven 0x1
#define FieldOdd 0x0
-#define TGReadWriteMode 0x0
-#define TGEnableMode 0x1
+#define TGReadWriteMode 0x0
+#define TGEnableMode 0x1
#define DV_CbAlign 0x0
#define DV_Y0Align 0x1
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 2765acee028..6d9bec1c583 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -57,39 +57,38 @@
#include "cx88.h"
static unsigned int audio_debug = 0;
-module_param(audio_debug,int,0644);
-MODULE_PARM_DESC(audio_debug,"enable debug messages [audio]");
+module_param(audio_debug, int, 0644);
+MODULE_PARM_DESC(audio_debug, "enable debug messages [audio]");
#define dprintk(fmt, arg...) if (audio_debug) \
printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
/* ----------------------------------------------------------- */
-static char *aud_ctl_names[64] =
-{
- [ EN_BTSC_FORCE_MONO ] = "BTSC_FORCE_MONO",
- [ EN_BTSC_FORCE_STEREO ] = "BTSC_FORCE_STEREO",
- [ EN_BTSC_FORCE_SAP ] = "BTSC_FORCE_SAP",
- [ EN_BTSC_AUTO_STEREO ] = "BTSC_AUTO_STEREO",
- [ EN_BTSC_AUTO_SAP ] = "BTSC_AUTO_SAP",
- [ EN_A2_FORCE_MONO1 ] = "A2_FORCE_MONO1",
- [ EN_A2_FORCE_MONO2 ] = "A2_FORCE_MONO2",
- [ EN_A2_FORCE_STEREO ] = "A2_FORCE_STEREO",
- [ EN_A2_AUTO_MONO2 ] = "A2_AUTO_MONO2",
- [ EN_A2_AUTO_STEREO ] = "A2_AUTO_STEREO",
- [ EN_EIAJ_FORCE_MONO1 ] = "EIAJ_FORCE_MONO1",
- [ EN_EIAJ_FORCE_MONO2 ] = "EIAJ_FORCE_MONO2",
- [ EN_EIAJ_FORCE_STEREO ] = "EIAJ_FORCE_STEREO",
- [ EN_EIAJ_AUTO_MONO2 ] = "EIAJ_AUTO_MONO2",
- [ EN_EIAJ_AUTO_STEREO ] = "EIAJ_AUTO_STEREO",
- [ EN_NICAM_FORCE_MONO1 ] = "NICAM_FORCE_MONO1",
- [ EN_NICAM_FORCE_MONO2 ] = "NICAM_FORCE_MONO2",
- [ EN_NICAM_FORCE_STEREO ] = "NICAM_FORCE_STEREO",
- [ EN_NICAM_AUTO_MONO2 ] = "NICAM_AUTO_MONO2",
- [ EN_NICAM_AUTO_STEREO ] = "NICAM_AUTO_STEREO",
- [ EN_FMRADIO_FORCE_MONO ] = "FMRADIO_FORCE_MONO",
- [ EN_FMRADIO_FORCE_STEREO ] = "FMRADIO_FORCE_STEREO",
- [ EN_FMRADIO_AUTO_STEREO ] = "FMRADIO_AUTO_STEREO",
+static char *aud_ctl_names[64] = {
+ [EN_BTSC_FORCE_MONO] = "BTSC_FORCE_MONO",
+ [EN_BTSC_FORCE_STEREO] = "BTSC_FORCE_STEREO",
+ [EN_BTSC_FORCE_SAP] = "BTSC_FORCE_SAP",
+ [EN_BTSC_AUTO_STEREO] = "BTSC_AUTO_STEREO",
+ [EN_BTSC_AUTO_SAP] = "BTSC_AUTO_SAP",
+ [EN_A2_FORCE_MONO1] = "A2_FORCE_MONO1",
+ [EN_A2_FORCE_MONO2] = "A2_FORCE_MONO2",
+ [EN_A2_FORCE_STEREO] = "A2_FORCE_STEREO",
+ [EN_A2_AUTO_MONO2] = "A2_AUTO_MONO2",
+ [EN_A2_AUTO_STEREO] = "A2_AUTO_STEREO",
+ [EN_EIAJ_FORCE_MONO1] = "EIAJ_FORCE_MONO1",
+ [EN_EIAJ_FORCE_MONO2] = "EIAJ_FORCE_MONO2",
+ [EN_EIAJ_FORCE_STEREO] = "EIAJ_FORCE_STEREO",
+ [EN_EIAJ_AUTO_MONO2] = "EIAJ_AUTO_MONO2",
+ [EN_EIAJ_AUTO_STEREO] = "EIAJ_AUTO_STEREO",
+ [EN_NICAM_FORCE_MONO1] = "NICAM_FORCE_MONO1",
+ [EN_NICAM_FORCE_MONO2] = "NICAM_FORCE_MONO2",
+ [EN_NICAM_FORCE_STEREO] = "NICAM_FORCE_STEREO",
+ [EN_NICAM_AUTO_MONO2] = "NICAM_AUTO_MONO2",
+ [EN_NICAM_AUTO_STEREO] = "NICAM_AUTO_STEREO",
+ [EN_FMRADIO_FORCE_MONO] = "FMRADIO_FORCE_MONO",
+ [EN_FMRADIO_FORCE_STEREO] = "FMRADIO_FORCE_STEREO",
+ [EN_FMRADIO_AUTO_STEREO] = "FMRADIO_AUTO_STEREO",
};
struct rlist {
@@ -97,8 +96,7 @@ struct rlist {
u32 val;
};
-static void set_audio_registers(struct cx88_core *core,
- const struct rlist *l)
+static void set_audio_registers(struct cx88_core *core, const struct rlist *l)
{
int i;
@@ -119,17 +117,18 @@ static void set_audio_registers(struct cx88_core *core,
}
}
-static void set_audio_start(struct cx88_core *core,
- u32 mode)
+static void set_audio_start(struct cx88_core *core, u32 mode)
{
// mute
- cx_write(AUD_VOL_CTL, (1 << 6));
+ cx_write(AUD_VOL_CTL, (1 << 6));
// start programming
- cx_write(AUD_CTL, 0x0000);
- cx_write(AUD_INIT, mode);
- cx_write(AUD_INIT_LD, 0x0001);
- cx_write(AUD_SOFT_RESET, 0x0001);
+ cx_write(MO_AUD_DMACNTRL, 0x0000);
+ msleep(100);
+ //cx_write(AUD_CTL, 0x0000);
+ cx_write(AUD_INIT, mode);
+ cx_write(AUD_INIT_LD, 0x0001);
+ cx_write(AUD_SOFT_RESET, 0x0001);
}
static void set_audio_finish(struct cx88_core *core, u32 ctl)
@@ -148,12 +147,13 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
cx_write(AUD_I2SCNTL, 0);
//cx_write(AUD_APB_IN_RATE_ADJ, 0);
} else {
- ctl |= EN_DAC_ENABLE;
- cx_write(AUD_CTL, ctl);
+ ctl |= EN_DAC_ENABLE;
+ cx_write(AUD_CTL, ctl);
}
/* finish programming */
cx_write(AUD_SOFT_RESET, 0x0000);
+ cx_write(MO_AUD_DMACNTRL, 0x0003);
/* unmute */
volume = cx_sread(SHADOW_AUD_VOL_CTL);
@@ -162,486 +162,463 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
/* ----------------------------------------------------------- */
-static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap, u32 mode)
+static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap,
+ u32 mode)
{
static const struct rlist btsc[] = {
- { AUD_AFE_12DB_EN, 0x00000001 },
- { AUD_OUT1_SEL, 0x00000013 },
- { AUD_OUT1_SHIFT, 0x00000000 },
- { AUD_POLY0_DDS_CONSTANT, 0x0012010c },
- { AUD_DMD_RA_DDS, 0x00c3e7aa },
- { AUD_DBX_IN_GAIN, 0x00004734 },
- { AUD_DBX_WBE_GAIN, 0x00004640 },
- { AUD_DBX_SE_GAIN, 0x00008d31 },
- { AUD_DCOC_0_SRC, 0x0000001a },
- { AUD_IIR1_4_SEL, 0x00000021 },
- { AUD_DCOC_PASS_IN, 0x00000003 },
- { AUD_DCOC_0_SHIFT_IN0, 0x0000000a },
- { AUD_DCOC_0_SHIFT_IN1, 0x00000008 },
- { AUD_DCOC_1_SHIFT_IN0, 0x0000000a },
- { AUD_DCOC_1_SHIFT_IN1, 0x00000008 },
- { AUD_DN0_FREQ, 0x0000283b },
- { AUD_DN2_SRC_SEL, 0x00000008 },
- { AUD_DN2_FREQ, 0x00003000 },
- { AUD_DN2_AFC, 0x00000002 },
- { AUD_DN2_SHFT, 0x00000000 },
- { AUD_IIR2_2_SEL, 0x00000020 },
- { AUD_IIR2_2_SHIFT, 0x00000000 },
- { AUD_IIR2_3_SEL, 0x0000001f },
- { AUD_IIR2_3_SHIFT, 0x00000000 },
- { AUD_CRDC1_SRC_SEL, 0x000003ce },
- { AUD_CRDC1_SHIFT, 0x00000000 },
- { AUD_CORDIC_SHIFT_1, 0x00000007 },
- { AUD_DCOC_1_SRC, 0x0000001b },
- { AUD_DCOC1_SHIFT, 0x00000000 },
- { AUD_RDSI_SEL, 0x00000008 },
- { AUD_RDSQ_SEL, 0x00000008 },
- { AUD_RDSI_SHIFT, 0x00000000 },
- { AUD_RDSQ_SHIFT, 0x00000000 },
- { AUD_POLYPH80SCALEFAC, 0x00000003 },
+ {AUD_AFE_12DB_EN, 0x00000001},
+ {AUD_OUT1_SEL, 0x00000013},
+ {AUD_OUT1_SHIFT, 0x00000000},
+ {AUD_POLY0_DDS_CONSTANT, 0x0012010c},
+ {AUD_DMD_RA_DDS, 0x00c3e7aa},
+ {AUD_DBX_IN_GAIN, 0x00004734},
+ {AUD_DBX_WBE_GAIN, 0x00004640},
+ {AUD_DBX_SE_GAIN, 0x00008d31},
+ {AUD_DCOC_0_SRC, 0x0000001a},
+ {AUD_IIR1_4_SEL, 0x00000021},
+ {AUD_DCOC_PASS_IN, 0x00000003},
+ {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+ {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+ {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+ {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+ {AUD_DN0_FREQ, 0x0000283b},
+ {AUD_DN2_SRC_SEL, 0x00000008},
+ {AUD_DN2_FREQ, 0x00003000},
+ {AUD_DN2_AFC, 0x00000002},
+ {AUD_DN2_SHFT, 0x00000000},
+ {AUD_IIR2_2_SEL, 0x00000020},
+ {AUD_IIR2_2_SHIFT, 0x00000000},
+ {AUD_IIR2_3_SEL, 0x0000001f},
+ {AUD_IIR2_3_SHIFT, 0x00000000},
+ {AUD_CRDC1_SRC_SEL, 0x000003ce},
+ {AUD_CRDC1_SHIFT, 0x00000000},
+ {AUD_CORDIC_SHIFT_1, 0x00000007},
+ {AUD_DCOC_1_SRC, 0x0000001b},
+ {AUD_DCOC1_SHIFT, 0x00000000},
+ {AUD_RDSI_SEL, 0x00000008},
+ {AUD_RDSQ_SEL, 0x00000008},
+ {AUD_RDSI_SHIFT, 0x00000000},
+ {AUD_RDSQ_SHIFT, 0x00000000},
+ {AUD_POLYPH80SCALEFAC, 0x00000003},
{ /* end of list */ },
};
static const struct rlist btsc_sap[] = {
- { AUD_AFE_12DB_EN, 0x00000001 },
- { AUD_DBX_IN_GAIN, 0x00007200 },
- { AUD_DBX_WBE_GAIN, 0x00006200 },
- { AUD_DBX_SE_GAIN, 0x00006200 },
- { AUD_IIR1_1_SEL, 0x00000000 },
- { AUD_IIR1_3_SEL, 0x00000001 },
- { AUD_DN1_SRC_SEL, 0x00000007 },
- { AUD_IIR1_4_SHIFT, 0x00000006 },
- { AUD_IIR2_1_SHIFT, 0x00000000 },
- { AUD_IIR2_2_SHIFT, 0x00000000 },
- { AUD_IIR3_0_SHIFT, 0x00000000 },
- { AUD_IIR3_1_SHIFT, 0x00000000 },
- { AUD_IIR3_0_SEL, 0x0000000d },
- { AUD_IIR3_1_SEL, 0x0000000e },
- { AUD_DEEMPH1_SRC_SEL, 0x00000014 },
- { AUD_DEEMPH1_SHIFT, 0x00000000 },
- { AUD_DEEMPH1_G0, 0x00004000 },
- { AUD_DEEMPH1_A0, 0x00000000 },
- { AUD_DEEMPH1_B0, 0x00000000 },
- { AUD_DEEMPH1_A1, 0x00000000 },
- { AUD_DEEMPH1_B1, 0x00000000 },
- { AUD_OUT0_SEL, 0x0000003f },
- { AUD_OUT1_SEL, 0x0000003f },
- { AUD_DN1_AFC, 0x00000002 },
- { AUD_DCOC_0_SHIFT_IN0, 0x0000000a },
- { AUD_DCOC_0_SHIFT_IN1, 0x00000008 },
- { AUD_DCOC_1_SHIFT_IN0, 0x0000000a },
- { AUD_DCOC_1_SHIFT_IN1, 0x00000008 },
- { AUD_IIR1_0_SEL, 0x0000001d },
- { AUD_IIR1_2_SEL, 0x0000001e },
- { AUD_IIR2_1_SEL, 0x00000002 },
- { AUD_IIR2_2_SEL, 0x00000004 },
- { AUD_IIR3_2_SEL, 0x0000000f },
- { AUD_DCOC2_SHIFT, 0x00000001 },
- { AUD_IIR3_2_SHIFT, 0x00000001 },
- { AUD_DEEMPH0_SRC_SEL, 0x00000014 },
- { AUD_CORDIC_SHIFT_1, 0x00000006 },
- { AUD_POLY0_DDS_CONSTANT, 0x000e4db2 },
- { AUD_DMD_RA_DDS, 0x00f696e6 },
- { AUD_IIR2_3_SEL, 0x00000025 },
- { AUD_IIR1_4_SEL, 0x00000021 },
- { AUD_DN1_FREQ, 0x0000c965 },
- { AUD_DCOC_PASS_IN, 0x00000003 },
- { AUD_DCOC_0_SRC, 0x0000001a },
- { AUD_DCOC_1_SRC, 0x0000001b },
- { AUD_DCOC1_SHIFT, 0x00000000 },
- { AUD_RDSI_SEL, 0x00000009 },
- { AUD_RDSQ_SEL, 0x00000009 },
- { AUD_RDSI_SHIFT, 0x00000000 },
- { AUD_RDSQ_SHIFT, 0x00000000 },
- { AUD_POLYPH80SCALEFAC, 0x00000003 },
+ {AUD_AFE_12DB_EN, 0x00000001},
+ {AUD_DBX_IN_GAIN, 0x00007200},
+ {AUD_DBX_WBE_GAIN, 0x00006200},
+ {AUD_DBX_SE_GAIN, 0x00006200},
+ {AUD_IIR1_1_SEL, 0x00000000},
+ {AUD_IIR1_3_SEL, 0x00000001},
+ {AUD_DN1_SRC_SEL, 0x00000007},
+ {AUD_IIR1_4_SHIFT, 0x00000006},
+ {AUD_IIR2_1_SHIFT, 0x00000000},
+ {AUD_IIR2_2_SHIFT, 0x00000000},
+ {AUD_IIR3_0_SHIFT, 0x00000000},
+ {AUD_IIR3_1_SHIFT, 0x00000000},
+ {AUD_IIR3_0_SEL, 0x0000000d},
+ {AUD_IIR3_1_SEL, 0x0000000e},
+ {AUD_DEEMPH1_SRC_SEL, 0x00000014},
+ {AUD_DEEMPH1_SHIFT, 0x00000000},
+ {AUD_DEEMPH1_G0, 0x00004000},
+ {AUD_DEEMPH1_A0, 0x00000000},
+ {AUD_DEEMPH1_B0, 0x00000000},
+ {AUD_DEEMPH1_A1, 0x00000000},
+ {AUD_DEEMPH1_B1, 0x00000000},
+ {AUD_OUT0_SEL, 0x0000003f},
+ {AUD_OUT1_SEL, 0x0000003f},
+ {AUD_DN1_AFC, 0x00000002},
+ {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+ {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+ {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+ {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+ {AUD_IIR1_0_SEL, 0x0000001d},
+ {AUD_IIR1_2_SEL, 0x0000001e},
+ {AUD_IIR2_1_SEL, 0x00000002},
+ {AUD_IIR2_2_SEL, 0x00000004},
+ {AUD_IIR3_2_SEL, 0x0000000f},
+ {AUD_DCOC2_SHIFT, 0x00000001},
+ {AUD_IIR3_2_SHIFT, 0x00000001},
+ {AUD_DEEMPH0_SRC_SEL, 0x00000014},
+ {AUD_CORDIC_SHIFT_1, 0x00000006},
+ {AUD_POLY0_DDS_CONSTANT, 0x000e4db2},
+ {AUD_DMD_RA_DDS, 0x00f696e6},
+ {AUD_IIR2_3_SEL, 0x00000025},
+ {AUD_IIR1_4_SEL, 0x00000021},
+ {AUD_DN1_FREQ, 0x0000c965},
+ {AUD_DCOC_PASS_IN, 0x00000003},
+ {AUD_DCOC_0_SRC, 0x0000001a},
+ {AUD_DCOC_1_SRC, 0x0000001b},
+ {AUD_DCOC1_SHIFT, 0x00000000},
+ {AUD_RDSI_SEL, 0x00000009},
+ {AUD_RDSQ_SEL, 0x00000009},
+ {AUD_RDSI_SHIFT, 0x00000000},
+ {AUD_RDSQ_SHIFT, 0x00000000},
+ {AUD_POLYPH80SCALEFAC, 0x00000003},
{ /* end of list */ },
};
mode |= EN_FMRADIO_EN_RDS;
if (sap) {
- dprintk("%s SAP (status: unknown)\n",__FUNCTION__);
- set_audio_start(core, SEL_SAP);
+ dprintk("%s SAP (status: unknown)\n", __FUNCTION__);
+ set_audio_start(core, SEL_SAP);
set_audio_registers(core, btsc_sap);
set_audio_finish(core, mode);
} else {
- dprintk("%s (status: known-good)\n",__FUNCTION__);
- set_audio_start(core, SEL_BTSC);
+ dprintk("%s (status: known-good)\n", __FUNCTION__);
+ set_audio_start(core, SEL_BTSC);
set_audio_registers(core, btsc);
set_audio_finish(core, mode);
}
}
-
-static void set_audio_standard_NICAM_L(struct cx88_core *core, int stereo)
+static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode)
{
- /* This is probably weird..
- * Let's operate and find out. */
-
- static const struct rlist nicam_l_mono[] = {
- { AUD_ERRLOGPERIOD_R, 0x00000064 },
- { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF },
- { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F },
- { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F },
-
- { AUD_PDF_DDS_CNST_BYTE2, 0x48 },
- { AUD_PDF_DDS_CNST_BYTE1, 0x3D },
- { AUD_QAM_MODE, 0x00 },
- { AUD_PDF_DDS_CNST_BYTE0, 0xf5 },
- { AUD_PHACC_FREQ_8MSB, 0x3a },
- { AUD_PHACC_FREQ_8LSB, 0x4a },
-
- { AUD_DEEMPHGAIN_R, 0x6680 },
- { AUD_DEEMPHNUMER1_R, 0x353DE },
- { AUD_DEEMPHNUMER2_R, 0x1B1 },
- { AUD_DEEMPHDENOM1_R, 0x0F3D0 },
- { AUD_DEEMPHDENOM2_R, 0x0 },
- { AUD_FM_MODE_ENABLE, 0x7 },
- { AUD_POLYPH80SCALEFAC, 0x3 },
- { AUD_AFE_12DB_EN, 0x1 },
- { AAGC_GAIN, 0x0 },
- { AAGC_HYST, 0x18 },
- { AAGC_DEF, 0x20 },
- { AUD_DN0_FREQ, 0x0 },
- { AUD_POLY0_DDS_CONSTANT, 0x0E4DB2 },
- { AUD_DCOC_0_SRC, 0x21 },
- { AUD_IIR1_0_SEL, 0x0 },
- { AUD_IIR1_0_SHIFT, 0x7 },
- { AUD_IIR1_1_SEL, 0x2 },
- { AUD_IIR1_1_SHIFT, 0x0 },
- { AUD_DCOC_1_SRC, 0x3 },
- { AUD_DCOC1_SHIFT, 0x0 },
- { AUD_DCOC_PASS_IN, 0x0 },
- { AUD_IIR1_2_SEL, 0x23 },
- { AUD_IIR1_2_SHIFT, 0x0 },
- { AUD_IIR1_3_SEL, 0x4 },
- { AUD_IIR1_3_SHIFT, 0x7 },
- { AUD_IIR1_4_SEL, 0x5 },
- { AUD_IIR1_4_SHIFT, 0x7 },
- { AUD_IIR3_0_SEL, 0x7 },
- { AUD_IIR3_0_SHIFT, 0x0 },
- { AUD_DEEMPH0_SRC_SEL, 0x11 },
- { AUD_DEEMPH0_SHIFT, 0x0 },
- { AUD_DEEMPH0_G0, 0x7000 },
- { AUD_DEEMPH0_A0, 0x0 },
- { AUD_DEEMPH0_B0, 0x0 },
- { AUD_DEEMPH0_A1, 0x0 },
- { AUD_DEEMPH0_B1, 0x0 },
- { AUD_DEEMPH1_SRC_SEL, 0x11 },
- { AUD_DEEMPH1_SHIFT, 0x0 },
- { AUD_DEEMPH1_G0, 0x7000 },
- { AUD_DEEMPH1_A0, 0x0 },
- { AUD_DEEMPH1_B0, 0x0 },
- { AUD_DEEMPH1_A1, 0x0 },
- { AUD_DEEMPH1_B1, 0x0 },
- { AUD_OUT0_SEL, 0x3F },
- { AUD_OUT1_SEL, 0x3F },
- { AUD_DMD_RA_DDS, 0x0F5C285 },
- { AUD_PLL_INT, 0x1E },
- { AUD_PLL_DDS, 0x0 },
- { AUD_PLL_FRAC, 0x0E542 },
-
- // setup QAM registers
- { AUD_RATE_ADJ1, 0x00000100 },
- { AUD_RATE_ADJ2, 0x00000200 },
- { AUD_RATE_ADJ3, 0x00000300 },
- { AUD_RATE_ADJ4, 0x00000400 },
- { AUD_RATE_ADJ5, 0x00000500 },
- { AUD_RATE_THRES_DMD, 0x000000C0 },
+ static const struct rlist nicam_l[] = {
+ {AUD_AFE_12DB_EN, 0x00000001},
+ {AUD_RATE_ADJ1, 0x00000060},
+ {AUD_RATE_ADJ2, 0x000000F9},
+ {AUD_RATE_ADJ3, 0x000001CC},
+ {AUD_RATE_ADJ4, 0x000002B3},
+ {AUD_RATE_ADJ5, 0x00000726},
+ {AUD_DEEMPHDENOM1_R, 0x0000F3D0},
+ {AUD_DEEMPHDENOM2_R, 0x00000000},
+ {AUD_ERRLOGPERIOD_R, 0x00000064},
+ {AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF},
+ {AUD_ERRINTRPTTHSHLD2_R, 0x0000001F},
+ {AUD_ERRINTRPTTHSHLD3_R, 0x0000000F},
+ {AUD_POLYPH80SCALEFAC, 0x00000003},
+ {AUD_DMD_RA_DDS, 0x00C00000},
+ {AUD_PLL_INT, 0x0000001E},
+ {AUD_PLL_DDS, 0x00000000},
+ {AUD_PLL_FRAC, 0x0000E542},
+ {AUD_START_TIMER, 0x00000000},
+ {AUD_DEEMPHNUMER1_R, 0x000353DE},
+ {AUD_DEEMPHNUMER2_R, 0x000001B1},
+ {AUD_PDF_DDS_CNST_BYTE2, 0x06},
+ {AUD_PDF_DDS_CNST_BYTE1, 0x82},
+ {AUD_PDF_DDS_CNST_BYTE0, 0x12},
+ {AUD_QAM_MODE, 0x05},
+ {AUD_PHACC_FREQ_8MSB, 0x34},
+ {AUD_PHACC_FREQ_8LSB, 0x4C},
+ {AUD_DEEMPHGAIN_R, 0x00006680},
+ {AUD_RATE_THRES_DMD, 0x000000C0},
{ /* end of list */ },
};
- static const struct rlist nicam_l[] = {
- // setup QAM registers
- { AUD_RATE_ADJ1, 0x00000060 },
- { AUD_RATE_ADJ2, 0x000000F9 },
- { AUD_RATE_ADJ3, 0x000001CC },
- { AUD_RATE_ADJ4, 0x000002B3 },
- { AUD_RATE_ADJ5, 0x00000726 },
- { AUD_DEEMPHDENOM1_R, 0x0000F3D0 },
- { AUD_DEEMPHDENOM2_R, 0x00000000 },
- { AUD_ERRLOGPERIOD_R, 0x00000064 },
- { AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF },
- { AUD_ERRINTRPTTHSHLD2_R, 0x0000001F },
- { AUD_ERRINTRPTTHSHLD3_R, 0x0000000F },
- { AUD_POLYPH80SCALEFAC, 0x00000003 },
- { AUD_DMD_RA_DDS, 0x00C00000 },
- { AUD_PLL_INT, 0x0000001E },
- { AUD_PLL_DDS, 0x00000000 },
- { AUD_PLL_FRAC, 0x0000E542 },
- { AUD_START_TIMER, 0x00000000 },
- { AUD_DEEMPHNUMER1_R, 0x000353DE },
- { AUD_DEEMPHNUMER2_R, 0x000001B1 },
- { AUD_PDF_DDS_CNST_BYTE2, 0x06 },
- { AUD_PDF_DDS_CNST_BYTE1, 0x82 },
- { AUD_QAM_MODE, 0x05 },
- { AUD_PDF_DDS_CNST_BYTE0, 0x12 },
- { AUD_PHACC_FREQ_8MSB, 0x34 },
- { AUD_PHACC_FREQ_8LSB, 0x4C },
- { AUD_DEEMPHGAIN_R, 0x00006680 },
- { AUD_RATE_THRES_DMD, 0x000000C0 },
+ static const struct rlist nicam_bgdki_common[] = {
+ {AUD_AFE_12DB_EN, 0x00000001},
+ {AUD_RATE_ADJ1, 0x00000010},
+ {AUD_RATE_ADJ2, 0x00000040},
+ {AUD_RATE_ADJ3, 0x00000100},
+ {AUD_RATE_ADJ4, 0x00000400},
+ {AUD_RATE_ADJ5, 0x00001000},
+ //{ AUD_DMD_RA_DDS, 0x00c0d5ce },
+ {AUD_ERRLOGPERIOD_R, 0x00000fff},
+ {AUD_ERRINTRPTTHSHLD1_R, 0x000003ff},
+ {AUD_ERRINTRPTTHSHLD2_R, 0x000000ff},
+ {AUD_ERRINTRPTTHSHLD3_R, 0x0000003f},
+ {AUD_POLYPH80SCALEFAC, 0x00000003},
+ {AUD_DEEMPHGAIN_R, 0x000023c2},
+ {AUD_DEEMPHNUMER1_R, 0x0002a7bc},
+ {AUD_DEEMPHNUMER2_R, 0x0003023e},
+ {AUD_DEEMPHDENOM1_R, 0x0000f3d0},
+ {AUD_DEEMPHDENOM2_R, 0x00000000},
+ {AUD_PDF_DDS_CNST_BYTE2, 0x06},
+ {AUD_PDF_DDS_CNST_BYTE1, 0x82},
+ {AUD_QAM_MODE, 0x05},
{ /* end of list */ },
- } ;
- dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo);
-
- if (!stereo) {
- /* AM Mono */
- set_audio_start(core, SEL_A2);
- set_audio_registers(core, nicam_l_mono);
- set_audio_finish(core, EN_A2_FORCE_MONO1);
- } else {
- /* Nicam Stereo */
- set_audio_start(core, SEL_NICAM);
- set_audio_registers(core, nicam_l);
- set_audio_finish(core, 0x1924); /* FIXME */
- }
-}
+ };
-static void set_audio_standard_PAL_I(struct cx88_core *core, int stereo)
-{
- static const struct rlist pal_i_fm_mono[] = {
- {AUD_ERRLOGPERIOD_R, 0x00000064},
- {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
- {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
- {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
- {AUD_PDF_DDS_CNST_BYTE2, 0x06},
- {AUD_PDF_DDS_CNST_BYTE1, 0x82},
- {AUD_PDF_DDS_CNST_BYTE0, 0x12},
- {AUD_QAM_MODE, 0x05},
- {AUD_PHACC_FREQ_8MSB, 0x3a},
- {AUD_PHACC_FREQ_8LSB, 0x93},
- {AUD_DMD_RA_DDS, 0x002a4f2f},
- {AUD_PLL_INT, 0x0000001e},
- {AUD_PLL_DDS, 0x00000004},
- {AUD_PLL_FRAC, 0x0000e542},
- {AUD_RATE_ADJ1, 0x00000100},
- {AUD_RATE_ADJ2, 0x00000200},
- {AUD_RATE_ADJ3, 0x00000300},
- {AUD_RATE_ADJ4, 0x00000400},
- {AUD_RATE_ADJ5, 0x00000500},
- {AUD_THR_FR, 0x00000000},
- {AUD_PILOT_BQD_1_K0, 0x0000755b},
- {AUD_PILOT_BQD_1_K1, 0x00551340},
- {AUD_PILOT_BQD_1_K2, 0x006d30be},
- {AUD_PILOT_BQD_1_K3, 0xffd394af},
- {AUD_PILOT_BQD_1_K4, 0x00400000},
- {AUD_PILOT_BQD_2_K0, 0x00040000},
- {AUD_PILOT_BQD_2_K1, 0x002a4841},
- {AUD_PILOT_BQD_2_K2, 0x00400000},
- {AUD_PILOT_BQD_2_K3, 0x00000000},
- {AUD_PILOT_BQD_2_K4, 0x00000000},
- {AUD_MODE_CHG_TIMER, 0x00000060},
- {AUD_AFE_12DB_EN, 0x00000001},
- {AAGC_HYST, 0x0000000a},
- {AUD_CORDIC_SHIFT_0, 0x00000007},
- {AUD_CORDIC_SHIFT_1, 0x00000007},
- {AUD_C1_UP_THR, 0x00007000},
- {AUD_C1_LO_THR, 0x00005400},
- {AUD_C2_UP_THR, 0x00005400},
- {AUD_C2_LO_THR, 0x00003000},
- {AUD_DCOC_0_SRC, 0x0000001a},
- {AUD_DCOC0_SHIFT, 0x00000000},
- {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
- {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
- {AUD_DCOC_PASS_IN, 0x00000003},
- {AUD_IIR3_0_SEL, 0x00000021},
- {AUD_DN2_AFC, 0x00000002},
- {AUD_DCOC_1_SRC, 0x0000001b},
- {AUD_DCOC1_SHIFT, 0x00000000},
- {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
- {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
- {AUD_IIR3_1_SEL, 0x00000023},
- {AUD_DN0_FREQ, 0x000035a3},
- {AUD_DN2_FREQ, 0x000029c7},
- {AUD_CRDC0_SRC_SEL, 0x00000511},
- {AUD_IIR1_0_SEL, 0x00000001},
- {AUD_IIR1_1_SEL, 0x00000000},
- {AUD_IIR3_2_SEL, 0x00000003},
- {AUD_IIR3_2_SHIFT, 0x00000000},
- {AUD_IIR3_0_SEL, 0x00000002},
- {AUD_IIR2_0_SEL, 0x00000021},
- {AUD_IIR2_0_SHIFT, 0x00000002},
- {AUD_DEEMPH0_SRC_SEL, 0x0000000b},
- {AUD_DEEMPH1_SRC_SEL, 0x0000000b},
- {AUD_POLYPH80SCALEFAC, 0x00000001},
- {AUD_START_TIMER, 0x00000000},
- { /* end of list */ },
- };
-
- static const struct rlist pal_i_nicam[] = {
- { AUD_RATE_ADJ1, 0x00000010 },
- { AUD_RATE_ADJ2, 0x00000040 },
- { AUD_RATE_ADJ3, 0x00000100 },
- { AUD_RATE_ADJ4, 0x00000400 },
- { AUD_RATE_ADJ5, 0x00001000 },
- // { AUD_DMD_RA_DDS, 0x00c0d5ce },
- { AUD_DEEMPHGAIN_R, 0x000023c2 },
- { AUD_DEEMPHNUMER1_R, 0x0002a7bc },
- { AUD_DEEMPHNUMER2_R, 0x0003023e },
- { AUD_DEEMPHDENOM1_R, 0x0000f3d0 },
- { AUD_DEEMPHDENOM2_R, 0x00000000 },
- { AUD_DEEMPHDENOM2_R, 0x00000000 },
- { AUD_ERRLOGPERIOD_R, 0x00000fff },
- { AUD_ERRINTRPTTHSHLD1_R, 0x000003ff },
- { AUD_ERRINTRPTTHSHLD2_R, 0x000000ff },
- { AUD_ERRINTRPTTHSHLD3_R, 0x0000003f },
- { AUD_POLYPH80SCALEFAC, 0x00000003 },
- { AUD_PDF_DDS_CNST_BYTE2, 0x06 },
- { AUD_PDF_DDS_CNST_BYTE1, 0x82 },
- { AUD_PDF_DDS_CNST_BYTE0, 0x16 },
- { AUD_QAM_MODE, 0x05 },
- { AUD_PDF_DDS_CNST_BYTE0, 0x12 },
- { AUD_PHACC_FREQ_8MSB, 0x3a },
- { AUD_PHACC_FREQ_8LSB, 0x93 },
- { /* end of list */ },
+ static const struct rlist nicam_i[] = {
+ {AUD_PDF_DDS_CNST_BYTE0, 0x12},
+ {AUD_PHACC_FREQ_8MSB, 0x3a},
+ {AUD_PHACC_FREQ_8LSB, 0x93},
+ { /* end of list */ },
};
- dprintk("%s (status: devel), stereo : %d\n",__FUNCTION__,stereo);
+ static const struct rlist nicam_default[] = {
+ {AUD_PDF_DDS_CNST_BYTE0, 0x16},
+ {AUD_PHACC_FREQ_8MSB, 0x34},
+ {AUD_PHACC_FREQ_8LSB, 0x4c},
+ { /* end of list */ },
+ };
- if (!stereo) {
- /* FM Mono */
- set_audio_start(core, SEL_A2);
- set_audio_registers(core, pal_i_fm_mono);
- set_audio_finish(core, EN_DMTRX_SUMDIFF | EN_A2_FORCE_MONO1);
- } else {
- /* Nicam Stereo */
- set_audio_start(core, SEL_NICAM);
- set_audio_registers(core, pal_i_nicam);
- set_audio_finish(core, EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO);
- }
+ set_audio_start(core,SEL_NICAM);
+ switch (core->tvaudio) {
+ case WW_L:
+ dprintk("%s SECAM-L NICAM (status: devel)\n", __FUNCTION__);
+ set_audio_registers(core, nicam_l);
+ break;
+ case WW_I:
+ dprintk("%s PAL-I NICAM (status: devel)\n", __FUNCTION__);
+ set_audio_registers(core, nicam_bgdki_common);
+ set_audio_registers(core, nicam_i);
+ break;
+ default:
+ dprintk("%s PAL-BGDK NICAM (status: unknown)\n", __FUNCTION__);
+ set_audio_registers(core, nicam_bgdki_common);
+ set_audio_registers(core, nicam_default);
+ break;
+ };
+
+ mode |= EN_DMTRX_LR | EN_DMTRX_BYPASS;
+ set_audio_finish(core, mode);
}
static void set_audio_standard_A2(struct cx88_core *core, u32 mode)
{
- static const struct rlist a2_common[] = {
- {AUD_ERRLOGPERIOD_R, 0x00000064},
- {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
- {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
- {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
- {AUD_PDF_DDS_CNST_BYTE2, 0x06},
- {AUD_PDF_DDS_CNST_BYTE1, 0x82},
- {AUD_PDF_DDS_CNST_BYTE0, 0x12},
- {AUD_QAM_MODE, 0x05},
- {AUD_PHACC_FREQ_8MSB, 0x34},
- {AUD_PHACC_FREQ_8LSB, 0x4c},
- {AUD_RATE_ADJ1, 0x00000100},
- {AUD_RATE_ADJ2, 0x00000200},
- {AUD_RATE_ADJ3, 0x00000300},
- {AUD_RATE_ADJ4, 0x00000400},
- {AUD_RATE_ADJ5, 0x00000500},
- {AUD_THR_FR, 0x00000000},
- {AAGC_HYST, 0x0000001a},
- {AUD_PILOT_BQD_1_K0, 0x0000755b},
- {AUD_PILOT_BQD_1_K1, 0x00551340},
- {AUD_PILOT_BQD_1_K2, 0x006d30be},
- {AUD_PILOT_BQD_1_K3, 0xffd394af},
- {AUD_PILOT_BQD_1_K4, 0x00400000},
- {AUD_PILOT_BQD_2_K0, 0x00040000},
- {AUD_PILOT_BQD_2_K1, 0x002a4841},
- {AUD_PILOT_BQD_2_K2, 0x00400000},
- {AUD_PILOT_BQD_2_K3, 0x00000000},
- {AUD_PILOT_BQD_2_K4, 0x00000000},
- {AUD_MODE_CHG_TIMER, 0x00000040},
- {AUD_AFE_12DB_EN, 0x00000001},
- {AUD_CORDIC_SHIFT_0, 0x00000007},
- {AUD_CORDIC_SHIFT_1, 0x00000007},
- {AUD_DEEMPH0_G0, 0x00000380},
- {AUD_DEEMPH1_G0, 0x00000380},
- {AUD_DCOC_0_SRC, 0x0000001a},
- {AUD_DCOC0_SHIFT, 0x00000000},
- {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
- {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
- {AUD_DCOC_PASS_IN, 0x00000003},
- {AUD_IIR3_0_SEL, 0x00000021},
- {AUD_DN2_AFC, 0x00000002},
- {AUD_DCOC_1_SRC, 0x0000001b},
- {AUD_DCOC1_SHIFT, 0x00000000},
- {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
- {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
- {AUD_IIR3_1_SEL, 0x00000023},
- {AUD_RDSI_SEL, 0x00000017},
- {AUD_RDSI_SHIFT, 0x00000000},
- {AUD_RDSQ_SEL, 0x00000017},
- {AUD_RDSQ_SHIFT, 0x00000000},
- {AUD_PLL_INT, 0x0000001e},
- {AUD_PLL_DDS, 0x00000000},
- {AUD_PLL_FRAC, 0x0000e542},
- {AUD_POLYPH80SCALEFAC, 0x00000001},
- {AUD_START_TIMER, 0x00000000},
- { /* end of list */ },
+ static const struct rlist a2_bgdk_common[] = {
+ {AUD_ERRLOGPERIOD_R, 0x00000064},
+ {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
+ {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
+ {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
+ {AUD_PDF_DDS_CNST_BYTE2, 0x06},
+ {AUD_PDF_DDS_CNST_BYTE1, 0x82},
+ {AUD_PDF_DDS_CNST_BYTE0, 0x12},
+ {AUD_QAM_MODE, 0x05},
+ {AUD_PHACC_FREQ_8MSB, 0x34},
+ {AUD_PHACC_FREQ_8LSB, 0x4c},
+ {AUD_RATE_ADJ1, 0x00000100},
+ {AUD_RATE_ADJ2, 0x00000200},
+ {AUD_RATE_ADJ3, 0x00000300},
+ {AUD_RATE_ADJ4, 0x00000400},
+ {AUD_RATE_ADJ5, 0x00000500},
+ {AUD_THR_FR, 0x00000000},
+ {AAGC_HYST, 0x0000001a},
+ {AUD_PILOT_BQD_1_K0, 0x0000755b},
+ {AUD_PILOT_BQD_1_K1, 0x00551340},
+ {AUD_PILOT_BQD_1_K2, 0x006d30be},
+ {AUD_PILOT_BQD_1_K3, 0xffd394af},
+ {AUD_PILOT_BQD_1_K4, 0x00400000},
+ {AUD_PILOT_BQD_2_K0, 0x00040000},
+ {AUD_PILOT_BQD_2_K1, 0x002a4841},
+ {AUD_PILOT_BQD_2_K2, 0x00400000},
+ {AUD_PILOT_BQD_2_K3, 0x00000000},
+ {AUD_PILOT_BQD_2_K4, 0x00000000},
+ {AUD_MODE_CHG_TIMER, 0x00000040},
+ {AUD_AFE_12DB_EN, 0x00000001},
+ {AUD_CORDIC_SHIFT_0, 0x00000007},
+ {AUD_CORDIC_SHIFT_1, 0x00000007},
+ {AUD_DEEMPH0_G0, 0x00000380},
+ {AUD_DEEMPH1_G0, 0x00000380},
+ {AUD_DCOC_0_SRC, 0x0000001a},
+ {AUD_DCOC0_SHIFT, 0x00000000},
+ {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+ {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+ {AUD_DCOC_PASS_IN, 0x00000003},
+ {AUD_IIR3_0_SEL, 0x00000021},
+ {AUD_DN2_AFC, 0x00000002},
+ {AUD_DCOC_1_SRC, 0x0000001b},
+ {AUD_DCOC1_SHIFT, 0x00000000},
+ {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+ {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+ {AUD_IIR3_1_SEL, 0x00000023},
+ {AUD_RDSI_SEL, 0x00000017},
+ {AUD_RDSI_SHIFT, 0x00000000},
+ {AUD_RDSQ_SEL, 0x00000017},
+ {AUD_RDSQ_SHIFT, 0x00000000},
+ {AUD_PLL_INT, 0x0000001e},
+ {AUD_PLL_DDS, 0x00000000},
+ {AUD_PLL_FRAC, 0x0000e542},
+ {AUD_POLYPH80SCALEFAC, 0x00000001},
+ {AUD_START_TIMER, 0x00000000},
+ { /* end of list */ },
};
static const struct rlist a2_bg[] = {
- {AUD_DMD_RA_DDS, 0x002a4f2f},
- {AUD_C1_UP_THR, 0x00007000},
- {AUD_C1_LO_THR, 0x00005400},
- {AUD_C2_UP_THR, 0x00005400},
- {AUD_C2_LO_THR, 0x00003000},
+ {AUD_DMD_RA_DDS, 0x002a4f2f},
+ {AUD_C1_UP_THR, 0x00007000},
+ {AUD_C1_LO_THR, 0x00005400},
+ {AUD_C2_UP_THR, 0x00005400},
+ {AUD_C2_LO_THR, 0x00003000},
{ /* end of list */ },
};
static const struct rlist a2_dk[] = {
- {AUD_DMD_RA_DDS, 0x002a4f2f},
- {AUD_C1_UP_THR, 0x00007000},
- {AUD_C1_LO_THR, 0x00005400},
- {AUD_C2_UP_THR, 0x00005400},
- {AUD_C2_LO_THR, 0x00003000},
- {AUD_DN0_FREQ, 0x00003a1c},
- {AUD_DN2_FREQ, 0x0000d2e0},
+ {AUD_DMD_RA_DDS, 0x002a4f2f},
+ {AUD_C1_UP_THR, 0x00007000},
+ {AUD_C1_LO_THR, 0x00005400},
+ {AUD_C2_UP_THR, 0x00005400},
+ {AUD_C2_LO_THR, 0x00003000},
+ {AUD_DN0_FREQ, 0x00003a1c},
+ {AUD_DN2_FREQ, 0x0000d2e0},
{ /* end of list */ },
};
-/* unknown, probably NTSC-M */
- static const struct rlist a2_m[] = {
- {AUD_DMD_RA_DDS, 0x002a0425},
- {AUD_C1_UP_THR, 0x00003c00},
- {AUD_C1_LO_THR, 0x00003000},
- {AUD_C2_UP_THR, 0x00006000},
- {AUD_C2_LO_THR, 0x00003c00},
- {AUD_DEEMPH0_A0, 0x00007a80},
- {AUD_DEEMPH1_A0, 0x00007a80},
- {AUD_DEEMPH0_G0, 0x00001200},
- {AUD_DEEMPH1_G0, 0x00001200},
- {AUD_DN0_FREQ, 0x0000283b},
- {AUD_DN1_FREQ, 0x00003418},
- {AUD_DN2_FREQ, 0x000029c7},
- {AUD_POLY0_DDS_CONSTANT, 0x000a7540},
+
+ static const struct rlist a1_i[] = {
+ {AUD_ERRLOGPERIOD_R, 0x00000064},
+ {AUD_ERRINTRPTTHSHLD1_R, 0x00000fff},
+ {AUD_ERRINTRPTTHSHLD2_R, 0x0000001f},
+ {AUD_ERRINTRPTTHSHLD3_R, 0x0000000f},
+ {AUD_PDF_DDS_CNST_BYTE2, 0x06},
+ {AUD_PDF_DDS_CNST_BYTE1, 0x82},
+ {AUD_PDF_DDS_CNST_BYTE0, 0x12},
+ {AUD_QAM_MODE, 0x05},
+ {AUD_PHACC_FREQ_8MSB, 0x3a},
+ {AUD_PHACC_FREQ_8LSB, 0x93},
+ {AUD_DMD_RA_DDS, 0x002a4f2f},
+ {AUD_PLL_INT, 0x0000001e},
+ {AUD_PLL_DDS, 0x00000004},
+ {AUD_PLL_FRAC, 0x0000e542},
+ {AUD_RATE_ADJ1, 0x00000100},
+ {AUD_RATE_ADJ2, 0x00000200},
+ {AUD_RATE_ADJ3, 0x00000300},
+ {AUD_RATE_ADJ4, 0x00000400},
+ {AUD_RATE_ADJ5, 0x00000500},
+ {AUD_THR_FR, 0x00000000},
+ {AUD_PILOT_BQD_1_K0, 0x0000755b},
+ {AUD_PILOT_BQD_1_K1, 0x00551340},
+ {AUD_PILOT_BQD_1_K2, 0x006d30be},
+ {AUD_PILOT_BQD_1_K3, 0xffd394af},
+ {AUD_PILOT_BQD_1_K4, 0x00400000},
+ {AUD_PILOT_BQD_2_K0, 0x00040000},
+ {AUD_PILOT_BQD_2_K1, 0x002a4841},
+ {AUD_PILOT_BQD_2_K2, 0x00400000},
+ {AUD_PILOT_BQD_2_K3, 0x00000000},
+ {AUD_PILOT_BQD_2_K4, 0x00000000},
+ {AUD_MODE_CHG_TIMER, 0x00000060},
+ {AUD_AFE_12DB_EN, 0x00000001},
+ {AAGC_HYST, 0x0000000a},
+ {AUD_CORDIC_SHIFT_0, 0x00000007},
+ {AUD_CORDIC_SHIFT_1, 0x00000007},
+ {AUD_C1_UP_THR, 0x00007000},
+ {AUD_C1_LO_THR, 0x00005400},
+ {AUD_C2_UP_THR, 0x00005400},
+ {AUD_C2_LO_THR, 0x00003000},
+ {AUD_DCOC_0_SRC, 0x0000001a},
+ {AUD_DCOC0_SHIFT, 0x00000000},
+ {AUD_DCOC_0_SHIFT_IN0, 0x0000000a},
+ {AUD_DCOC_0_SHIFT_IN1, 0x00000008},
+ {AUD_DCOC_PASS_IN, 0x00000003},
+ {AUD_IIR3_0_SEL, 0x00000021},
+ {AUD_DN2_AFC, 0x00000002},
+ {AUD_DCOC_1_SRC, 0x0000001b},
+ {AUD_DCOC1_SHIFT, 0x00000000},
+ {AUD_DCOC_1_SHIFT_IN0, 0x0000000a},
+ {AUD_DCOC_1_SHIFT_IN1, 0x00000008},
+ {AUD_IIR3_1_SEL, 0x00000023},
+ {AUD_DN0_FREQ, 0x000035a3},
+ {AUD_DN2_FREQ, 0x000029c7},
+ {AUD_CRDC0_SRC_SEL, 0x00000511},
+ {AUD_IIR1_0_SEL, 0x00000001},
+ {AUD_IIR1_1_SEL, 0x00000000},
+ {AUD_IIR3_2_SEL, 0x00000003},
+ {AUD_IIR3_2_SHIFT, 0x00000000},
+ {AUD_IIR3_0_SEL, 0x00000002},
+ {AUD_IIR2_0_SEL, 0x00000021},
+ {AUD_IIR2_0_SHIFT, 0x00000002},
+ {AUD_DEEMPH0_SRC_SEL, 0x0000000b},
+ {AUD_DEEMPH1_SRC_SEL, 0x0000000b},
+ {AUD_POLYPH80SCALEFAC, 0x00000001},
+ {AUD_START_TIMER, 0x00000000},
{ /* end of list */ },
};
- static const struct rlist a2_deemph50[] = {
- {AUD_DEEMPH0_G0, 0x00000380},
- {AUD_DEEMPH1_G0, 0x00000380},
- {AUD_DEEMPHGAIN_R, 0x000011e1},
- {AUD_DEEMPHNUMER1_R, 0x0002a7bc},
- {AUD_DEEMPHNUMER2_R, 0x0003023c},
- { /* end of list */ },
+ static const struct rlist am_l[] = {
+ {AUD_ERRLOGPERIOD_R, 0x00000064},
+ {AUD_ERRINTRPTTHSHLD1_R, 0x00000FFF},
+ {AUD_ERRINTRPTTHSHLD2_R, 0x0000001F},
+ {AUD_ERRINTRPTTHSHLD3_R, 0x0000000F},
+ {AUD_PDF_DDS_CNST_BYTE2, 0x48},
+ {AUD_PDF_DDS_CNST_BYTE1, 0x3D},
+ {AUD_QAM_MODE, 0x00},
+ {AUD_PDF_DDS_CNST_BYTE0, 0xf5},
+ {AUD_PHACC_FREQ_8MSB, 0x3a},
+ {AUD_PHACC_FREQ_8LSB, 0x4a},
+ {AUD_DEEMPHGAIN_R, 0x00006680},
+ {AUD_DEEMPHNUMER1_R, 0x000353DE},
+ {AUD_DEEMPHNUMER2_R, 0x000001B1},
+ {AUD_DEEMPHDENOM1_R, 0x0000F3D0},
+ {AUD_DEEMPHDENOM2_R, 0x00000000},
+ {AUD_FM_MODE_ENABLE, 0x00000007},
+ {AUD_POLYPH80SCALEFAC, 0x00000003},
+ {AUD_AFE_12DB_EN, 0x00000001},
+ {AAGC_GAIN, 0x00000000},
+ {AAGC_HYST, 0x00000018},
+ {AAGC_DEF, 0x00000020},
+ {AUD_DN0_FREQ, 0x00000000},
+ {AUD_POLY0_DDS_CONSTANT, 0x000E4DB2},
+ {AUD_DCOC_0_SRC, 0x00000021},
+ {AUD_IIR1_0_SEL, 0x00000000},
+ {AUD_IIR1_0_SHIFT, 0x00000007},
+ {AUD_IIR1_1_SEL, 0x00000002},
+ {AUD_IIR1_1_SHIFT, 0x00000000},
+ {AUD_DCOC_1_SRC, 0x00000003},
+ {AUD_DCOC1_SHIFT, 0x00000000},
+ {AUD_DCOC_PASS_IN, 0x00000000},
+ {AUD_IIR1_2_SEL, 0x00000023},
+ {AUD_IIR1_2_SHIFT, 0x00000000},
+ {AUD_IIR1_3_SEL, 0x00000004},
+ {AUD_IIR1_3_SHIFT, 0x00000007},
+ {AUD_IIR1_4_SEL, 0x00000005},
+ {AUD_IIR1_4_SHIFT, 0x00000007},
+ {AUD_IIR3_0_SEL, 0x00000007},
+ {AUD_IIR3_0_SHIFT, 0x00000000},
+ {AUD_DEEMPH0_SRC_SEL, 0x00000011},
+ {AUD_DEEMPH0_SHIFT, 0x00000000},
+ {AUD_DEEMPH0_G0, 0x00007000},
+ {AUD_DEEMPH0_A0, 0x00000000},
+ {AUD_DEEMPH0_B0, 0x00000000},
+ {AUD_DEEMPH0_A1, 0x00000000},
+ {AUD_DEEMPH0_B1, 0x00000000},
+ {AUD_DEEMPH1_SRC_SEL, 0x00000011},
+ {AUD_DEEMPH1_SHIFT, 0x00000000},
+ {AUD_DEEMPH1_G0, 0x00007000},
+ {AUD_DEEMPH1_A0, 0x00000000},
+ {AUD_DEEMPH1_B0, 0x00000000},
+ {AUD_DEEMPH1_A1, 0x00000000},
+ {AUD_DEEMPH1_B1, 0x00000000},
+ {AUD_OUT0_SEL, 0x0000003F},
+ {AUD_OUT1_SEL, 0x0000003F},
+ {AUD_DMD_RA_DDS, 0x00F5C285},
+ {AUD_PLL_INT, 0x0000001E},
+ {AUD_PLL_DDS, 0x00000000},
+ {AUD_PLL_FRAC, 0x0000E542},
+ {AUD_RATE_ADJ1, 0x00000100},
+ {AUD_RATE_ADJ2, 0x00000200},
+ {AUD_RATE_ADJ3, 0x00000300},
+ {AUD_RATE_ADJ4, 0x00000400},
+ {AUD_RATE_ADJ5, 0x00000500},
+ {AUD_RATE_THRES_DMD, 0x000000C0},
+ { /* end of list */ },
};
- static const struct rlist a2_deemph75[] = {
- {AUD_DEEMPH0_G0, 0x00000480},
- {AUD_DEEMPH1_G0, 0x00000480},
- {AUD_DEEMPHGAIN_R, 0x00009000},
- {AUD_DEEMPHNUMER1_R, 0x000353de},
- {AUD_DEEMPHNUMER2_R, 0x000001b1},
+ static const struct rlist a2_deemph50[] = {
+ {AUD_DEEMPH0_G0, 0x00000380},
+ {AUD_DEEMPH1_G0, 0x00000380},
+ {AUD_DEEMPHGAIN_R, 0x000011e1},
+ {AUD_DEEMPHNUMER1_R, 0x0002a7bc},
+ {AUD_DEEMPHNUMER2_R, 0x0003023c},
{ /* end of list */ },
};
set_audio_start(core, SEL_A2);
- set_audio_registers(core, a2_common);
switch (core->tvaudio) {
- case WW_A2_BG:
- dprintk("%s PAL-BG A2 (status: known-good)\n",__FUNCTION__);
- set_audio_registers(core, a2_bg);
- set_audio_registers(core, a2_deemph50);
+ case WW_BG:
+ dprintk("%s PAL-BG A1/2 (status: known-good)\n", __FUNCTION__);
+ set_audio_registers(core, a2_bgdk_common);
+ set_audio_registers(core, a2_bg);
+ set_audio_registers(core, a2_deemph50);
break;
- case WW_A2_DK:
- dprintk("%s PAL-DK A2 (status: known-good)\n",__FUNCTION__);
- set_audio_registers(core, a2_dk);
- set_audio_registers(core, a2_deemph50);
+ case WW_DK:
+ dprintk("%s PAL-DK A1/2 (status: known-good)\n", __FUNCTION__);
+ set_audio_registers(core, a2_bgdk_common);
+ set_audio_registers(core, a2_dk);
+ set_audio_registers(core, a2_deemph50);
break;
- case WW_A2_M:
- dprintk("%s NTSC-M A2 (status: unknown)\n",__FUNCTION__);
- set_audio_registers(core, a2_m);
- set_audio_registers(core, a2_deemph75);
+ case WW_I:
+ dprintk("%s PAL-I A1 (status: known-good)\n", __FUNCTION__);
+ set_audio_registers(core, a1_i);
+ set_audio_registers(core, a2_deemph50);
+ break;
+ case WW_L:
+ dprintk("%s AM-L (status: devel)\n", __FUNCTION__);
+ set_audio_registers(core, am_l);
+ break;
+ default:
+ dprintk("%s Warning: wrong value\n", __FUNCTION__);
+ return;
break;
};
@@ -656,71 +633,71 @@ static void set_audio_standard_EIAJ(struct cx88_core *core)
{ /* end of list */ },
};
- dprintk("%s (status: unknown)\n",__FUNCTION__);
+ dprintk("%s (status: unknown)\n", __FUNCTION__);
set_audio_start(core, SEL_EIAJ);
set_audio_registers(core, eiaj);
set_audio_finish(core, EN_EIAJ_AUTO_STEREO);
}
-static void set_audio_standard_FM(struct cx88_core *core, enum cx88_deemph_type deemph)
+static void set_audio_standard_FM(struct cx88_core *core,
+ enum cx88_deemph_type deemph)
{
static const struct rlist fm_deemph_50[] = {
- { AUD_DEEMPH0_G0, 0x0C45 },
- { AUD_DEEMPH0_A0, 0x6262 },
- { AUD_DEEMPH0_B0, 0x1C29 },
- { AUD_DEEMPH0_A1, 0x3FC66},
- { AUD_DEEMPH0_B1, 0x399A },
-
- { AUD_DEEMPH1_G0, 0x0D80 },
- { AUD_DEEMPH1_A0, 0x6262 },
- { AUD_DEEMPH1_B0, 0x1C29 },
- { AUD_DEEMPH1_A1, 0x3FC66},
- { AUD_DEEMPH1_B1, 0x399A},
-
- { AUD_POLYPH80SCALEFAC, 0x0003},
+ {AUD_DEEMPH0_G0, 0x0C45},
+ {AUD_DEEMPH0_A0, 0x6262},
+ {AUD_DEEMPH0_B0, 0x1C29},
+ {AUD_DEEMPH0_A1, 0x3FC66},
+ {AUD_DEEMPH0_B1, 0x399A},
+
+ {AUD_DEEMPH1_G0, 0x0D80},
+ {AUD_DEEMPH1_A0, 0x6262},
+ {AUD_DEEMPH1_B0, 0x1C29},
+ {AUD_DEEMPH1_A1, 0x3FC66},
+ {AUD_DEEMPH1_B1, 0x399A},
+
+ {AUD_POLYPH80SCALEFAC, 0x0003},
{ /* end of list */ },
};
static const struct rlist fm_deemph_75[] = {
- { AUD_DEEMPH0_G0, 0x091B },
- { AUD_DEEMPH0_A0, 0x6B68 },
- { AUD_DEEMPH0_B0, 0x11EC },
- { AUD_DEEMPH0_A1, 0x3FC66},
- { AUD_DEEMPH0_B1, 0x399A },
-
- { AUD_DEEMPH1_G0, 0x0AA0 },
- { AUD_DEEMPH1_A0, 0x6B68 },
- { AUD_DEEMPH1_B0, 0x11EC },
- { AUD_DEEMPH1_A1, 0x3FC66},
- { AUD_DEEMPH1_B1, 0x399A},
-
- { AUD_POLYPH80SCALEFAC, 0x0003},
+ {AUD_DEEMPH0_G0, 0x091B},
+ {AUD_DEEMPH0_A0, 0x6B68},
+ {AUD_DEEMPH0_B0, 0x11EC},
+ {AUD_DEEMPH0_A1, 0x3FC66},
+ {AUD_DEEMPH0_B1, 0x399A},
+
+ {AUD_DEEMPH1_G0, 0x0AA0},
+ {AUD_DEEMPH1_A0, 0x6B68},
+ {AUD_DEEMPH1_B0, 0x11EC},
+ {AUD_DEEMPH1_A1, 0x3FC66},
+ {AUD_DEEMPH1_B1, 0x399A},
+
+ {AUD_POLYPH80SCALEFAC, 0x0003},
{ /* end of list */ },
};
/* It is enough to leave default values? */
static const struct rlist fm_no_deemph[] = {
- { AUD_POLYPH80SCALEFAC, 0x0003},
+ {AUD_POLYPH80SCALEFAC, 0x0003},
{ /* end of list */ },
};
- dprintk("%s (status: unknown)\n",__FUNCTION__);
+ dprintk("%s (status: unknown)\n", __FUNCTION__);
set_audio_start(core, SEL_FMRADIO);
- switch (deemph)
- {
- case FM_NO_DEEMPH:
- set_audio_registers(core, fm_no_deemph);
- break;
+ switch (deemph) {
+ case FM_NO_DEEMPH:
+ set_audio_registers(core, fm_no_deemph);
+ break;
- case FM_DEEMPH_50:
- set_audio_registers(core, fm_deemph_50);
- break;
+ case FM_DEEMPH_50:
+ set_audio_registers(core, fm_deemph_50);
+ break;
- case FM_DEEMPH_75:
- set_audio_registers(core, fm_deemph_75);
- break;
+ case FM_DEEMPH_75:
+ set_audio_registers(core, fm_deemph_75);
+ break;
}
set_audio_finish(core, EN_FMRADIO_AUTO_STEREO);
@@ -728,36 +705,64 @@ static void set_audio_standard_FM(struct cx88_core *core, enum cx88_deemph_type
/* ----------------------------------------------------------- */
+int cx88_detect_nicam(struct cx88_core *core)
+{
+ int i, j = 0;
+
+ dprintk("start nicam autodetect.\n");
+
+ for (i = 0; i < 6; i++) {
+ /* if bit1=1 then nicam is detected */
+ j += ((cx_read(AUD_NICAM_STATUS2) & 0x02) >> 1);
+
+ /* 3x detected: absolutly sure now */
+ if (j == 3) {
+ dprintk("nicam is detected.\n");
+ return 1;
+ }
+
+ /* wait a little bit for next reading status */
+ msleep(10);
+ }
+
+ dprintk("nicam is not detected.\n");
+ return 0;
+}
+
void cx88_set_tvaudio(struct cx88_core *core)
{
switch (core->tvaudio) {
case WW_BTSC:
set_audio_standard_BTSC(core, 0, EN_BTSC_AUTO_STEREO);
break;
- case WW_NICAM_BGDKL:
- set_audio_standard_NICAM_L(core,0);
- break;
- case WW_NICAM_I:
- set_audio_standard_PAL_I(core,0);
- break;
- case WW_A2_BG:
- case WW_A2_DK:
- case WW_A2_M:
- set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+ case WW_BG:
+ case WW_DK:
+ case WW_I:
+ case WW_L:
+ /* prepare all dsp registers */
+ set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+
+ /* set nicam mode - otherwise
+ AUD_NICAM_STATUS2 contains wrong values */
+ set_audio_standard_NICAM(core, EN_NICAM_AUTO_STEREO);
+ if (0 == cx88_detect_nicam(core)) {
+ /* fall back to fm / am mono */
+ set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+ core->use_nicam = 0;
+ } else {
+ core->use_nicam = 1;
+ }
break;
case WW_EIAJ:
set_audio_standard_EIAJ(core);
break;
case WW_FM:
- set_audio_standard_FM(core,FM_NO_DEEMPH);
- break;
- case WW_SYSTEM_L_AM:
- set_audio_standard_NICAM_L(core, 1);
+ set_audio_standard_FM(core, FM_NO_DEEMPH);
break;
case WW_NONE:
default:
printk("%s/0: unknown tv audio mode [%d]\n",
- core->name, core->tvaudio);
+ core->name, core->tvaudio);
break;
}
return;
@@ -766,24 +771,16 @@ void cx88_set_tvaudio(struct cx88_core *core)
void cx88_newstation(struct cx88_core *core)
{
core->audiomode_manual = UNSET;
-
- switch (core->tvaudio) {
- case WW_SYSTEM_L_AM:
- /* try nicam ... */
- core->audiomode_current = V4L2_TUNER_MODE_STEREO;
- set_audio_standard_NICAM_L(core, 1);
- break;
- }
}
void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
{
- static char *m[] = {"stereo", "dual mono", "mono", "sap"};
- static char *p[] = {"no pilot", "pilot c1", "pilot c2", "?"};
- u32 reg,mode,pilot;
+ static char *m[] = { "stereo", "dual mono", "mono", "sap" };
+ static char *p[] = { "no pilot", "pilot c1", "pilot c2", "?" };
+ u32 reg, mode, pilot;
- reg = cx_read(AUD_STATUS);
- mode = reg & 0x03;
+ reg = cx_read(AUD_STATUS);
+ mode = reg & 0x03;
pilot = (reg >> 2) & 0x03;
if (core->astat != reg)
@@ -800,14 +797,13 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
# if 0
t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
- V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+ V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
t->rxsubchans = V4L2_TUNER_SUB_MONO;
- t->audmode = V4L2_TUNER_MODE_MONO;
+ t->audmode = V4L2_TUNER_MODE_MONO;
switch (core->tvaudio) {
case WW_BTSC:
- t->capability = V4L2_TUNER_CAP_STEREO |
- V4L2_TUNER_CAP_SAP;
+ t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP;
t->rxsubchans = V4L2_TUNER_SUB_STEREO;
if (1 == pilot) {
/* SAP */
@@ -819,13 +815,15 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
case WW_A2_M:
if (1 == pilot) {
/* stereo */
- t->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_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->rxsubchans =
+ V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
t->audmode = V4L2_TUNER_MODE_LANG1;
}
break;
@@ -840,7 +838,7 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
t->audmode = V4L2_TUNER_MODE_STEREO;
t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
}
- break ;
+ break;
default:
/* nothing */
break;
@@ -851,7 +849,7 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
{
- u32 ctl = UNSET;
+ u32 ctl = UNSET;
u32 mask = UNSET;
if (manual) {
@@ -879,68 +877,58 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
break;
}
break;
- case WW_A2_BG:
- case WW_A2_DK:
- case WW_A2_M:
- switch (mode) {
- case V4L2_TUNER_MODE_MONO:
- case V4L2_TUNER_MODE_LANG1:
- set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
- break;
- case V4L2_TUNER_MODE_LANG2:
- set_audio_standard_A2(core, EN_A2_FORCE_MONO2);
- break;
- case V4L2_TUNER_MODE_STEREO:
- set_audio_standard_A2(core, EN_A2_FORCE_STEREO);
- break;
- }
- break;
- case WW_NICAM_BGDKL:
- switch (mode) {
- case V4L2_TUNER_MODE_MONO:
- ctl = EN_NICAM_FORCE_MONO1;
- mask = 0x3f;
- break;
- case V4L2_TUNER_MODE_LANG1:
- ctl = EN_NICAM_AUTO_MONO2;
- mask = 0x3f;
- break;
- case V4L2_TUNER_MODE_STEREO:
- ctl = EN_NICAM_FORCE_STEREO | EN_DMTRX_LR;
- mask = 0x93f;
- break;
- }
- break;
- case WW_SYSTEM_L_AM:
- switch (mode) {
- case V4L2_TUNER_MODE_MONO:
- case V4L2_TUNER_MODE_LANG1: /* FIXME */
- set_audio_standard_NICAM_L(core, 0);
- break;
- case V4L2_TUNER_MODE_STEREO:
- set_audio_standard_NICAM_L(core, 1);
- break;
- }
- break;
- case WW_NICAM_I:
- switch (mode) {
- case V4L2_TUNER_MODE_MONO:
- case V4L2_TUNER_MODE_LANG1:
- set_audio_standard_PAL_I(core, 0);
- break;
- case V4L2_TUNER_MODE_STEREO:
- set_audio_standard_PAL_I(core, 1);
- break;
+ case WW_BG:
+ case WW_DK:
+ case WW_I:
+ case WW_L:
+ if (1 == core->use_nicam) {
+ switch (mode) {
+ case V4L2_TUNER_MODE_MONO:
+ case V4L2_TUNER_MODE_LANG1:
+ set_audio_standard_NICAM(core,
+ EN_NICAM_FORCE_MONO1);
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ set_audio_standard_NICAM(core,
+ EN_NICAM_FORCE_MONO2);
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ set_audio_standard_NICAM(core,
+ EN_NICAM_FORCE_STEREO);
+ break;
+ }
+ } else {
+ if ((core->tvaudio == WW_I) || (core->tvaudio == WW_L)) {
+ /* fall back to fm / am mono */
+ set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+ } else {
+ /* TODO: Add A2 autodection */
+ switch (mode) {
+ case V4L2_TUNER_MODE_MONO:
+ case V4L2_TUNER_MODE_LANG1:
+ set_audio_standard_A2(core,
+ EN_A2_FORCE_MONO1);
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ set_audio_standard_A2(core,
+ EN_A2_FORCE_MONO2);
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ set_audio_standard_A2(core,
+ EN_A2_FORCE_STEREO);
+ break;
+ }
+ }
}
break;
case WW_FM:
switch (mode) {
case V4L2_TUNER_MODE_MONO:
- ctl = EN_FMRADIO_FORCE_MONO;
+ ctl = EN_FMRADIO_FORCE_MONO;
mask = 0x3f;
break;
case V4L2_TUNER_MODE_STEREO:
- ctl = EN_FMRADIO_AUTO_STEREO;
+ ctl = EN_FMRADIO_AUTO_STEREO;
mask = 0x3f;
break;
}
@@ -970,8 +958,8 @@ int cx88_audio_thread(void *data)
break;
/* just monitor the audio status for now ... */
- memset(&t,0,sizeof(t));
- cx88_get_stereo(core,&t);
+ memset(&t, 0, sizeof(t));
+ cx88_get_stereo(core, &t);
if (UNSET != core->audiomode_manual)
/* manually set, don't do anything. */
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 3dbc074fb51..24a48f8a48c 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -34,6 +34,9 @@
#include "cx88.h"
+/* Include V4L1 specific functions. Should be removed soon */
+#include <linux/videodev.h>
+
MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
@@ -100,7 +103,7 @@ static struct cx88_tvnorm tvnorms[] = {
.id = V4L2_STD_PAL_I,
.cxiformat = VideoFormatPAL,
.cxoformat = 0x181f0008,
- },{
+ },{
.name = "PAL-M",
.id = V4L2_STD_PAL_M,
.cxiformat = VideoFormatPALM,
@@ -470,7 +473,7 @@ static int restart_video_queue(struct cx8800_dev *dev,
struct list_head *item;
if (!list_empty(&q->active)) {
- buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+ buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
dprintk(2,"restart_queue [%p/%d]: restart dma\n",
buf, buf->vb.i);
start_video_dma(dev, q, buf);
@@ -486,7 +489,7 @@ static int restart_video_queue(struct cx8800_dev *dev,
for (;;) {
if (list_empty(&q->queued))
return 0;
- buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
+ buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
if (NULL == prev) {
list_del(&buf->vb.queue);
list_add_tail(&buf->vb.queue,&q->active);
@@ -783,11 +786,11 @@ static int video_open(struct inode *inode, struct file *file)
cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL);
}
- return 0;
+ return 0;
}
static ssize_t
-video_read(struct file *file, char *data, size_t count, loff_t *ppos)
+video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
struct cx8800_fh *fh = file->private_data;
@@ -922,7 +925,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
{
/* struct cx88_core *core = dev->core; */
struct cx88_ctrl *c = NULL;
- u32 v_sat_value;
+ u32 v_sat_value;
u32 value;
int i;
@@ -1187,7 +1190,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_format *f = arg;
return cx8800_try_fmt(dev,fh,f);
}
-
+#ifdef HAVE_V4L1
/* --- streaming capture ------------------------------------- */
case VIDIOCGMBUF:
{
@@ -1213,6 +1216,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
}
return 0;
}
+#endif
case VIDIOC_REQBUFS:
return videobuf_reqbufs(get_queue(fh), arg);
@@ -1244,7 +1248,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
res_free(dev,fh,res);
return 0;
}
-
default:
return cx88_do_ioctl( inode, file, fh->radio, core, cmd, arg, video_do_ioctl );
}
@@ -1252,15 +1255,13 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
}
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)
+ struct cx88_core *core, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl)
{
int err;
+ dprintk( 1, "CORE IOCTL: 0x%x\n", cmd );
if (video_debug > 1)
cx88_print_ioctl(core->name,cmd);
- printk( KERN_INFO "CORE IOCTL: 0x%x\n", cmd );
- cx88_print_ioctl(core->name,cmd);
- dprintk( 1, "CORE IOCTL: 0x%x\n", cmd );
switch (cmd) {
/* ---------- tv norms ---------- */
@@ -1401,7 +1402,7 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
cx88_get_stereo(core ,t);
reg = cx_read(MO_DEVICE_STATUS);
- t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
+ t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
return 0;
}
case VIDIOC_S_TUNER:
@@ -1488,7 +1489,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_capability *cap = arg;
memset(cap,0,sizeof(*cap));
- strcpy(cap->driver, "cx8800");
+ 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));
@@ -1505,6 +1506,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
memset(t,0,sizeof(*t));
strcpy(t->name, "Radio");
+ t->type = V4L2_TUNER_RADIO;
cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t);
return 0;
@@ -1539,6 +1541,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
*id = 0;
return 0;
}
+#ifdef HAVE_V4L1
case VIDIOCSTUNER:
{
struct video_tuner *v = arg;
@@ -1549,6 +1552,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
cx88_call_i2c_clients(core,VIDIOCSTUNER,v);
return 0;
}
+#endif
case VIDIOC_S_TUNER:
{
struct v4l2_tuner *t = arg;
@@ -1829,8 +1833,8 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
/* print pci info */
pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
- pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
- printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
+ pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
+ printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%lx\n", core->name,
pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
dev->pci_lat,pci_resource_start(pci_dev,0));
@@ -1946,7 +1950,7 @@ fail_free:
static void __devexit cx8800_finidev(struct pci_dev *pci_dev)
{
- struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
+ struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core;
/* stop thread */
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index f48dd435356..b19d3a9e229 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -22,7 +22,7 @@
#include <linux/pci.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <linux/kdev_t.h>
#include <media/tuner.h>
@@ -148,7 +148,7 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_PIXELVIEW 3
#define CX88_BOARD_ATI_WONDER_PRO 4
#define CX88_BOARD_WINFAST2000XP_EXPERT 5
-#define CX88_BOARD_AVERTV_303 6
+#define CX88_BOARD_AVERTV_STUDIO_303 6
#define CX88_BOARD_MSI_TVANYWHERE_MASTER 7
#define CX88_BOARD_WINFAST_DV2000 8
#define CX88_BOARD_LEADTEK_PVR2000 9
@@ -174,6 +174,11 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_ADSTECH_DVB_T_PCI 29
#define CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1 30
#define CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD 31
+#define CX88_BOARD_AVERMEDIA_ULTRATV_MC_550 32
+#define CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD 33
+#define CX88_BOARD_ATI_HDTVWONDER 34
+#define CX88_BOARD_WINFAST_DTV1000 35
+#define CX88_BOARD_AVERTV_303 36
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
@@ -203,8 +208,8 @@ struct cx88_board {
int tda9887_conf;
struct cx88_input input[MAX_CX88_INPUT];
struct cx88_input radio;
- int blackbird:1;
- int dvb:1;
+ unsigned int blackbird:1;
+ unsigned int dvb:1;
};
struct cx88_subid {
@@ -255,8 +260,8 @@ struct cx88_core {
/* pci stuff */
int pci_bus;
int pci_slot;
- u32 __iomem *lmmio;
- u8 __iomem *bmmio;
+ u32 __iomem *lmmio;
+ u8 __iomem *bmmio;
u32 shadow[SHADOW_MAX];
int pci_irqmask;
@@ -287,6 +292,7 @@ struct cx88_core {
u32 audiomode_current;
u32 input;
u32 astat;
+ u32 use_nicam;
/* IR remote control state */
struct cx88_IR *ir;
@@ -370,6 +376,14 @@ struct cx8802_suspend_state {
int disabled;
};
+/* TODO: move this to struct v4l2_mpeg_compression ? */
+struct blackbird_dnr {
+ u32 mode;
+ u32 type;
+ u32 spatial;
+ u32 temporal;
+};
+
struct cx8802_dev {
struct cx88_core *core;
spinlock_t slock;
@@ -400,6 +414,10 @@ struct cx8802_dev {
/* for switching modulation types */
unsigned char ts_gen_cntrl;
+
+ /* mpeg params */
+ struct v4l2_mpeg_compression params;
+ struct blackbird_dnr dnr_params;
};
/* ----------------------------------------------------------- */
@@ -514,22 +532,20 @@ extern void cx88_card_setup(struct cx88_core *core);
#define WW_NONE 1
#define WW_BTSC 2
-#define WW_NICAM_I 3
-#define WW_NICAM_BGDKL 4
-#define WW_A1 5
-#define WW_A2_BG 6
-#define WW_A2_DK 7
-#define WW_A2_M 8
-#define WW_EIAJ 9
-#define WW_SYSTEM_L_AM 10
-#define WW_I2SPT 11
-#define WW_FM 12
+#define WW_BG 3
+#define WW_DK 4
+#define WW_I 5
+#define WW_L 6
+#define WW_EIAJ 7
+#define WW_I2SPT 8
+#define WW_FM 9
void cx88_set_tvaudio(struct cx88_core *core);
void cx88_newstation(struct cx88_core *core);
void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t);
void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual);
int cx88_audio_thread(void *data);
+int cx88_detect_nicam(struct cx88_core *core);
/* ----------------------------------------------------------- */
/* cx88-input.c */
@@ -541,7 +557,8 @@ void cx88_ir_irq(struct cx88_core *core);
/* ----------------------------------------------------------- */
/* cx88-mpeg.c */
-int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf);
+int cx8802_buf_prepare(struct cx8802_dev *dev, struct cx88_buffer *buf,
+ enum v4l2_field field);
void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf);
void cx8802_cancel_buffers(struct cx8802_dev *dev);
@@ -562,6 +579,10 @@ extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
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);
+void blackbird_set_params(struct cx8802_dev *dev,
+ struct v4l2_mpeg_compression *params);
+void blackbird_set_dnr_params(struct cx8802_dev *dev,
+ struct blackbird_dnr* dnr_params);
/*
* Local variables:
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
new file mode 100644
index 00000000000..885fd017008
--- /dev/null
+++ b/drivers/media/video/em28xx/Kconfig
@@ -0,0 +1,12 @@
+config VIDEO_EM28XX
+ tristate "Empia EM2800/2820/2840 USB video capture support"
+ depends on VIDEO_DEV && USB && I2C
+ select VIDEO_BUF
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_IR
+ ---help---
+ This is a video4linux driver for Empia 28xx based TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called em28xx
diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile
new file mode 100644
index 00000000000..da457a05b0d
--- /dev/null
+++ b/drivers/media/video/em28xx/Makefile
@@ -0,0 +1,6 @@
+em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \
+ em28xx-input.o
+
+obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
+
+EXTRA_CFLAGS += -I$(src)/..
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
new file mode 100644
index 00000000000..57779e63f35
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -0,0 +1,292 @@
+/*
+ em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+ Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+ Markus Rechberger <mrechberger@gmail.com>
+ Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Sascha Sommer <saschasommer@freenet.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; 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/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/usb.h>
+#include <media/tuner.h>
+#include <media/audiochip.h>
+#include <media/tveeprom.h>
+#include "msp3400.h"
+
+#include "em28xx.h"
+
+struct em28xx_board em28xx_boards[] = {
+ [EM2800_BOARD_UNKNOWN] = {
+ .name = "Unknown EM2800 video grabber",
+ .is_em2800 = 1,
+ .vchannels = 2,
+ .norm = VIDEO_MODE_PAL,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM28XX_SAA7113,
+ .input = {{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2820_BOARD_UNKNOWN] = {
+ .name = "Unknown EM2820/2840 video grabber",
+ .is_em2800 = 0,
+ .vchannels = 2,
+ .norm = VIDEO_MODE_PAL,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM28XX_SAA7113,
+ .input = {{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2820_BOARD_TERRATEC_CINERGY_250] = {
+ .name = "Terratec Cinergy 250 USB",
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM28XX_SAA7113,
+ .input = {{
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = 2,
+ .amux = 0,
+ },{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2820_BOARD_PINNACLE_USB_2] = {
+ .name = "Pinnacle PCTV USB 2",
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM28XX_SAA7113,
+ .input = {{
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = 2,
+ .amux = 0,
+ },{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = {
+ .name = "Hauppauge WinTV USB 2",
+ .vchannels = 3,
+ .norm = VIDEO_MODE_NTSC,
+ .tuner_type = TUNER_PHILIPS_FM1236_MK3,
+ .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
+ .has_tuner = 1,
+ .decoder = EM28XX_TVP5150,
+ .has_msp34xx = 1,
+ /*FIXME: S-Video not tested */
+ .input = {{
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = 0,
+ .amux = 6,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 2,
+ .amux = 1,
+ }},
+ },
+ [EM2820_BOARD_MSI_VOX_USB_2] = {
+ .name = "MSI VOX USB 2.0",
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
+ .has_tuner = 1,
+ .decoder = EM28XX_SAA7114,
+ .input = {{
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = 4,
+ .amux = 0,
+ },{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2800_BOARD_TERRATEC_CINERGY_200] = {
+ .name = "Terratec Cinergy 200 USB",
+ .is_em2800 = 1,
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM28XX_SAA7113,
+ .input = {{
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = 2,
+ .amux = 0,
+ },{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2800_BOARD_LEADTEK_WINFAST_USBII] = {
+ .name = "Leadtek Winfast USB II",
+ .is_em2800 = 1,
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM28XX_SAA7113,
+ .input = {{
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = 2,
+ .amux = 0,
+ },{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2800_BOARD_KWORLD_USB2800] = {
+ .name = "Kworld USB2800",
+ .is_em2800 = 1,
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_PHILIPS_ATSC,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM28XX_SAA7113,
+ .input = {{
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = 2,
+ .amux = 0,
+ },{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2820_BOARD_PINNACLE_DVC_90] = {
+ .name = "Pinnacle Dazzle DVC 90",
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .has_tuner = 0,
+ .decoder = EM28XX_SAA7113,
+ .input = {{
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+};
+const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
+
+/* table of devices that work with this driver */
+struct usb_device_id em28xx_id_table [] = {
+ { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_MSI_VOX_USB_2 },
+ { USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
+ { USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 },
+ { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
+ { USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+ { },
+};
+
+void em28xx_card_setup(struct em28xx *dev)
+{
+ /* request some modules */
+ if (dev->model == EM2820_BOARD_HAUPPAUGE_WINTV_USB_2) {
+ struct tveeprom tv;
+ struct v4l2_audioout ao;
+#ifdef CONFIG_MODULES
+ request_module("tveeprom");
+ request_module("ir-kbd-i2c");
+ request_module("msp3400");
+#endif
+ /* Call first TVeeprom */
+
+ dev->i2c_client.addr = 0xa0 >> 1;
+ tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
+
+ dev->tuner_type= tv.tuner_type;
+ if (tv.audio_processor == AUDIO_CHIP_MSP34XX) {
+ dev->has_msp34xx=1;
+ memset (&ao,0,sizeof(ao));
+
+ ao.index=2;
+ ao.mode=V4L2_AUDMODE_32BITS;
+ em28xx_i2c_call_clients(dev, VIDIOC_S_AUDOUT, &ao);
+ } else
+ dev->has_msp34xx=0;
+ }
+}
+
+EXPORT_SYMBOL(em28xx_boards);
+EXPORT_SYMBOL(em28xx_bcount);
+EXPORT_SYMBOL(em28xx_id_table);
+
+MODULE_DEVICE_TABLE (usb, em28xx_id_table);
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
new file mode 100644
index 00000000000..d54bc012748
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -0,0 +1,817 @@
+/*
+ em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+ Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+ Markus Rechberger <mrechberger@gmail.com>
+ Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Sascha Sommer <saschasommer@freenet.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; 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/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/usb.h>
+#include <linux/vmalloc.h>
+
+#include "em28xx.h"
+
+/* #define ENABLE_DEBUG_ISOC_FRAMES */
+
+unsigned int core_debug;
+module_param(core_debug,int,0644);
+MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+
+#define em28xx_coredbg(fmt, arg...) do {\
+ if (core_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __FUNCTION__ , ##arg); } while (0)
+
+unsigned int reg_debug;
+module_param(reg_debug,int,0644);
+MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]");
+
+#define em28xx_regdbg(fmt, arg...) do {\
+ if (reg_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __FUNCTION__ , ##arg); } while (0)
+
+unsigned int isoc_debug;
+module_param(isoc_debug,int,0644);
+MODULE_PARM_DESC(isoc_debug,"enable debug messages [isoc transfers]");
+
+#define em28xx_isocdbg(fmt, arg...) do {\
+ if (isoc_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __FUNCTION__ , ##arg); } while (0)
+
+static int alt = EM28XX_PINOUT;
+module_param(alt, int, 0644);
+MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
+
+/* ------------------------------------------------------------------ */
+/* debug help functions */
+
+static const char *v4l1_ioctls[] = {
+ "0", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
+ "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
+ "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
+ "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
+ "SMICROCODE", "GVBIFMT", "SVBIFMT" };
+#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
+
+static const char *v4l2_ioctls[] = {
+ "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
+ "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF",
+ "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON",
+ "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD",
+ "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER",
+ "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL",
+ "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43",
+ "44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT",
+ "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
+ "S_MODULATOR"
+};
+#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
+
+void em28xx_print_ioctl(char *name, unsigned int cmd)
+{
+ char *dir;
+
+ switch (_IOC_DIR(cmd)) {
+ case _IOC_NONE: dir = "--"; break;
+ case _IOC_READ: dir = "r-"; break;
+ case _IOC_WRITE: dir = "-w"; break;
+ case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
+ default: dir = "??"; break;
+ }
+ switch (_IOC_TYPE(cmd)) {
+ case 'v':
+ printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n",
+ name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
+ v4l1_ioctls[_IOC_NR(cmd)] : "???");
+ break;
+ case 'V':
+ printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n",
+ name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ?
+ v4l2_ioctls[_IOC_NR(cmd)] : "???");
+ break;
+ default:
+ printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
+ name, cmd, dir, _IOC_NR(cmd));
+ }
+}
+
+static void *rvmalloc(size_t size)
+{
+ void *mem;
+ unsigned long adr;
+
+ size = PAGE_ALIGN(size);
+
+ mem = vmalloc_32((unsigned long)size);
+ if (!mem)
+ return NULL;
+
+ memset(mem, 0, size);
+
+ adr = (unsigned long)mem;
+ while (size > 0) {
+ SetPageReserved(vmalloc_to_page((void *)adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ return mem;
+}
+
+static void rvfree(void *mem, size_t size)
+{
+ unsigned long adr;
+
+ if (!mem)
+ return;
+
+ size = PAGE_ALIGN(size);
+
+ adr = (unsigned long)mem;
+ while (size > 0) {
+ ClearPageReserved(vmalloc_to_page((void *)adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ vfree(mem);
+}
+
+/*
+ * em28xx_request_buffers()
+ * allocate a number of buffers
+ */
+u32 em28xx_request_buffers(struct em28xx *dev, u32 count)
+{
+ const size_t imagesize = PAGE_ALIGN(dev->frame_size); /*needs to be page aligned cause the buffers can be mapped individually! */
+ void *buff = NULL;
+ u32 i;
+ em28xx_coredbg("requested %i buffers with size %i", count, imagesize);
+ if (count > EM28XX_NUM_FRAMES)
+ count = EM28XX_NUM_FRAMES;
+
+ dev->num_frames = count;
+ while (dev->num_frames > 0) {
+ if ((buff = rvmalloc(dev->num_frames * imagesize)))
+ break;
+ dev->num_frames--;
+ }
+
+ for (i = 0; i < dev->num_frames; i++) {
+ dev->frame[i].bufmem = buff + i * imagesize;
+ dev->frame[i].buf.index = i;
+ dev->frame[i].buf.m.offset = i * imagesize;
+ dev->frame[i].buf.length = dev->frame_size;
+ dev->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dev->frame[i].buf.sequence = 0;
+ dev->frame[i].buf.field = V4L2_FIELD_NONE;
+ dev->frame[i].buf.memory = V4L2_MEMORY_MMAP;
+ dev->frame[i].buf.flags = 0;
+ }
+ return dev->num_frames;
+}
+
+/*
+ * em28xx_queue_unusedframes()
+ * add all frames that are not currently in use to the inbuffer queue
+ */
+void em28xx_queue_unusedframes(struct em28xx *dev)
+{
+ unsigned long lock_flags;
+ u32 i;
+
+ for (i = 0; i < dev->num_frames; i++)
+ if (dev->frame[i].state == F_UNUSED) {
+ dev->frame[i].state = F_QUEUED;
+ spin_lock_irqsave(&dev->queue_lock, lock_flags);
+ list_add_tail(&dev->frame[i].frame, &dev->inqueue);
+ spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+ }
+}
+
+/*
+ * em28xx_release_buffers()
+ * free frame buffers
+ */
+void em28xx_release_buffers(struct em28xx *dev)
+{
+ if (dev->num_frames) {
+ rvfree(dev->frame[0].bufmem,
+ dev->num_frames * PAGE_ALIGN(dev->frame[0].buf.length));
+ dev->num_frames = 0;
+ }
+}
+
+/*
+ * em28xx_read_reg_req()
+ * reads data from the usb device specifying bRequest
+ */
+int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
+ char *buf, int len)
+{
+ int ret, byte;
+
+ em28xx_regdbg("req=%02x, reg=%02x ", req, reg);
+
+ ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x0000, reg, buf, len, HZ);
+
+ if (reg_debug){
+ printk(ret < 0 ? " failed!\n" : "%02x values: ", ret);
+ for (byte = 0; byte < len; byte++) {
+ printk(" %02x", buf[byte]);
+ }
+ printk("\n");
+ }
+
+ return ret;
+}
+
+/*
+ * em28xx_read_reg_req()
+ * reads data from the usb device specifying bRequest
+ */
+int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg)
+{
+ u8 val;
+ int ret;
+
+ em28xx_regdbg("req=%02x, reg=%02x:", req, reg);
+
+ ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x0000, reg, &val, 1, HZ);
+
+ if (reg_debug)
+ printk(ret < 0 ? " failed!\n" : "%02x\n", val);
+
+ if (ret < 0)
+ return ret;
+
+ return val;
+}
+
+int em28xx_read_reg(struct em28xx *dev, u16 reg)
+{
+ return em28xx_read_reg_req(dev, USB_REQ_GET_STATUS, reg);
+}
+
+/*
+ * em28xx_write_regs_req()
+ * sends data to the usb device, specifying bRequest
+ */
+int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
+ int len)
+{
+ int ret;
+
+ /*usb_control_msg seems to expect a kmalloced buffer */
+ unsigned char *bufs = kmalloc(len, GFP_KERNEL);
+
+ em28xx_regdbg("req=%02x reg=%02x:", req, reg);
+
+ if (reg_debug) {
+ int i;
+ for (i = 0; i < len; ++i)
+ printk (" %02x", (unsigned char)buf[i]);
+ printk ("\n");
+ }
+
+ if (!bufs)
+ return -ENOMEM;
+ memcpy(bufs, buf, len);
+ ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x0000, reg, bufs, len, HZ);
+ mdelay(5); /* FIXME: magic number */
+ kfree(bufs);
+ return ret;
+}
+
+int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
+{
+ return em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
+}
+
+/*
+ * em28xx_write_reg_bits()
+ * sets only some bits (specified by bitmask) of a register, by first reading
+ * the actual value
+ */
+int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
+ u8 bitmask)
+{
+ int oldval;
+ u8 newval;
+ if ((oldval = em28xx_read_reg(dev, reg)) < 0)
+ return oldval;
+ newval = (((u8) oldval) & ~bitmask) | (val & bitmask);
+ return em28xx_write_regs(dev, reg, &newval, 1);
+}
+
+/*
+ * em28xx_write_ac97()
+ * write a 16 bit value to the specified AC97 address (LSB first!)
+ */
+int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val)
+{
+ int ret;
+ u8 addr = reg & 0x7f;
+ if ((ret = em28xx_write_regs(dev, AC97LSB_REG, val, 2)) < 0)
+ return ret;
+ if ((ret = em28xx_write_regs(dev, AC97ADDR_REG, &addr, 1)) < 0)
+ return ret;
+ if ((ret = em28xx_read_reg(dev, AC97BUSY_REG)) < 0)
+ return ret;
+ else if (((u8) ret) & 0x01) {
+ em28xx_warn ("AC97 command still being exectuted: not handled properly!\n");
+ }
+ return 0;
+}
+
+int em28xx_audio_analog_set(struct em28xx *dev)
+{
+ char s[2] = { 0x00, 0x00 };
+ s[0] |= 0x1f - dev->volume;
+ s[1] |= 0x1f - dev->volume;
+ if (dev->mute)
+ s[1] |= 0x80;
+ return em28xx_write_ac97(dev, MASTER_AC97, s);
+}
+
+
+int em28xx_colorlevels_set_default(struct em28xx *dev)
+{
+ em28xx_write_regs(dev, YGAIN_REG, "\x10", 1); /* contrast */
+ em28xx_write_regs(dev, YOFFSET_REG, "\x00", 1); /* brightness */
+ em28xx_write_regs(dev, UVGAIN_REG, "\x10", 1); /* saturation */
+ em28xx_write_regs(dev, UOFFSET_REG, "\x00", 1);
+ em28xx_write_regs(dev, VOFFSET_REG, "\x00", 1);
+ em28xx_write_regs(dev, SHARPNESS_REG, "\x00", 1);
+
+ em28xx_write_regs(dev, GAMMA_REG, "\x20", 1);
+ em28xx_write_regs(dev, RGAIN_REG, "\x20", 1);
+ em28xx_write_regs(dev, GGAIN_REG, "\x20", 1);
+ em28xx_write_regs(dev, BGAIN_REG, "\x20", 1);
+ em28xx_write_regs(dev, ROFFSET_REG, "\x00", 1);
+ em28xx_write_regs(dev, GOFFSET_REG, "\x00", 1);
+ return em28xx_write_regs(dev, BOFFSET_REG, "\x00", 1);
+}
+
+int em28xx_capture_start(struct em28xx *dev, int start)
+{
+ int ret;
+ /* FIXME: which is the best order? */
+ /* video registers are sampled by VREF */
+ if ((ret = em28xx_write_reg_bits(dev, USBSUSP_REG, start ? 0x10 : 0x00,
+ 0x10)) < 0)
+ return ret;
+ /* enable video capture */
+ return em28xx_write_regs(dev, VINENABLE_REG, start ? "\x67" : "\x27", 1);
+}
+
+int em28xx_outfmt_set_yuv422(struct em28xx *dev)
+{
+ em28xx_write_regs(dev, OUTFMT_REG, "\x34", 1);
+ em28xx_write_regs(dev, VINMODE_REG, "\x10", 1);
+ return em28xx_write_regs(dev, VINCTRL_REG, "\x11", 1);
+}
+
+int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
+ u8 ymax)
+{
+ em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n", xmin, ymin, xmax, ymax);
+
+ em28xx_write_regs(dev, XMIN_REG, &xmin, 1);
+ em28xx_write_regs(dev, XMAX_REG, &xmax, 1);
+ em28xx_write_regs(dev, YMIN_REG, &ymin, 1);
+ return em28xx_write_regs(dev, YMAX_REG, &ymax, 1);
+}
+
+int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+ u16 width, u16 height)
+{
+ u8 cwidth = width;
+ u8 cheight = height;
+ u8 overflow = (height >> 7 & 0x02) | (width >> 8 & 0x01);
+
+ em28xx_coredbg("em28xx Area Set: (%d,%d)\n", (width | (overflow & 2) << 7),
+ (height | (overflow & 1) << 8));
+
+ em28xx_write_regs(dev, HSTART_REG, &hstart, 1);
+ em28xx_write_regs(dev, VSTART_REG, &vstart, 1);
+ em28xx_write_regs(dev, CWIDTH_REG, &cwidth, 1);
+ em28xx_write_regs(dev, CHEIGHT_REG, &cheight, 1);
+ return em28xx_write_regs(dev, OFLOW_REG, &overflow, 1);
+}
+
+int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
+{
+ u8 mode;
+ /* the em2800 scaler only supports scaling down to 50% */
+ if(dev->is_em2800)
+ mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
+ else {
+ u8 buf[2];
+ buf[0] = h;
+ buf[1] = h >> 8;
+ em28xx_write_regs(dev, HSCALELOW_REG, (char *)buf, 2);
+ buf[0] = v;
+ buf[1] = v >> 8;
+ em28xx_write_regs(dev, VSCALELOW_REG, (char *)buf, 2);
+ /* it seems that both H and V scalers must be active to work correctly */
+ mode = (h || v)? 0x30: 0x00;
+ }
+ return em28xx_write_reg_bits(dev, COMPR_REG, mode, 0x30);
+}
+
+/* FIXME: this only function read values from dev */
+int em28xx_resolution_set(struct em28xx *dev)
+{
+ int width, height;
+ width = norm_maxw(dev);
+ height = norm_maxh(dev) >> 1;
+
+ em28xx_outfmt_set_yuv422(dev);
+ em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
+ em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
+ return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
+}
+
+
+/******************* isoc transfer handling ****************************/
+
+#ifdef ENABLE_DEBUG_ISOC_FRAMES
+static void em28xx_isoc_dump(struct urb *urb, struct pt_regs *regs)
+{
+ int len = 0;
+ int ntrans = 0;
+ int i;
+
+ printk(KERN_DEBUG "isocIrq: sf=%d np=%d ec=%x\n",
+ urb->start_frame, urb->number_of_packets,
+ urb->error_count);
+ for (i = 0; i < urb->number_of_packets; i++) {
+ unsigned char *buf =
+ urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset;
+ int alen = urb->iso_frame_desc[i].actual_length;
+ if (alen > 0) {
+ if (buf[0] == 0x88) {
+ ntrans++;
+ len += alen;
+ } else if (buf[0] == 0x22) {
+ printk(KERN_DEBUG
+ "= l=%d nt=%d bpp=%d\n",
+ len - 4 * ntrans, ntrans,
+ ntrans == 0 ? 0 : len / ntrans);
+ ntrans = 1;
+ len = alen;
+ } else
+ printk(KERN_DEBUG "!\n");
+ }
+ printk(KERN_DEBUG " n=%d s=%d al=%d %x\n", i,
+ urb->iso_frame_desc[i].status,
+ urb->iso_frame_desc[i].actual_length,
+ (unsigned int)
+ *((unsigned char *)(urb->transfer_buffer +
+ urb->iso_frame_desc[i].
+ offset)));
+ }
+}
+#endif
+
+static inline int em28xx_isoc_video(struct em28xx *dev,struct em28xx_frame_t **f,
+ unsigned long *lock_flags, unsigned char buf)
+{
+ if (!(buf & 0x01)) {
+ if ((*f)->state == F_GRABBING) {
+ /*previous frame is incomplete */
+ if ((*f)->fieldbytesused < dev->field_size) {
+ (*f)->state = F_ERROR;
+ em28xx_isocdbg ("dropping incomplete bottom field (%i missing bytes)",
+ dev->field_size-(*f)->fieldbytesused);
+ } else {
+ (*f)->state = F_DONE;
+ (*f)->buf.bytesused = dev->frame_size;
+ }
+ }
+ if ((*f)->state == F_DONE || (*f)->state == F_ERROR) {
+ /* move current frame to outqueue and get next free buffer from inqueue */
+ spin_lock_irqsave(&dev-> queue_lock, *lock_flags);
+ list_move_tail(&(*f)->frame, &dev->outqueue);
+ if (!list_empty(&dev->inqueue))
+ (*f) = list_entry(dev-> inqueue.next,
+ struct em28xx_frame_t,frame);
+ else
+ (*f) = NULL;
+ spin_unlock_irqrestore(&dev->queue_lock,*lock_flags);
+ }
+ if (!(*f)) {
+ em28xx_isocdbg ("new frame but no buffer is free");
+ return -1;
+ }
+ do_gettimeofday(&(*f)->buf.timestamp);
+ (*f)->buf.sequence = ++dev->frame_count;
+ (*f)->buf.field = V4L2_FIELD_INTERLACED;
+ (*f)->state = F_GRABBING;
+ (*f)->buf.bytesused = 0;
+ (*f)->top_field = 1;
+ (*f)->fieldbytesused = 0;
+ } else {
+ /* acquiring bottom field */
+ if ((*f)->state == F_GRABBING) {
+ if (!(*f)->top_field) {
+ (*f)->state = F_ERROR;
+ em28xx_isocdbg ("unexpected begin of bottom field; discarding it");
+ } else if ((*f)-> fieldbytesused < dev->field_size - 172) {
+ (*f)->state = F_ERROR;
+ em28xx_isocdbg ("dropping incomplete top field (%i missing bytes)",
+ dev->field_size-(*f)->fieldbytesused);
+ } else {
+ (*f)->top_field = 0;
+ (*f)->fieldbytesused = 0;
+ }
+ }
+ }
+ return (0);
+}
+
+static inline void em28xx_isoc_video_copy(struct em28xx *dev,
+ struct em28xx_frame_t **f, unsigned char *buf, int len)
+{
+ void *fieldstart, *startwrite, *startread;
+ int linesdone, currlinedone, offset, lencopy,remain;
+
+ if(dev->frame_size != (*f)->buf.length){
+ em28xx_err("frame_size %i and buf.length %i are different!!!\n",dev->frame_size,(*f)->buf.length);
+ return;
+ }
+
+ if ((*f)->fieldbytesused + len > dev->field_size)
+ len =dev->field_size - (*f)->fieldbytesused;
+
+ if (buf[0] != 0x88 && buf[0] != 0x22) {
+ em28xx_isocdbg("frame is not complete\n");
+ startread = buf;
+ len+=4;
+ } else
+ startread = buf + 4;
+
+ remain = len;
+
+ if ((*f)->top_field)
+ fieldstart = (*f)->bufmem;
+ else
+ fieldstart = (*f)->bufmem + dev->bytesperline;
+
+ linesdone = (*f)->fieldbytesused / dev->bytesperline;
+ currlinedone = (*f)->fieldbytesused % dev->bytesperline;
+ offset = linesdone * dev->bytesperline * 2 + currlinedone;
+ startwrite = fieldstart + offset;
+ lencopy = dev->bytesperline - currlinedone;
+ lencopy = lencopy > remain ? remain : lencopy;
+
+ memcpy(startwrite, startread, lencopy);
+ remain -= lencopy;
+
+ while (remain > 0) {
+ startwrite += lencopy + dev->bytesperline;
+ startread += lencopy;
+ if (dev->bytesperline > remain)
+ lencopy = remain;
+ else
+ lencopy = dev->bytesperline;
+
+ memcpy(startwrite, startread, lencopy);
+ remain -= lencopy;
+ }
+
+ (*f)->fieldbytesused += len;
+}
+
+/*
+ * em28xx_isoIrq()
+ * handles the incoming isoc urbs and fills the frames from our inqueue
+ */
+void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
+{
+ struct em28xx *dev = urb->context;
+ int i, status;
+ struct em28xx_frame_t **f;
+ unsigned long lock_flags;
+
+ if (!dev)
+ return;
+#ifdef ENABLE_DEBUG_ISOC_FRAMES
+ if (isoc_debug>1)
+ em28xx_isoc_dump(urb, regs);
+#endif
+
+ if (urb->status == -ENOENT)
+ return;
+
+ f = &dev->frame_current;
+
+ if (dev->stream == STREAM_INTERRUPT) {
+ dev->stream = STREAM_OFF;
+ if ((*f))
+ (*f)->state = F_QUEUED;
+ em28xx_isocdbg("stream interrupted");
+ wake_up_interruptible(&dev->wait_stream);
+ }
+
+ if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ return;
+
+ if (dev->stream == STREAM_ON && !list_empty(&dev->inqueue)) {
+ if (!(*f))
+ (*f) = list_entry(dev->inqueue.next,
+ struct em28xx_frame_t, frame);
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ unsigned char *buf = urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset;
+ int len = urb->iso_frame_desc[i].actual_length - 4;
+
+ if (urb->iso_frame_desc[i].status) {
+ em28xx_isocdbg("data error: [%d] len=%d, status=%d", i,
+ urb->iso_frame_desc[i].actual_length,
+ urb->iso_frame_desc[i].status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+ if (urb->iso_frame_desc[i].actual_length <= 0) {
+ em28xx_isocdbg("packet %d is empty",i);
+ continue;
+ }
+ if (urb->iso_frame_desc[i].actual_length >
+ dev->max_pkt_size) {
+ em28xx_isocdbg("packet bigger than packet size");
+ continue;
+ }
+ /*new frame */
+ if (buf[0] == 0x22 && buf[1] == 0x5a) {
+ em28xx_isocdbg("Video frame, length=%i!",len);
+
+ if (em28xx_isoc_video(dev,f,&lock_flags,buf[2]))
+ break;
+ } else if (buf[0]==0x33 && buf[1]==0x95 && buf[2]==0x00) {
+ em28xx_isocdbg("VBI HEADER!!!");
+ }
+
+ /* actual copying */
+ if ((*f)->state == F_GRABBING) {
+ em28xx_isoc_video_copy(dev,f,buf, len);
+ }
+ }
+ }
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ urb->iso_frame_desc[i].status = 0;
+ urb->iso_frame_desc[i].actual_length = 0;
+ }
+
+ urb->status = 0;
+ if ((status = usb_submit_urb(urb, GFP_ATOMIC))) {
+ em28xx_errdev("resubmit of urb failed (error=%i)\n", status);
+ dev->state |= DEV_MISCONFIGURED;
+ }
+ wake_up_interruptible(&dev->wait_frame);
+ return;
+}
+
+/*
+ * em28xx_uninit_isoc()
+ * deallocates the buffers and urbs allocated during em28xx_init_iosc()
+ */
+void em28xx_uninit_isoc(struct em28xx *dev)
+{
+ int i;
+
+ for (i = 0; i < EM28XX_NUM_BUFS; i++) {
+ if (dev->urb[i]) {
+ usb_kill_urb(dev->urb[i]);
+ if (dev->transfer_buffer[i]){
+ usb_buffer_free(dev->udev,(EM28XX_NUM_PACKETS*dev->max_pkt_size),dev->transfer_buffer[i],dev->urb[i]->transfer_dma);
+ }
+ usb_free_urb(dev->urb[i]);
+ }
+ dev->urb[i] = NULL;
+ dev->transfer_buffer[i] = NULL;
+ }
+ em28xx_capture_start(dev, 0);
+}
+
+/*
+ * em28xx_init_isoc()
+ * allocates transfer buffers and submits the urbs for isoc transfer
+ */
+int em28xx_init_isoc(struct em28xx *dev)
+{
+ /* change interface to 3 which allowes the biggest packet sizes */
+ int i, errCode;
+ const int sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size;
+
+ /* reset streaming vars */
+ dev->frame_current = NULL;
+ dev->frame_count = 0;
+
+ /* allocate urbs */
+ for (i = 0; i < EM28XX_NUM_BUFS; i++) {
+ struct urb *urb;
+ int j, k;
+ /* allocate transfer buffer */
+ urb = usb_alloc_urb(EM28XX_NUM_PACKETS, GFP_KERNEL);
+ if (!urb){
+ em28xx_errdev("cannot alloc urb %i\n", i);
+ em28xx_uninit_isoc(dev);
+ return -ENOMEM;
+ }
+ dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size, GFP_KERNEL,&urb->transfer_dma);
+ if (!dev->transfer_buffer[i]) {
+ em28xx_errdev
+ ("unable to allocate %i bytes for transfer buffer %i\n",
+ sb_size, i);
+ em28xx_uninit_isoc(dev);
+ return -ENOMEM;
+ }
+ memset(dev->transfer_buffer[i], 0, sb_size);
+ urb->dev = dev->udev;
+ urb->context = dev;
+ urb->pipe = usb_rcvisocpipe(dev->udev, 0x82);
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->interval = 1;
+ urb->transfer_buffer = dev->transfer_buffer[i];
+ urb->complete = em28xx_isocIrq;
+ urb->number_of_packets = EM28XX_NUM_PACKETS;
+ urb->transfer_buffer_length = sb_size;
+ for (j = k = 0; j < EM28XX_NUM_PACKETS;
+ j++, k += dev->max_pkt_size) {
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length =
+ dev->max_pkt_size;
+ }
+ dev->urb[i] = urb;
+ }
+
+ /* submit urbs */
+ for (i = 0; i < EM28XX_NUM_BUFS; i++) {
+ errCode = usb_submit_urb(dev->urb[i], GFP_KERNEL);
+ if (errCode) {
+ em28xx_errdev("submit of urb %i failed (error=%i)\n", i,
+ errCode);
+ em28xx_uninit_isoc(dev);
+ return errCode;
+ }
+ }
+
+ return 0;
+}
+
+int em28xx_set_alternate(struct em28xx *dev)
+{
+ int errCode, prev_alt = dev->alt;
+ dev->alt = alt;
+ if (dev->alt == 0) {
+ int i;
+ for(i=0;i< dev->num_alt; i++)
+ if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->alt])
+ dev->alt=i;
+ }
+
+ if (dev->alt != prev_alt) {
+ dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
+ em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", dev->alt,
+ dev->max_pkt_size);
+ errCode = usb_set_interface(dev->udev, 0, dev->alt);
+ if (errCode < 0) {
+ em28xx_errdev ("cannot change alternate number to %d (error=%i)\n",
+ dev->alt, errCode);
+ return errCode;
+ }
+ }
+ return 0;
+}
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
new file mode 100644
index 00000000000..b32d9852f34
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -0,0 +1,586 @@
+/*
+ em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+ Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+ Markus Rechberger <mrechberger@gmail.com>
+ Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Sascha Sommer <saschasommer@freenet.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; 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/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/video_decoder.h>
+
+#include "em28xx.h"
+#include <media/tuner.h>
+
+/* ----------------------------------------------------------- */
+
+static unsigned int i2c_scan = 0;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+static unsigned int i2c_debug = 0;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+#define dprintk1(lvl,fmt, args...) if (i2c_debug>=lvl) do {\
+ printk(fmt , ##args); } while (0)
+#define dprintk2(lvl,fmt, args...) if (i2c_debug>=lvl) do{ \
+ printk(KERN_DEBUG "%s at %s: " fmt, \
+ dev->name, __FUNCTION__ , ##args); } while (0)
+
+/*
+ * em2800_i2c_send_max4()
+ * send up to 4 bytes to the i2c device
+ */
+static int em2800_i2c_send_max4(struct em28xx *dev, unsigned char addr,
+ char *buf, int len)
+{
+ int ret;
+ int write_timeout;
+ unsigned char b2[6];
+ BUG_ON(len < 1 || len > 4);
+ b2[5] = 0x80 + len - 1;
+ b2[4] = addr;
+ b2[3] = buf[0];
+ if (len > 1)
+ b2[2] = buf[1];
+ if (len > 2)
+ b2[1] = buf[2];
+ if (len > 3)
+ b2[0] = buf[3];
+
+ ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
+ if (ret != 2 + len) {
+ em28xx_warn("writting to i2c device failed (error=%i)\n", ret);
+ return -EIO;
+ }
+ for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+ write_timeout -= 5) {
+ ret = dev->em28xx_read_reg(dev, 0x05);
+ if (ret == 0x80 + len - 1)
+ return len;
+ mdelay(5);
+ }
+ em28xx_warn("i2c write timed out\n");
+ return -EIO;
+}
+
+/*
+ * em2800_i2c_send_bytes()
+ */
+static int em2800_i2c_send_bytes(void *data, unsigned char addr, char *buf,
+ short len)
+{
+ char *bufPtr = buf;
+ int ret;
+ int wrcount = 0;
+ int count;
+ int maxLen = 4;
+ struct em28xx *dev = (struct em28xx *)data;
+ while (len > 0) {
+ count = (len > maxLen) ? maxLen : len;
+ ret = em2800_i2c_send_max4(dev, addr, bufPtr, count);
+ if (ret > 0) {
+ len -= count;
+ bufPtr += count;
+ wrcount += count;
+ } else
+ return (ret < 0) ? ret : -EFAULT;
+ }
+ return wrcount;
+}
+
+/*
+ * em2800_i2c_check_for_device()
+ * check if there is a i2c_device at the supplied address
+ */
+static int em2800_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
+{
+ char msg;
+ int ret;
+ int write_timeout;
+ msg = addr;
+ ret = dev->em28xx_write_regs(dev, 0x04, &msg, 1);
+ if (ret < 0) {
+ em28xx_warn("setting i2c device address failed (error=%i)\n",
+ ret);
+ return ret;
+ }
+ msg = 0x84;
+ ret = dev->em28xx_write_regs(dev, 0x05, &msg, 1);
+ if (ret < 0) {
+ em28xx_warn("preparing i2c read failed (error=%i)\n", ret);
+ return ret;
+ }
+ for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+ write_timeout -= 5) {
+ unsigned msg = dev->em28xx_read_reg(dev, 0x5);
+ if (msg == 0x94)
+ return -ENODEV;
+ else if (msg == 0x84)
+ return 0;
+ mdelay(5);
+ }
+ return -ENODEV;
+}
+
+/*
+ * em2800_i2c_recv_bytes()
+ * read from the i2c device
+ */
+static int em2800_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
+ char *buf, int len)
+{
+ int ret;
+ /* check for the device and set i2c read address */
+ ret = em2800_i2c_check_for_device(dev, addr);
+ if (ret) {
+ em28xx_warn
+ ("preparing read at i2c address 0x%x failed (error=%i)\n",
+ addr, ret);
+ return ret;
+ }
+ ret = dev->em28xx_read_reg_req_len(dev, 0x0, 0x3, buf, len);
+ if (ret < 0) {
+ em28xx_warn("reading from i2c device at 0x%x failed (error=%i)",
+ addr, ret);
+ return ret;
+ }
+ return ret;
+}
+
+/*
+ * em28xx_i2c_send_bytes()
+ * untested for more than 4 bytes
+ */
+static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf,
+ short len, int stop)
+{
+ int wrcount = 0;
+ struct em28xx *dev = (struct em28xx *)data;
+
+ wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
+
+ return wrcount;
+}
+
+/*
+ * em28xx_i2c_recv_bytes()
+ * read a byte from the i2c device
+ */
+static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
+ char *buf, int len)
+{
+ int ret;
+ ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
+ if (ret < 0) {
+ em28xx_warn("reading i2c device failed (error=%i)\n", ret);
+ return ret;
+ }
+ if (dev->em28xx_read_reg(dev, 0x5) != 0)
+ return -ENODEV;
+ return ret;
+}
+
+/*
+ * em28xx_i2c_check_for_device()
+ * check if there is a i2c_device at the supplied address
+ */
+static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
+{
+ char msg;
+ int ret;
+ msg = addr;
+
+ ret = dev->em28xx_read_reg_req(dev, 2, addr);
+ if (ret < 0) {
+ em28xx_warn("reading from i2c device failed (error=%i)\n", ret);
+ return ret;
+ }
+ if (dev->em28xx_read_reg(dev, 0x5) != 0)
+ return -ENODEV;
+ return 0;
+}
+
+/*
+ * em28xx_i2c_xfer()
+ * the main i2c transfer function
+ */
+static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msgs[], int num)
+{
+ struct em28xx *dev = i2c_adap->algo_data;
+ int addr, rc, i, byte;
+
+ if (num <= 0)
+ return 0;
+ for (i = 0; i < num; i++) {
+ addr = msgs[i].addr << 1;
+ dprintk2(2,"%s %s addr=%x len=%d:",
+ (msgs[i].flags & I2C_M_RD) ? "read" : "write",
+ i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
+ if (!msgs[i].len) { /* no len: check only for device presence */
+ if (dev->is_em2800)
+ rc = em2800_i2c_check_for_device(dev, addr);
+ else
+ rc = em28xx_i2c_check_for_device(dev, addr);
+ if (rc < 0) {
+ dprintk2(2," no device\n");
+ return rc;
+ }
+
+ } else if (msgs[i].flags & I2C_M_RD) {
+ /* read bytes */
+ if (dev->is_em2800)
+ rc = em2800_i2c_recv_bytes(dev, addr,
+ msgs[i].buf,
+ msgs[i].len);
+ else
+ rc = em28xx_i2c_recv_bytes(dev, addr,
+ msgs[i].buf,
+ msgs[i].len);
+ if (i2c_debug>=2) {
+ for (byte = 0; byte < msgs[i].len; byte++) {
+ printk(" %02x", msgs[i].buf[byte]);
+ }
+ }
+ } else {
+ /* write bytes */
+ if (i2c_debug>=2) {
+ for (byte = 0; byte < msgs[i].len; byte++)
+ printk(" %02x", msgs[i].buf[byte]);
+ }
+ if (dev->is_em2800)
+ rc = em2800_i2c_send_bytes(dev, addr,
+ msgs[i].buf,
+ msgs[i].len);
+ else
+ rc = em28xx_i2c_send_bytes(dev, addr,
+ msgs[i].buf,
+ msgs[i].len,
+ i == num - 1);
+ if (rc < 0)
+ goto err;
+ }
+ if (i2c_debug>=2)
+ printk("\n");
+ }
+
+ return num;
+ err:
+ dprintk2(2," ERROR: %i\n", rc);
+ return rc;
+}
+
+static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
+{
+ unsigned char buf, *p = eedata;
+ struct em28xx_eeprom *em_eeprom = (void *)eedata;
+ int i, err, size = len, block;
+
+ dev->i2c_client.addr = 0xa0 >> 1;
+
+ /* Check if board has eeprom */
+ err = i2c_master_recv(&dev->i2c_client, &buf, 0);
+ if (err < 0)
+ return -1;
+
+ buf = 0;
+ if (1 != (err = i2c_master_send(&dev->i2c_client, &buf, 1))) {
+ printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
+ dev->name, err);
+ return -1;
+ }
+ while (size > 0) {
+ if (size > 16)
+ block = 16;
+ else
+ block = size;
+
+ if (block !=
+ (err = i2c_master_recv(&dev->i2c_client, p, block))) {
+ printk(KERN_WARNING
+ "%s: i2c eeprom read error (err=%d)\n",
+ dev->name, err);
+ return -1;
+ }
+ size -= block;
+ p += block;
+ }
+ for (i = 0; i < len; i++) {
+ if (0 == (i % 16))
+ printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
+ printk(" %02x", eedata[i]);
+ if (15 == (i % 16))
+ printk("\n");
+ }
+
+ printk(KERN_INFO "EEPROM ID= 0x%08x\n", em_eeprom->id);
+ printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID,
+ em_eeprom->product_ID);
+
+ switch (em_eeprom->chip_conf >> 4 & 0x3) {
+ case 0:
+ printk(KERN_INFO "No audio on board.\n");
+ break;
+ case 1:
+ printk(KERN_INFO "AC97 audio (5 sample rates)\n");
+ break;
+ case 2:
+ printk(KERN_INFO "I2S audio, sample rate=32k\n");
+ break;
+ case 3:
+ printk(KERN_INFO "I2S audio, 3 sample rates\n");
+ break;
+ }
+
+ if (em_eeprom->chip_conf & 1 << 3)
+ printk(KERN_INFO "USB Remote wakeup capable\n");
+
+ if (em_eeprom->chip_conf & 1 << 2)
+ printk(KERN_INFO "USB Self power capable\n");
+
+ switch (em_eeprom->chip_conf & 0x3) {
+ case 0:
+ printk(KERN_INFO "500mA max power\n");
+ break;
+ case 1:
+ printk(KERN_INFO "400mA max power\n");
+ break;
+ case 2:
+ printk(KERN_INFO "300mA max power\n");
+ break;
+ case 3:
+ printk(KERN_INFO "200mA max power\n");
+ break;
+ }
+ printk(KERN_INFO "Table at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
+ em_eeprom->string_idx_table,em_eeprom->string1,
+ em_eeprom->string2,em_eeprom->string3);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------- */
+
+/*
+ * algo_control()
+ */
+static int algo_control(struct i2c_adapter *adapter,
+ unsigned int cmd, unsigned long arg)
+{
+ return 0;
+}
+
+/*
+ * functionality()
+ */
+static u32 functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL;
+}
+
+#ifndef I2C_PEC
+static void inc_use(struct i2c_adapter *adap)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use(struct i2c_adapter *adap)
+{
+ MOD_DEC_USE_COUNT;
+}
+#endif
+
+static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client)
+{
+ struct em28xx *dev = client->adapter->algo_data;
+ struct tuner_setup tun_setup;
+
+ if (dev->has_tuner) {
+ tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+ tun_setup.type = dev->tuner_type;
+ tun_setup.addr = dev->tuner_addr;
+
+ em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
+
+ return (0);
+}
+
+/*
+ * attach_inform()
+ * gets called when a device attaches to the i2c bus
+ * does some basic configuration
+ */
+static int attach_inform(struct i2c_client *client)
+{
+ struct em28xx *dev = client->adapter->algo_data;
+
+ switch (client->addr << 1) {
+ case 0x86:
+ em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf);
+ break;
+ case 0x42:
+ dprintk1(1,"attach_inform: saa7114 detected.\n");
+ break;
+ case 0x4a:
+ dprintk1(1,"attach_inform: saa7113 detected.\n");
+ break;
+ case 0xa0:
+ dprintk1(1,"attach_inform: eeprom detected.\n");
+ break;
+ case 0x60:
+ case 0x8e:
+ {
+ struct IR_i2c *ir = i2c_get_clientdata(client);
+ dprintk1(1,"attach_inform: IR detected (%s).\n",ir->phys);
+ em28xx_set_ir(dev,ir);
+ break;
+ }
+ case 0x80:
+ case 0x88:
+ dprintk1(1,"attach_inform: msp34xx detected.\n");
+ break;
+ case 0xb8:
+ case 0xba:
+ dprintk1(1,"attach_inform: tvp5150 detected.\n");
+ break;
+ default:
+ dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
+ dev->tuner_addr = client->addr;
+ em28xx_set_tuner(-1, client);
+ }
+
+ return 0;
+}
+
+static struct i2c_algorithm em28xx_algo = {
+ .master_xfer = em28xx_i2c_xfer,
+ .algo_control = algo_control,
+ .functionality = functionality,
+};
+
+static struct i2c_adapter em28xx_adap_template = {
+#ifdef I2C_PEC
+ .owner = THIS_MODULE,
+#else
+ .inc_use = inc_use,
+ .dec_use = dec_use,
+#endif
+#ifdef I2C_CLASS_TV_ANALOG
+ .class = I2C_CLASS_TV_ANALOG,
+#endif
+ .name = "em28xx",
+ .id = I2C_HW_B_EM28XX,
+ .algo = &em28xx_algo,
+ .client_register = attach_inform,
+};
+
+static struct i2c_client em28xx_client_template = {
+ .name = "em28xx internal",
+ .flags = I2C_CLIENT_ALLOW_USE,
+};
+
+/* ----------------------------------------------------------- */
+
+/*
+ * i2c_devs
+ * incomplete list of known devices
+ */
+static char *i2c_devs[128] = {
+ [0x4a >> 1] = "saa7113h",
+ [0x60 >> 1] = "remote IR sensor",
+ [0x8e >> 1] = "remote IR sensor",
+ [0x86 >> 1] = "tda9887",
+ [0x80 >> 1] = "msp34xx",
+ [0x88 >> 1] = "msp34xx",
+ [0xa0 >> 1] = "eeprom",
+ [0xb8 >> 1] = "tvp5150a",
+ [0xba >> 1] = "tvp5150a",
+ [0xc0 >> 1] = "tuner (analog)",
+ [0xc2 >> 1] = "tuner (analog)",
+ [0xc4 >> 1] = "tuner (analog)",
+ [0xc6 >> 1] = "tuner (analog)",
+};
+
+/*
+ * do_i2c_scan()
+ * check i2c address range for devices
+ */
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+ unsigned char buf;
+ int i, rc;
+
+ for (i = 0; i < 128; i++) {
+ c->addr = i;
+ rc = i2c_master_recv(c, &buf, 0);
+ if (rc < 0)
+ continue;
+ printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name,
+ i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+ }
+}
+
+/*
+ * em28xx_i2c_call_clients()
+ * send commands to all attached i2c devices
+ */
+void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg)
+{
+ BUG_ON(NULL == dev->i2c_adap.algo_data);
+ i2c_clients_command(&dev->i2c_adap, cmd, arg);
+}
+
+/*
+ * em28xx_i2c_register()
+ * register i2c bus
+ */
+int em28xx_i2c_register(struct em28xx *dev)
+{
+ BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
+ BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
+ dev->i2c_adap = em28xx_adap_template;
+ dev->i2c_adap.dev.parent = &dev->udev->dev;
+ strcpy(dev->i2c_adap.name, dev->name);
+ dev->i2c_adap.algo_data = dev;
+ i2c_add_adapter(&dev->i2c_adap);
+
+ dev->i2c_client = em28xx_client_template;
+ dev->i2c_client.adapter = &dev->i2c_adap;
+
+ em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
+
+ if (i2c_scan)
+ do_i2c_scan(dev->name, &dev->i2c_client);
+ return 0;
+}
+
+/*
+ * em28xx_i2c_unregister()
+ * unregister i2c_bus
+ */
+int em28xx_i2c_unregister(struct em28xx *dev)
+{
+ i2c_del_adapter(&dev->i2c_adap);
+ return 0;
+}
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
new file mode 100644
index 00000000000..32c49df58ad
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -0,0 +1,184 @@
+/*
+ handle em28xx IR remotes via linux kernel input layer.
+
+ Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+ Markus Rechberger <mrechberger@gmail.com>
+ Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Sascha Sommer <saschasommer@freenet.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; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include "em28xx.h"
+
+static unsigned int disable_ir = 0;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
+
+static unsigned int ir_debug = 0;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+
+#define dprintk(fmt, arg...) if (ir_debug) \
+ printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
+
+/* ---------------------------------------------------------------------- */
+
+static IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = {
+ [ 0x01 ] = KEY_CHANNEL,
+ [ 0x02 ] = KEY_SELECT,
+ [ 0x03 ] = KEY_MUTE,
+ [ 0x04 ] = KEY_POWER,
+ [ 0x05 ] = KEY_KP1,
+ [ 0x06 ] = KEY_KP2,
+ [ 0x07 ] = KEY_KP3,
+ [ 0x08 ] = KEY_CHANNELUP,
+ [ 0x09 ] = KEY_KP4,
+ [ 0x0a ] = KEY_KP5,
+ [ 0x0b ] = KEY_KP6,
+ [ 0x0c ] = KEY_CHANNELDOWN,
+ [ 0x0d ] = KEY_KP7,
+ [ 0x0e ] = KEY_KP8,
+ [ 0x0f ] = KEY_KP9,
+ [ 0x10 ] = KEY_VOLUMEUP,
+ [ 0x11 ] = KEY_KP0,
+ [ 0x12 ] = KEY_MENU,
+ [ 0x13 ] = KEY_PRINT,
+ [ 0x14 ] = KEY_VOLUMEDOWN,
+ [ 0x16 ] = KEY_PAUSE,
+ [ 0x18 ] = KEY_RECORD,
+ [ 0x19 ] = KEY_REWIND,
+ [ 0x1a ] = KEY_PLAY,
+ [ 0x1b ] = KEY_FORWARD,
+ [ 0x1c ] = KEY_BACKSPACE,
+ [ 0x1e ] = KEY_STOP,
+ [ 0x40 ] = KEY_ZOOM,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ unsigned char b;
+
+ /* poll IR chip */
+ if (1 != i2c_master_recv(&ir->c,&b,1)) {
+ dprintk("read error\n");
+ return -EIO;
+ }
+
+ /* it seems that 0xFE indicates that a button is still hold
+ down, while 0xff indicates that no button is hold
+ down. 0xfe sequences are sometimes interrupted by 0xFF */
+
+ dprintk("key %02x\n", b);
+
+ if (b == 0xff)
+ return 0;
+
+ if (b == 0xfe)
+ /* keep old data */
+ return 1;
+
+ *ir_key = b;
+ *ir_raw = b;
+ return 1;
+}
+
+
+static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ unsigned char buf[2];
+ unsigned char code;
+
+ /* poll IR chip */
+ if (2 != i2c_master_recv(&ir->c,buf,2))
+ return -EIO;
+
+ /* Does eliminate repeated parity code */
+ if (buf[1]==0xff)
+ return 0;
+
+ /* avoid fast reapeating */
+ if (buf[1]==ir->old)
+ return 0;
+ ir->old=buf[1];
+
+ /* Rearranges bits to the right order */
+ code= ((buf[0]&0x01)<<5) | /* 0010 0000 */
+ ((buf[0]&0x02)<<3) | /* 0001 0000 */
+ ((buf[0]&0x04)<<1) | /* 0000 1000 */
+ ((buf[0]&0x08)>>1) | /* 0000 0100 */
+ ((buf[0]&0x10)>>3) | /* 0000 0010 */
+ ((buf[0]&0x20)>>5); /* 0000 0001 */
+
+ dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",code,buf[0]);
+
+ /* return key */
+ *ir_key = code;
+ *ir_raw = code;
+ return 1;
+}
+
+/* ----------------------------------------------------------------------- */
+void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir)
+{
+ if (disable_ir) {
+ ir->get_key=NULL;
+ return ;
+ }
+
+ /* detect & configure */
+ switch (dev->model) {
+ case (EM2800_BOARD_UNKNOWN):
+ break;
+ case (EM2820_BOARD_UNKNOWN):
+ break;
+ case (EM2800_BOARD_TERRATEC_CINERGY_200):
+ case (EM2820_BOARD_TERRATEC_CINERGY_250):
+ ir->ir_codes = ir_codes_em_terratec;
+ ir->get_key = get_key_terratec;
+ snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)");
+ break;
+ case (EM2820_BOARD_PINNACLE_USB_2):
+ break;
+ case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
+ ir->ir_codes = ir_codes_hauppauge_new;
+ ir->get_key = get_key_em_haup;
+ snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM2840 Hauppauge)");
+ break;
+ case (EM2820_BOARD_MSI_VOX_USB_2):
+ break;
+ case (EM2800_BOARD_LEADTEK_WINFAST_USBII):
+ break;
+ case (EM2800_BOARD_KWORLD_USB2800):
+ break;
+ }
+}
+
+/* ----------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
new file mode 100644
index 00000000000..57c1826b928
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -0,0 +1,1933 @@
+/*
+ em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+ Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+ Markus Rechberger <mrechberger@gmail.com>
+ Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Sascha Sommer <saschasommer@freenet.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; 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/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/version.h>
+#include <linux/video_decoder.h>
+
+#include "em28xx.h"
+#include <media/tuner.h>
+
+#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
+ "Markus Rechberger <mrechberger@gmail.com>, " \
+ "Mauro Carvalho Chehab <mchehab@brturbo.com.br>, " \
+ "Sascha Sommer <saschasommer@freenet.de>"
+
+#define DRIVER_NAME "em28xx"
+#define DRIVER_DESC "Empia em28xx based USB video device driver"
+#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 0, 1)
+
+#define em28xx_videodbg(fmt, arg...) do {\
+ if (video_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __FUNCTION__ , ##arg); } while (0)
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+static LIST_HEAD(em28xx_devlist);
+
+static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+module_param_array(card, int, NULL, 0444);
+MODULE_PARM_DESC(card,"card type");
+
+static int tuner = -1;
+module_param(tuner, int, 0444);
+MODULE_PARM_DESC(tuner, "tuner type");
+
+static unsigned int video_debug = 0;
+module_param(video_debug,int,0644);
+MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
+
+/* supported tv norms */
+static struct em28xx_tvnorm tvnorms[] = {
+ {
+ .name = "PAL",
+ .id = V4L2_STD_PAL,
+ .mode = VIDEO_MODE_PAL,
+ }, {
+ .name = "NTSC",
+ .id = V4L2_STD_NTSC,
+ .mode = VIDEO_MODE_NTSC,
+ }, {
+ .name = "SECAM",
+ .id = V4L2_STD_SECAM,
+ .mode = VIDEO_MODE_SECAM,
+ }, {
+ .name = "PAL-M",
+ .id = V4L2_STD_PAL_M,
+ .mode = VIDEO_MODE_PAL,
+ }
+};
+
+static const unsigned char saa7114_i2c_init[] = {
+ 0x00,0x00,0x01,0x08,0x02,0xc4,0x03,0x30,0x04,0x90,0x05,0x90,0x06,0xeb,0x07,0xe0,
+ 0x08,0x88,0x09,0x40,0x0a,0x80,0x0b,0x44,0x0c,0x40,0x0d,0x00,0x0e,0x81,0x0f,0x2a,
+ 0x10,0x06,0x11,0x00,0x12,0xc8,0x13,0x80,0x14,0x00,0x15,0x11,0x16,0x01,0x17,0x42,
+ 0x18,0x40,0x19,0x80,0x40,0x00,0x41,0xff,0x42,0xff,0x43,0xff,0x44,0xff,0x45,0xff,
+ 0x46,0xff,0x47,0xff,0x48,0xff,0x49,0xff,0x4a,0xff,0x4b,0xff,0x4c,0xff,0x4d,0xff,
+ 0x4e,0xff,0x4f,0xff,0x50,0xff,0x51,0xff,0x52,0xff,0x53,0xff,0x54,0x5f,0x55,0xff,
+ 0x56,0xff,0x57,0xff,0x58,0x00,0x59,0x47,0x5a,0x03,0x5b,0x03,0x5d,0x3e,0x5e,0x00,
+ 0x80,0x1c,0x83,0x01,0x84,0xa5,0x85,0x10,0x86,0x45,0x87,0x41,0x88,0xf0,0x88,0x00,
+ 0x88,0xf0,0x90,0x00,0x91,0x08,0x92,0x00,0x93,0x80,0x94,0x08,0x95,0x00,0x96,0xc0,
+ 0x97,0x02,0x98,0x13,0x99,0x00,0x9a,0x38,0x9b,0x01,0x9c,0x80,0x9d,0x02,0x9e,0x06,
+ 0x9f,0x01,0xa0,0x01,0xa1,0x00,0xa2,0x00,0xa4,0x80,0xa5,0x36,0xa6,0x36,0xa8,0x67,
+ 0xa9,0x04,0xaa,0x00,0xac,0x33,0xad,0x02,0xae,0x00,0xb0,0xcd,0xb1,0x04,0xb2,0xcd,
+ 0xb3,0x04,0xb4,0x01,0xb8,0x00,0xb9,0x00,0xba,0x00,0xbb,0x00,0xbc,0x00,0xbd,0x00,
+ 0xbe,0x00,0xbf,0x00
+};
+
+#define TVNORMS ARRAY_SIZE(tvnorms)
+
+/* supported controls */
+static struct v4l2_queryctrl em28xx_qctrl[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ },{
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0x0,
+ .maximum = 0x1f,
+ .step = 0x1,
+ .default_value = 0x10,
+ .flags = 0,
+ },{
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0x0,
+ .maximum = 0x1f,
+ .step = 0x1,
+ .default_value = 0x10,
+ .flags = 0,
+ },{
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Volume",
+ .minimum = 0x0,
+ .maximum = 0x1f,
+ .step = 0x1,
+ .default_value = 0x1f,
+ .flags = 0,
+ },{
+ .id = V4L2_CID_AUDIO_MUTE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ .flags = 0,
+ },{
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red chroma balance",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ },{
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue chroma balance",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ },{
+ .id = V4L2_CID_GAMMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gamma",
+ .minimum = 0x0,
+ .maximum = 0x3f,
+ .step = 0x1,
+ .default_value = 0x20,
+ .flags = 0,
+ }
+};
+
+static struct usb_driver em28xx_usb_driver;
+
+static DECLARE_MUTEX(em28xx_sysfs_lock);
+static DECLARE_RWSEM(em28xx_disconnect);
+
+/********************* v4l2 interface ******************************************/
+
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+ unsigned long kva, ret;
+
+ kva = (unsigned long)page_address(vmalloc_to_page((void *)adr));
+ kva |= adr & (PAGE_SIZE - 1);
+ ret = __pa(kva);
+ return ret;
+}
+
+/*
+ * em28xx_config()
+ * inits registers with sane defaults
+ */
+static int em28xx_config(struct em28xx *dev)
+{
+
+ /* Sets I2C speed to 100 KHz */
+ em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
+
+ /* enable vbi capturing */
+ em28xx_audio_usb_mute(dev, 1);
+ dev->mute = 1; /* maybe not the right place... */
+ dev->volume = 0x1f;
+ em28xx_audio_analog_set(dev);
+ em28xx_audio_analog_setup(dev);
+ em28xx_outfmt_set_yuv422(dev);
+ em28xx_colorlevels_set_default(dev);
+ em28xx_compression_disable(dev);
+
+ return 0;
+}
+
+/*
+ * em28xx_config_i2c()
+ * configure i2c attached devices
+ */
+void em28xx_config_i2c(struct em28xx *dev)
+{
+ struct v4l2_frequency f;
+ struct video_decoder_init em28xx_vdi = {.data = NULL };
+
+
+ /* configure decoder */
+ if(dev->model == EM2820_BOARD_MSI_VOX_USB_2){
+ em28xx_vdi.data=saa7114_i2c_init;
+ em28xx_vdi.len=sizeof(saa7114_i2c_init);
+ }
+
+
+ em28xx_i2c_call_clients(dev, DECODER_INIT, &em28xx_vdi);
+ em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &dev->ctl_input);
+/* em28xx_i2c_call_clients(dev,DECODER_SET_PICTURE, &dev->vpic); */
+/* em28xx_i2c_call_clients(dev,DECODER_SET_NORM,&dev->tvnorm->id); */
+/* em28xx_i2c_call_clients(dev,DECODER_ENABLE_OUTPUT,&output); */
+/* em28xx_i2c_call_clients(dev,DECODER_DUMP, NULL); */
+
+ /* configure tuner */
+ f.tuner = 0;
+ f.type = V4L2_TUNER_ANALOG_TV;
+ f.frequency = 9076; /* FIXME:remove magic number */
+ dev->ctl_freq = f.frequency;
+ em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
+
+ /* configure tda9887 */
+
+
+/* em28xx_i2c_call_clients(dev,VIDIOC_S_STD,&dev->tvnorm->id); */
+}
+
+/*
+ * em28xx_empty_framequeues()
+ * prepare queues for incoming and outgoing frames
+ */
+static void em28xx_empty_framequeues(struct em28xx *dev)
+{
+ u32 i;
+
+ INIT_LIST_HEAD(&dev->inqueue);
+ INIT_LIST_HEAD(&dev->outqueue);
+
+ for (i = 0; i < EM28XX_NUM_FRAMES; i++) {
+ dev->frame[i].state = F_UNUSED;
+ dev->frame[i].buf.bytesused = 0;
+ }
+}
+
+static void video_mux(struct em28xx *dev, int index)
+{
+ int input, ainput;
+
+ input = INPUT(index)->vmux;
+ dev->ctl_input = index;
+ dev->ctl_ainput = INPUT(index)->amux;
+
+ em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &input);
+
+
+ em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
+
+ if (dev->has_msp34xx) {
+ em28xx_i2c_call_clients(dev, VIDIOC_S_AUDIO, &dev->ctl_ainput);
+ ainput = EM28XX_AUDIO_SRC_TUNER;
+ em28xx_audio_source(dev, ainput);
+ } else {
+ switch (dev->ctl_ainput) {
+ case 0:
+ ainput = EM28XX_AUDIO_SRC_TUNER;
+ break;
+ default:
+ ainput = EM28XX_AUDIO_SRC_LINE;
+ }
+ em28xx_audio_source(dev, ainput);
+ }
+}
+
+/*
+ * em28xx_v4l2_open()
+ * inits the device and starts isoc transfer
+ */
+static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
+{
+ int minor = iminor(inode);
+ int errCode = 0;
+ struct em28xx *h,*dev = NULL;
+ struct list_head *list;
+
+ list_for_each(list,&em28xx_devlist) {
+ h = list_entry(list, struct em28xx, devlist);
+ if (h->vdev->minor == minor) {
+ dev = h;
+ }
+ }
+
+ filp->private_data=dev;
+
+
+ em28xx_videodbg("users=%d\n", dev->users);
+
+ if (!down_read_trylock(&em28xx_disconnect))
+ return -ERESTARTSYS;
+
+ if (dev->users) {
+ em28xx_warn("this driver can be opened only once\n");
+ up_read(&em28xx_disconnect);
+ return -EBUSY;
+ }
+
+/* if(dev->vbi_dev->minor == minor){
+ dev->type=V4L2_BUF_TYPE_VBI_CAPTURE;
+ }*/
+ if (dev->vdev->minor == minor) {
+ dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ }
+
+ init_MUTEX(&dev->fileop_lock); /* to 1 == available */
+ spin_lock_init(&dev->queue_lock);
+ init_waitqueue_head(&dev->wait_frame);
+ init_waitqueue_head(&dev->wait_stream);
+
+ down(&dev->lock);
+
+ em28xx_set_alternate(dev);
+
+ dev->width = norm_maxw(dev);
+ dev->height = norm_maxh(dev);
+ dev->frame_size = dev->width * dev->height * 2;
+ dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
+ dev->bytesperline = dev->width * 2;
+ dev->hscale = 0;
+ dev->vscale = 0;
+
+ em28xx_capture_start(dev, 1);
+ em28xx_resolution_set(dev);
+
+ /* start the transfer */
+ errCode = em28xx_init_isoc(dev);
+ if (errCode)
+ goto err;
+
+ dev->users++;
+ filp->private_data = dev;
+ dev->io = IO_NONE;
+ dev->stream = STREAM_OFF;
+ dev->num_frames = 0;
+
+ /* prepare queues */
+ em28xx_empty_framequeues(dev);
+
+ dev->state |= DEV_INITIALIZED;
+
+ video_mux(dev, 0);
+
+ err:
+ up(&dev->lock);
+ up_read(&em28xx_disconnect);
+ return errCode;
+}
+
+/*
+ * em28xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+static void em28xx_release_resources(struct em28xx *dev)
+{
+ down(&em28xx_sysfs_lock);
+
+ em28xx_info("V4L2 device /dev/video%d deregistered\n",
+ dev->vdev->minor);
+ list_del(&dev->devlist);
+ video_unregister_device(dev->vdev);
+/* video_unregister_device(dev->vbi_dev); */
+ em28xx_i2c_unregister(dev);
+ usb_put_dev(dev->udev);
+ up(&em28xx_sysfs_lock);
+}
+
+/*
+ * em28xx_v4l2_close()
+ * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls
+ */
+static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
+{
+ int errCode;
+ struct em28xx *dev=filp->private_data;
+
+ em28xx_videodbg("users=%d\n", dev->users);
+
+ down(&dev->lock);
+
+ em28xx_uninit_isoc(dev);
+
+ em28xx_release_buffers(dev);
+
+ /* the device is already disconnect, free the remaining resources */
+ if (dev->state & DEV_DISCONNECTED) {
+ em28xx_release_resources(dev);
+ up(&dev->lock);
+ kfree(dev);
+ return 0;
+ }
+
+ /* set alternate 0 */
+ dev->alt = 0;
+ em28xx_videodbg("setting alternate 0\n");
+ errCode = usb_set_interface(dev->udev, 0, 0);
+ if (errCode < 0) {
+ em28xx_errdev ("cannot change alternate number to 0 (error=%i)\n",
+ errCode);
+ }
+
+ dev->users--;
+ wake_up_interruptible_nr(&dev->open, 1);
+ up(&dev->lock);
+ return 0;
+}
+
+/*
+ * em28xx_v4l2_read()
+ * will allocate buffers when called for the first time
+ */
+static ssize_t
+em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
+ loff_t * f_pos)
+{
+ struct em28xx_frame_t *f, *i;
+ unsigned long lock_flags;
+ int ret = 0;
+ struct em28xx *dev = filp->private_data;
+
+ if (down_interruptible(&dev->fileop_lock))
+ return -ERESTARTSYS;
+
+ if (dev->state & DEV_DISCONNECTED) {
+ em28xx_videodbg("device not present\n");
+ up(&dev->fileop_lock);
+ return -ENODEV;
+ }
+
+ if (dev->state & DEV_MISCONFIGURED) {
+ em28xx_videodbg("device misconfigured; close and open it again\n");
+ up(&dev->fileop_lock);
+ return -EIO;
+ }
+
+ if (dev->io == IO_MMAP) {
+ em28xx_videodbg ("IO method is set to mmap; close and open"
+ " the device again to choose the read method\n");
+ up(&dev->fileop_lock);
+ return -EINVAL;
+ }
+
+ if (dev->io == IO_NONE) {
+ if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) {
+ em28xx_errdev("read failed, not enough memory\n");
+ up(&dev->fileop_lock);
+ return -ENOMEM;
+ }
+ dev->io = IO_READ;
+ dev->stream = STREAM_ON;
+ em28xx_queue_unusedframes(dev);
+ }
+
+ if (!count) {
+ up(&dev->fileop_lock);
+ return 0;
+ }
+
+ if (list_empty(&dev->outqueue)) {
+ if (filp->f_flags & O_NONBLOCK) {
+ up(&dev->fileop_lock);
+ return -EAGAIN;
+ }
+ ret = wait_event_interruptible
+ (dev->wait_frame,
+ (!list_empty(&dev->outqueue)) ||
+ (dev->state & DEV_DISCONNECTED));
+ if (ret) {
+ up(&dev->fileop_lock);
+ return ret;
+ }
+ if (dev->state & DEV_DISCONNECTED) {
+ up(&dev->fileop_lock);
+ return -ENODEV;
+ }
+ }
+
+ f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame);
+
+ spin_lock_irqsave(&dev->queue_lock, lock_flags);
+ list_for_each_entry(i, &dev->outqueue, frame)
+ i->state = F_UNUSED;
+ INIT_LIST_HEAD(&dev->outqueue);
+ spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+ em28xx_queue_unusedframes(dev);
+
+ if (count > f->buf.length)
+ count = f->buf.length;
+
+ if (copy_to_user(buf, f->bufmem, count)) {
+ up(&dev->fileop_lock);
+ return -EFAULT;
+ }
+ *f_pos += count;
+
+ up(&dev->fileop_lock);
+
+ return count;
+}
+
+/*
+ * em28xx_v4l2_poll()
+ * will allocate buffers when called for the first time
+ */
+static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
+{
+ unsigned int mask = 0;
+ struct em28xx *dev = filp->private_data;
+
+ if (down_interruptible(&dev->fileop_lock))
+ return POLLERR;
+
+ if (dev->state & DEV_DISCONNECTED) {
+ em28xx_videodbg("device not present\n");
+ } else if (dev->state & DEV_MISCONFIGURED) {
+ em28xx_videodbg("device is misconfigured; close and open it again\n");
+ } else {
+ if (dev->io == IO_NONE) {
+ if (!em28xx_request_buffers
+ (dev, EM28XX_NUM_READ_FRAMES)) {
+ em28xx_warn
+ ("poll() failed, not enough memory\n");
+ } else {
+ dev->io = IO_READ;
+ dev->stream = STREAM_ON;
+ }
+ }
+
+ if (dev->io == IO_READ) {
+ em28xx_queue_unusedframes(dev);
+ poll_wait(filp, &dev->wait_frame, wait);
+
+ if (!list_empty(&dev->outqueue))
+ mask |= POLLIN | POLLRDNORM;
+
+ up(&dev->fileop_lock);
+
+ return mask;
+ }
+ }
+
+ up(&dev->fileop_lock);
+ return POLLERR;
+}
+
+/*
+ * em28xx_vm_open()
+ */
+static void em28xx_vm_open(struct vm_area_struct *vma)
+{
+ struct em28xx_frame_t *f = vma->vm_private_data;
+ f->vma_use_count++;
+}
+
+/*
+ * em28xx_vm_close()
+ */
+static void em28xx_vm_close(struct vm_area_struct *vma)
+{
+ /* NOTE: buffers are not freed here */
+ struct em28xx_frame_t *f = vma->vm_private_data;
+ f->vma_use_count--;
+}
+
+static struct vm_operations_struct em28xx_vm_ops = {
+ .open = em28xx_vm_open,
+ .close = em28xx_vm_close,
+};
+
+/*
+ * em28xx_v4l2_mmap()
+ */
+static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ unsigned long size = vma->vm_end - vma->vm_start,
+ start = vma->vm_start, pos, page;
+ u32 i;
+
+ struct em28xx *dev = filp->private_data;
+
+ if (down_interruptible(&dev->fileop_lock))
+ return -ERESTARTSYS;
+
+ if (dev->state & DEV_DISCONNECTED) {
+ em28xx_videodbg("mmap: device not present\n");
+ up(&dev->fileop_lock);
+ return -ENODEV;
+ }
+
+ if (dev->state & DEV_MISCONFIGURED) {
+ em28xx_videodbg ("mmap: Device is misconfigured; close and "
+ "open it again\n");
+ up(&dev->fileop_lock);
+ return -EIO;
+ }
+
+ if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+ size != PAGE_ALIGN(dev->frame[0].buf.length)) {
+ up(&dev->fileop_lock);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < dev->num_frames; i++) {
+ if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
+ break;
+ }
+ if (i == dev->num_frames) {
+ em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
+ up(&dev->fileop_lock);
+ return -EINVAL;
+ }
+
+ /* VM_IO is eventually going to replace PageReserved altogether */
+ vma->vm_flags |= VM_IO;
+ vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
+
+ pos = (unsigned long)dev->frame[i].bufmem;
+ while (size > 0) { /* size is page-aligned */
+ page = vmalloc_to_pfn((void *)pos);
+ if (remap_pfn_range(vma, start, page, PAGE_SIZE,
+ vma->vm_page_prot)) {
+ em28xx_videodbg("mmap: rename page map failed\n");
+ up(&dev->fileop_lock);
+ return -EAGAIN;
+ }
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ vma->vm_ops = &em28xx_vm_ops;
+ vma->vm_private_data = &dev->frame[i];
+
+ em28xx_vm_open(vma);
+ up(&dev->fileop_lock);
+ return 0;
+}
+
+/*
+ * em28xx_get_ctrl()
+ * return the current saturation, brightness or contrast, mute state
+ */
+static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
+{
+ s32 tmp;
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value = dev->mute;
+ return 0;
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value = dev->volume;
+ return 0;
+ case V4L2_CID_BRIGHTNESS:
+ if ((tmp = em28xx_brightness_get(dev)) < 0)
+ return -EIO;
+ ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */
+ return 0;
+ case V4L2_CID_CONTRAST:
+ if ((ctrl->value = em28xx_contrast_get(dev)) < 0)
+ return -EIO;
+ return 0;
+ case V4L2_CID_SATURATION:
+ if ((ctrl->value = em28xx_saturation_get(dev)) < 0)
+ return -EIO;
+ return 0;
+ case V4L2_CID_RED_BALANCE:
+ if ((tmp = em28xx_v_balance_get(dev)) < 0)
+ return -EIO;
+ ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */
+ return 0;
+ case V4L2_CID_BLUE_BALANCE:
+ if ((tmp = em28xx_u_balance_get(dev)) < 0)
+ return -EIO;
+ ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */
+ return 0;
+ case V4L2_CID_GAMMA:
+ if ((ctrl->value = em28xx_gamma_get(dev)) < 0)
+ return -EIO;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * em28xx_set_ctrl()
+ * mute or set new saturation, brightness or contrast
+ */
+static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value != dev->mute) {
+ dev->mute = ctrl->value;
+ em28xx_audio_usb_mute(dev, ctrl->value);
+ return em28xx_audio_analog_set(dev);
+ }
+ return 0;
+ case V4L2_CID_AUDIO_VOLUME:
+ dev->volume = ctrl->value;
+ return em28xx_audio_analog_set(dev);
+ case V4L2_CID_BRIGHTNESS:
+ return em28xx_brightness_set(dev, ctrl->value);
+ case V4L2_CID_CONTRAST:
+ return em28xx_contrast_set(dev, ctrl->value);
+ case V4L2_CID_SATURATION:
+ return em28xx_saturation_set(dev, ctrl->value);
+ case V4L2_CID_RED_BALANCE:
+ return em28xx_v_balance_set(dev, ctrl->value);
+ case V4L2_CID_BLUE_BALANCE:
+ return em28xx_u_balance_set(dev, ctrl->value);
+ case V4L2_CID_GAMMA:
+ return em28xx_gamma_set(dev, ctrl->value);
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * em28xx_stream_interrupt()
+ * stops streaming
+ */
+static int em28xx_stream_interrupt(struct em28xx *dev)
+{
+ int ret = 0;
+
+ /* stop reading from the device */
+
+ dev->stream = STREAM_INTERRUPT;
+ ret = wait_event_timeout(dev->wait_stream,
+ (dev->stream == STREAM_OFF) ||
+ (dev->state & DEV_DISCONNECTED),
+ EM28XX_URB_TIMEOUT);
+ if (dev->state & DEV_DISCONNECTED)
+ return -ENODEV;
+ else if (ret) {
+ dev->state |= DEV_MISCONFIGURED;
+ em28xx_videodbg("device is misconfigured; close and "
+ "open /dev/video%d again\n", dev->vdev->minor);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int em28xx_set_norm(struct em28xx *dev, int width, int height)
+{
+ unsigned int hscale, vscale;
+ unsigned int maxh, maxw;
+
+ maxw = norm_maxw(dev);
+ maxh = norm_maxh(dev);
+
+ /* width must even because of the YUYV format */
+ /* height must be even because of interlacing */
+ height &= 0xfffe;
+ width &= 0xfffe;
+
+ if (height < 32)
+ height = 32;
+ if (height > maxh)
+ height = maxh;
+ if (width < 48)
+ width = 48;
+ if (width > maxw)
+ width = maxw;
+
+ if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000)
+ hscale = 0x3fff;
+ width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+
+ if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000)
+ vscale = 0x3fff;
+ height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+
+ /* set new image size */
+ dev->width = width;
+ dev->height = height;
+ dev->frame_size = dev->width * dev->height * 2;
+ dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
+ dev->bytesperline = dev->width * 2;
+ dev->hscale = hscale;
+ dev->vscale = vscale;
+
+ em28xx_resolution_set(dev);
+
+ return 0;
+}
+
+/*
+ * em28xx_v4l2_do_ioctl()
+ * This function is _not_ called directly, but from
+ * em28xx_v4l2_ioctl. Userspace
+ * copying is done already, arg is a kernel pointer.
+ */
+static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
+ struct em28xx *dev, unsigned int cmd, void *arg,
+ v4l2_kioctl driver_ioctl)
+{
+ int ret;
+
+ switch (cmd) {
+ /* ---------- tv norms ---------- */
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *e = arg;
+ unsigned int i;
+
+ i = e->index;
+ if (i >= TVNORMS)
+ return -EINVAL;
+ ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
+ tvnorms[e->index].name);
+ e->index = i;
+ if (ret < 0)
+ return ret;
+ return 0;
+ }
+ case VIDIOC_G_STD:
+ {
+ v4l2_std_id *id = arg;
+
+ *id = dev->tvnorm->id;
+ return 0;
+ }
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id *id = arg;
+ unsigned int i;
+
+ for (i = 0; i < TVNORMS; i++)
+ if (*id == tvnorms[i].id)
+ break;
+ if (i == TVNORMS)
+ for (i = 0; i < TVNORMS; i++)
+ if (*id & tvnorms[i].id)
+ break;
+ if (i == TVNORMS)
+ return -EINVAL;
+
+ down(&dev->lock);
+ dev->tvnorm = &tvnorms[i];
+
+ em28xx_set_norm(dev, dev->width, dev->height);
+
+/*
+ dev->width=norm_maxw(dev);
+ dev->height=norm_maxh(dev);
+ dev->frame_size=dev->width*dev->height*2;
+ dev->field_size=dev->frame_size>>1;
+ dev->bytesperline=dev->width*2;
+ dev->hscale=0;
+ dev->vscale=0;
+
+ em28xx_resolution_set(dev);
+*/
+/*
+ em28xx_uninit_isoc(dev);
+ em28xx_set_alternate(dev);
+ em28xx_capture_start(dev, 1);
+ em28xx_resolution_set(dev);
+ em28xx_init_isoc(dev);
+*/
+ em28xx_i2c_call_clients(dev, DECODER_SET_NORM,
+ &tvnorms[i].mode);
+ em28xx_i2c_call_clients(dev, VIDIOC_S_STD,
+ &dev->tvnorm->id);
+
+ up(&dev->lock);
+
+ return 0;
+ }
+
+ /* ------ input switching ---------- */
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *i = arg;
+ unsigned int n;
+ static const char *iname[] = {
+ [EM28XX_VMUX_COMPOSITE1] = "Composite1",
+ [EM28XX_VMUX_COMPOSITE2] = "Composite2",
+ [EM28XX_VMUX_COMPOSITE3] = "Composite3",
+ [EM28XX_VMUX_COMPOSITE4] = "Composite4",
+ [EM28XX_VMUX_SVIDEO] = "S-Video",
+ [EM28XX_VMUX_TELEVISION] = "Television",
+ [EM28XX_VMUX_CABLE] = "Cable TV",
+ [EM28XX_VMUX_DVB] = "DVB",
+ [EM28XX_VMUX_DEBUG] = "for debug only",
+ };
+
+ n = i->index;
+ if (n >= MAX_EM28XX_INPUT)
+ 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 ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
+ (EM28XX_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:
+ {
+ int *i = arg;
+ *i = dev->ctl_input;
+
+ return 0;
+ }
+
+ case VIDIOC_S_INPUT:
+ {
+ int *index = arg;
+
+ if (*index >= MAX_EM28XX_INPUT)
+ return -EINVAL;
+ if (0 == INPUT(*index)->type)
+ return -EINVAL;
+
+ down(&dev->lock);
+ video_mux(dev, *index);
+ up(&dev->lock);
+
+ return 0;
+ }
+
+ case VIDIOC_G_AUDIO:
+ {
+ struct v4l2_audio *a = arg;
+ unsigned int index = a->index;
+
+ if (a->index > 1)
+ return -EINVAL;
+ memset(a, 0, sizeof(*a));
+ index = dev->ctl_ainput;
+
+ if (index == 0) {
+ strcpy(a->name, "Television");
+ } else {
+ strcpy(a->name, "Line In");
+ }
+ a->capability = V4L2_AUDCAP_STEREO;
+ a->index = index;
+ return 0;
+ }
+
+ case VIDIOC_S_AUDIO:
+ {
+ struct v4l2_audio *a = arg;
+ if (a->index != dev->ctl_ainput)
+ return -EINVAL;
+
+ return 0;
+ }
+
+ /* --- controls ---------------------------------------------- */
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+ u8 i, n;
+ n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
+ for (i = 0; i < n; i++)
+ if (qc->id && qc->id == em28xx_qctrl[i].id) {
+ memcpy(qc, &(em28xx_qctrl[i]),
+ sizeof(*qc));
+ return 0;
+ }
+
+ return -EINVAL;
+ }
+
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+
+
+ return em28xx_get_ctrl(dev, ctrl);
+ }
+
+ case VIDIOC_S_CTRL_OLD: /* ??? */
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+ u8 i, n;
+
+
+ n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
+ for (i = 0; i < n; i++)
+ if (ctrl->id == em28xx_qctrl[i].id) {
+ if (ctrl->value <
+ em28xx_qctrl[i].minimum
+ || ctrl->value >
+ em28xx_qctrl[i].maximum)
+ return -ERANGE;
+
+ return em28xx_set_ctrl(dev, ctrl);
+ }
+ return -EINVAL;
+ }
+
+ /* --- tuner ioctls ------------------------------------------ */
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *t = arg;
+ int status = 0;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ memset(t, 0, sizeof(*t));
+ strcpy(t->name, "Tuner");
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->rangehigh = 0xffffffffUL; /* FIXME: set correct range */
+/* t->signal = 0xffff;*/
+/* em28xx_i2c_call_clients(dev,VIDIOC_G_TUNER,t);*/
+ /* No way to get signal strength? */
+ down(&dev->lock);
+ em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
+ &status);
+ up(&dev->lock);
+ t->signal =
+ (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
+
+ em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal,
+ t->afc);
+ return 0;
+ }
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *t = arg;
+ int status = 0;
+
+ if (0 != t->index)
+ return -EINVAL;
+ memset(t, 0, sizeof(*t));
+ strcpy(t->name, "Tuner");
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->rangehigh = 0xffffffffUL; /* FIXME: set correct range */
+/* t->signal = 0xffff; */
+ /* No way to get signal strength? */
+ down(&dev->lock);
+ em28xx_i2c_call_clients(dev, DECODER_GET_STATUS,
+ &status);
+ up(&dev->lock);
+ t->signal =
+ (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0;
+
+ em28xx_videodbg("VIDIO_S_TUNER: signal=%x, afc=%x\n",
+ t->signal, t->afc);
+ return 0;
+ }
+ case VIDIOC_G_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ memset(f, 0, sizeof(*f));
+ f->type = V4L2_TUNER_ANALOG_TV;
+ f->frequency = dev->ctl_freq;
+
+ return 0;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ if (0 != f->tuner)
+ return -EINVAL;
+
+ if (V4L2_TUNER_ANALOG_TV != f->type)
+ return -EINVAL;
+
+ down(&dev->lock);
+ dev->ctl_freq = f->frequency;
+ em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
+ up(&dev->lock);
+ return 0;
+ }
+
+ case VIDIOC_CROPCAP:
+ {
+ struct v4l2_cropcap *cc = arg;
+
+ if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ cc->bounds.left = 0;
+ cc->bounds.top = 0;
+ cc->bounds.width = dev->width;
+ cc->bounds.height = dev->height;
+ cc->defrect = cc->bounds;
+ cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
+ cc->pixelaspect.denominator = 59;
+ return 0;
+ }
+ case VIDIOC_STREAMON:
+ {
+ int *type = arg;
+
+ if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+ || dev->io != IO_MMAP)
+ return -EINVAL;
+
+ if (list_empty(&dev->inqueue))
+ return -EINVAL;
+
+ dev->stream = STREAM_ON; /* FIXME: Start video capture here? */
+
+ em28xx_videodbg("VIDIOC_STREAMON: starting stream\n");
+
+ return 0;
+ }
+ case VIDIOC_STREAMOFF:
+ {
+ int *type = arg;
+ int ret;
+
+ if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+ || dev->io != IO_MMAP)
+ return -EINVAL;
+
+ if (dev->stream == STREAM_ON) {
+ em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n");
+ if ((ret = em28xx_stream_interrupt(dev)))
+ return ret;
+ }
+ em28xx_empty_framequeues(dev);
+
+ return 0;
+ }
+ default:
+ return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
+ driver_ioctl);
+ }
+ return 0;
+}
+
+/*
+ * em28xx_v4l2_do_ioctl()
+ * This function is _not_ called directly, but from
+ * em28xx_v4l2_ioctl. Userspace
+ * copying is done already, arg is a kernel pointer.
+ */
+static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, void *arg)
+{
+ struct em28xx *dev = filp->private_data;
+
+ if (!dev)
+ return -ENODEV;
+
+ if (video_debug > 1)
+ em28xx_print_ioctl(dev->name,cmd);
+
+ switch (cmd) {
+
+ /* --- capabilities ------------------------------------------ */
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap = arg;
+
+ memset(cap, 0, sizeof(*cap));
+ strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
+ strlcpy(cap->card, em28xx_boards[dev->model].name,
+ sizeof(cap->card));
+ strlcpy(cap->bus_info, dev->udev->dev.bus_id,
+ sizeof(cap->bus_info));
+ cap->version = EM28XX_VERSION_CODE;
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ if (dev->has_tuner)
+ cap->capabilities |= V4L2_CAP_TUNER;
+ return 0;
+ }
+
+ /* --- capture ioctls ---------------------------------------- */
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *fmtd = arg;
+
+ if (fmtd->index != 0)
+ return -EINVAL;
+ memset(fmtd, 0, sizeof(*fmtd));
+ fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ strcpy(fmtd->description, "Packed YUY2");
+ fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
+ memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
+ return 0;
+ }
+
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *format = arg;
+
+ em28xx_videodbg("VIDIOC_G_FMT: type=%s\n",
+ format->type ==
+ V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+ "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type ==
+ V4L2_BUF_TYPE_VBI_CAPTURE ?
+ "V4L2_BUF_TYPE_VBI_CAPTURE " :
+ "not supported");
+
+ if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ format->fmt.pix.width = dev->width;
+ format->fmt.pix.height = dev->height;
+ format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ format->fmt.pix.bytesperline = dev->bytesperline;
+ format->fmt.pix.sizeimage = dev->frame_size;
+ format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
+
+ em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width,
+ dev->height);
+ return 0;
+ }
+
+ case VIDIOC_TRY_FMT:
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *format = arg;
+ u32 i;
+ int ret = 0;
+ int width = format->fmt.pix.width;
+ int height = format->fmt.pix.height;
+ unsigned int hscale, vscale;
+ unsigned int maxh, maxw;
+
+ maxw = norm_maxw(dev);
+ maxh = norm_maxh(dev);
+
+/* int both_fields; */
+
+ em28xx_videodbg("%s: type=%s\n",
+ cmd ==
+ VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
+ "VIDIOC_S_FMT",
+ format->type ==
+ V4L2_BUF_TYPE_VIDEO_CAPTURE ?
+ "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type ==
+ V4L2_BUF_TYPE_VBI_CAPTURE ?
+ "V4L2_BUF_TYPE_VBI_CAPTURE " :
+ "not supported");
+
+ if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ em28xx_videodbg("%s: requested %dx%d\n",
+ cmd ==
+ VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
+ "VIDIOC_S_FMT", format->fmt.pix.width,
+ format->fmt.pix.height);
+
+ /* FIXME: Move some code away from here */
+ /* width must even because of the YUYV format */
+ /* height must be even because of interlacing */
+ height &= 0xfffe;
+ width &= 0xfffe;
+
+ if (height < 32)
+ height = 32;
+ if (height > maxh)
+ height = maxh;
+ if (width < 48)
+ width = 48;
+ if (width > maxw)
+ width = maxw;
+
+ if(dev->is_em2800){
+ /* the em2800 can only scale down to 50% */
+ if(height % (maxh / 2))
+ height=maxh;
+ if(width % (maxw / 2))
+ width=maxw;
+ /* according to empiatech support */
+ /* the MaxPacketSize is to small to support */
+ /* framesizes larger than 640x480 @ 30 fps */
+ /* or 640x576 @ 25 fps. As this would cut */
+ /* of a part of the image we prefer */
+ /* 360x576 or 360x480 for now */
+ if(width == maxw && height == maxh)
+ width /= 2;
+ }
+
+ if ((hscale =
+ (((unsigned long)maxw) << 12) / width - 4096L) >=
+ 0x4000)
+ hscale = 0x3fff;
+ width =
+ (((unsigned long)maxw) << 12) / (hscale + 4096L);
+
+ if ((vscale =
+ (((unsigned long)maxh) << 12) / height - 4096L) >=
+ 0x4000)
+ vscale = 0x3fff;
+ height =
+ (((unsigned long)maxh) << 12) / (vscale + 4096L);
+
+ format->fmt.pix.width = width;
+ format->fmt.pix.height = height;
+ format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ format->fmt.pix.bytesperline = width * 2;
+ format->fmt.pix.sizeimage = width * 2 * height;
+ format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ format->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+ em28xx_videodbg("%s: returned %dx%d (%d, %d)\n",
+ cmd ==
+ VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" :
+ "VIDIOC_S_FMT", format->fmt.pix.width,
+ format->fmt.pix.height, hscale, vscale);
+
+ if (cmd == VIDIOC_TRY_FMT)
+ return 0;
+
+ for (i = 0; i < dev->num_frames; i++)
+ if (dev->frame[i].vma_use_count) {
+ em28xx_videodbg("VIDIOC_S_FMT failed. "
+ "Unmap the buffers first.\n");
+ return -EINVAL;
+ }
+
+ /* stop io in case it is already in progress */
+ if (dev->stream == STREAM_ON) {
+ em28xx_videodbg("VIDIOC_SET_FMT: interupting stream\n");
+ if ((ret = em28xx_stream_interrupt(dev)))
+ return ret;
+ }
+
+ em28xx_release_buffers(dev);
+ dev->io = IO_NONE;
+
+ /* set new image size */
+ dev->width = width;
+ dev->height = height;
+ dev->frame_size = dev->width * dev->height * 2;
+ dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
+ dev->bytesperline = dev->width * 2;
+ dev->hscale = hscale;
+ dev->vscale = vscale;
+/* dev->both_fileds = both_fileds; */
+ em28xx_uninit_isoc(dev);
+ em28xx_set_alternate(dev);
+ em28xx_capture_start(dev, 1);
+ em28xx_resolution_set(dev);
+ em28xx_init_isoc(dev);
+
+ return 0;
+ }
+
+ /* --- streaming capture ------------------------------------- */
+ case VIDIOC_REQBUFS:
+ {
+ struct v4l2_requestbuffers *rb = arg;
+ u32 i;
+ int ret;
+
+ if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ rb->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ if (dev->io == IO_READ) {
+ em28xx_videodbg ("method is set to read;"
+ " close and open the device again to"
+ " choose the mmap I/O method\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < dev->num_frames; i++)
+ if (dev->frame[i].vma_use_count) {
+ em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n");
+ return -EINVAL;
+ }
+
+ if (dev->stream == STREAM_ON) {
+ em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
+ if ((ret = em28xx_stream_interrupt(dev)))
+ return ret;
+ }
+
+ em28xx_empty_framequeues(dev);
+
+ em28xx_release_buffers(dev);
+ if (rb->count)
+ rb->count =
+ em28xx_request_buffers(dev, rb->count);
+
+ dev->frame_current = NULL;
+
+ em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n",
+ rb->count);
+ dev->io = rb->count ? IO_MMAP : IO_NONE;
+ return 0;
+ }
+
+ case VIDIOC_QUERYBUF:
+ {
+ struct v4l2_buffer *b = arg;
+
+ if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ b->index >= dev->num_frames || dev->io != IO_MMAP)
+ return -EINVAL;
+
+ memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
+
+ if (dev->frame[b->index].vma_use_count) {
+ b->flags |= V4L2_BUF_FLAG_MAPPED;
+ }
+ if (dev->frame[b->index].state == F_DONE)
+ b->flags |= V4L2_BUF_FLAG_DONE;
+ else if (dev->frame[b->index].state != F_UNUSED)
+ b->flags |= V4L2_BUF_FLAG_QUEUED;
+ return 0;
+ }
+ case VIDIOC_QBUF:
+ {
+ struct v4l2_buffer *b = arg;
+ unsigned long lock_flags;
+
+ if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ b->index >= dev->num_frames || dev->io != IO_MMAP) {
+ return -EINVAL;
+ }
+
+ if (dev->frame[b->index].state != F_UNUSED) {
+ return -EAGAIN;
+ }
+ dev->frame[b->index].state = F_QUEUED;
+
+ /* add frame to fifo */
+ spin_lock_irqsave(&dev->queue_lock, lock_flags);
+ list_add_tail(&dev->frame[b->index].frame,
+ &dev->inqueue);
+ spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+ return 0;
+ }
+ case VIDIOC_DQBUF:
+ {
+ struct v4l2_buffer *b = arg;
+ struct em28xx_frame_t *f;
+ unsigned long lock_flags;
+ int ret = 0;
+
+ if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+ || dev->io != IO_MMAP)
+ return -EINVAL;
+
+ if (list_empty(&dev->outqueue)) {
+ if (dev->stream == STREAM_OFF)
+ return -EINVAL;
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ ret = wait_event_interruptible
+ (dev->wait_frame,
+ (!list_empty(&dev->outqueue)) ||
+ (dev->state & DEV_DISCONNECTED));
+ if (ret)
+ return ret;
+ if (dev->state & DEV_DISCONNECTED)
+ return -ENODEV;
+ }
+
+ spin_lock_irqsave(&dev->queue_lock, lock_flags);
+ f = list_entry(dev->outqueue.next,
+ struct em28xx_frame_t, frame);
+ list_del(dev->outqueue.next);
+ spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+ f->state = F_UNUSED;
+ memcpy(b, &f->buf, sizeof(*b));
+
+ if (f->vma_use_count)
+ b->flags |= V4L2_BUF_FLAG_MAPPED;
+
+ return 0;
+ }
+ default:
+ return em28xx_do_ioctl(inode, filp, dev, cmd, arg,
+ em28xx_video_do_ioctl);
+ }
+ return 0;
+}
+
+/*
+ * em28xx_v4l2_ioctl()
+ * handle v4l2 ioctl the main action happens in em28xx_v4l2_do_ioctl()
+ */
+static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ struct em28xx *dev = filp->private_data;
+
+ if (down_interruptible(&dev->fileop_lock))
+ return -ERESTARTSYS;
+
+ if (dev->state & DEV_DISCONNECTED) {
+ em28xx_errdev("v4l2 ioctl: device not present\n");
+ up(&dev->fileop_lock);
+ return -ENODEV;
+ }
+
+ if (dev->state & DEV_MISCONFIGURED) {
+ em28xx_errdev
+ ("v4l2 ioctl: device is misconfigured; close and open it again\n");
+ up(&dev->fileop_lock);
+ return -EIO;
+ }
+
+ ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl);
+
+ up(&dev->fileop_lock);
+
+ return ret;
+}
+
+static struct file_operations em28xx_v4l_fops = {
+ .owner = THIS_MODULE,
+ .open = em28xx_v4l2_open,
+ .release = em28xx_v4l2_close,
+ .ioctl = em28xx_v4l2_ioctl,
+ .read = em28xx_v4l2_read,
+ .poll = em28xx_v4l2_poll,
+ .mmap = em28xx_v4l2_mmap,
+ .llseek = no_llseek,
+};
+
+/******************************** usb interface *****************************************/
+
+/*
+ * em28xx_init_dev()
+ * allocates and inits the device structs, registers i2c bus and v4l device
+ */
+static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
+ int minor, int model)
+{
+ struct em28xx *dev = *devhandle;
+ int retval = -ENOMEM;
+ int errCode, i;
+ unsigned int maxh, maxw;
+
+ dev->udev = udev;
+ dev->model = model;
+ init_MUTEX(&dev->lock);
+ init_waitqueue_head(&dev->open);
+
+ dev->em28xx_write_regs = em28xx_write_regs;
+ dev->em28xx_read_reg = em28xx_read_reg;
+ dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
+ dev->em28xx_write_regs_req = em28xx_write_regs_req;
+ dev->em28xx_read_reg_req = em28xx_read_reg_req;
+ dev->is_em2800 = em28xx_boards[model].is_em2800;
+ dev->has_tuner = em28xx_boards[model].has_tuner;
+ dev->has_msp34xx = em28xx_boards[model].has_msp34xx;
+ dev->tda9887_conf = em28xx_boards[model].tda9887_conf;
+ dev->decoder = em28xx_boards[model].decoder;
+
+ if (tuner >= 0)
+ dev->tuner_type = tuner;
+ else
+ dev->tuner_type = em28xx_boards[model].tuner_type;
+
+ dev->video_inputs = em28xx_boards[model].vchannels;
+
+ for (i = 0; i < TVNORMS; i++)
+ if (em28xx_boards[model].norm == tvnorms[i].mode)
+ break;
+ if (i == TVNORMS)
+ i = 0;
+
+ dev->tvnorm = &tvnorms[i]; /* set default norm */
+
+ em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name);
+
+ maxw = norm_maxw(dev);
+ maxh = norm_maxh(dev);
+
+ /* set default image size */
+ dev->width = maxw;
+ dev->height = maxh;
+ dev->interlaced = EM28XX_INTERLACED_DEFAULT;
+ dev->field_size = dev->width * dev->height;
+ dev->frame_size =
+ dev->interlaced ? dev->field_size << 1 : dev->field_size;
+ dev->bytesperline = dev->width * 2;
+ dev->hscale = 0;
+ dev->vscale = 0;
+ dev->ctl_input = 2;
+
+ /* setup video picture settings for saa7113h */
+ memset(&dev->vpic, 0, sizeof(dev->vpic));
+ dev->vpic.colour = 128 << 8;
+ dev->vpic.hue = 128 << 8;
+ dev->vpic.brightness = 128 << 8;
+ dev->vpic.contrast = 192 << 8;
+ dev->vpic.whiteness = 128 << 8; /* This one isn't used */
+ dev->vpic.depth = 16;
+ dev->vpic.palette = VIDEO_PALETTE_YUV422;
+
+#ifdef CONFIG_MODULES
+ /* request some modules */
+ if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114)
+ request_module("saa711x");
+ if (dev->decoder == EM28XX_TVP5150)
+ request_module("tvp5150");
+ if (dev->has_tuner)
+ request_module("tuner");
+ if (dev->tda9887_conf)
+ request_module("tda9887");
+#endif
+ errCode = em28xx_config(dev);
+ if (errCode) {
+ em28xx_errdev("error configuring device\n");
+ kfree(dev);
+ return -ENOMEM;
+ }
+
+ down(&dev->lock);
+ /* register i2c bus */
+ em28xx_i2c_register(dev);
+
+ /* Do board specific init and eeprom reading */
+ em28xx_card_setup(dev);
+
+ /* configure the device */
+ em28xx_config_i2c(dev);
+
+ up(&dev->lock);
+
+ errCode = em28xx_config(dev);
+
+#ifdef CONFIG_MODULES
+ if (dev->has_msp34xx)
+ request_module("msp3400");
+#endif
+ /* allocate and fill v4l2 device struct */
+ dev->vdev = video_device_alloc();
+ if (NULL == dev->vdev) {
+ em28xx_errdev("cannot allocate video_device.\n");
+ kfree(dev);
+ return -ENOMEM;
+ }
+
+ dev->vdev->type = VID_TYPE_CAPTURE;
+ if (dev->has_tuner)
+ dev->vdev->type |= VID_TYPE_TUNER;
+ dev->vdev->hardware = 0;
+ dev->vdev->fops = &em28xx_v4l_fops;
+ dev->vdev->minor = -1;
+ dev->vdev->dev = &dev->udev->dev;
+ dev->vdev->release = video_device_release;
+ snprintf(dev->vdev->name, sizeof(dev->vdev->name), "%s",
+ "em28xx video");
+ list_add_tail(&dev->devlist,&em28xx_devlist);
+
+ /* register v4l2 device */
+ down(&dev->lock);
+ if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1))) {
+ em28xx_errdev("unable to register video device (error=%i).\n",
+ retval);
+ up(&dev->lock);
+ list_del(&dev->devlist);
+ video_device_release(dev->vdev);
+ kfree(dev);
+ return -ENODEV;
+ }
+ if (dev->has_msp34xx) {
+ /* Send a reset to other chips via gpio */
+ em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
+ udelay(2500);
+ em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
+ udelay(2500);
+
+ }
+ video_mux(dev, 0);
+
+ up(&dev->lock);
+
+ em28xx_info("V4L2 device registered as /dev/video%d\n",
+ dev->vdev->minor);
+
+ return 0;
+}
+
+/*
+ * em28xx_usb_probe()
+ * checks for supported devices
+ */
+static int em28xx_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ const struct usb_endpoint_descriptor *endpoint;
+ struct usb_device *udev;
+ struct usb_interface *uif;
+ struct em28xx *dev = NULL;
+ int retval = -ENODEV;
+ int model,i,nr,ifnum;
+
+ udev = usb_get_dev(interface_to_usbdev(interface));
+ ifnum = interface->altsetting[0].desc.bInterfaceNumber;
+
+
+ /* Don't register audio interfaces */
+ if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
+ em28xx_err(DRIVER_NAME " audio device (%04x:%04x): interface %i, class %i\n",
+ udev->descriptor.idVendor,udev->descriptor.idProduct,
+ ifnum,
+ interface->altsetting[0].desc.bInterfaceClass);
+ return -ENODEV;
+ }
+
+ em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n",
+ udev->descriptor.idVendor,udev->descriptor.idProduct,
+ ifnum,
+ interface->altsetting[0].desc.bInterfaceClass);
+
+ endpoint = &interface->cur_altsetting->endpoint[1].desc;
+
+ /* check if the the device has the iso in endpoint at the correct place */
+ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+ USB_ENDPOINT_XFER_ISOC) {
+ em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
+ return -ENODEV;
+ }
+ if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
+ em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
+ return -ENODEV;
+ }
+
+ model=id->driver_info;
+ nr=interface->minor;
+
+ if (nr>EM28XX_MAXBOARDS) {
+ printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
+ return -ENOMEM;
+ }
+
+ /* allocate memory for our device state and initialize it */
+ dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ em28xx_err(DRIVER_NAME ": out of memory!\n");
+ return -ENOMEM;
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ /* compute alternate max packet sizes */
+ uif = udev->actconfig->interface[0];
+
+ dev->num_alt=uif->num_altsetting;
+ printk(DRIVER_NAME ": Alternate settings: %i\n",dev->num_alt);
+// dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)*
+ dev->alt_max_pkt_size = kmalloc(32*
+ dev->num_alt,GFP_KERNEL);
+ if (dev->alt_max_pkt_size == NULL) {
+ em28xx_err(DRIVER_NAME ": out of memory!\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < dev->num_alt ; i++) {
+ u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
+ wMaxPacketSize);
+ dev->alt_max_pkt_size[i] =
+ (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+ printk(DRIVER_NAME ": Alternate setting %i, max size= %i\n",i,
+ dev->alt_max_pkt_size[i]);
+ }
+
+ snprintf(dev->name, 29, "em28xx #%d", nr);
+
+ if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
+ model=card[nr];
+
+ if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) {
+ printk( "%s: Your board has no eeprom inside it and thus can't\n"
+ "%s: be autodetected. Please pass card=<n> insmod option to\n"
+ "%s: workaround that. Redirect complaints to the vendor of\n"
+ "%s: the TV card. Best regards,\n"
+ "%s: -- tux\n",
+ dev->name,dev->name,dev->name,dev->name,dev->name);
+ printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+ dev->name);
+ for (i = 0; i < em28xx_bcount; i++) {
+ printk("%s: card=%d -> %s\n",
+ dev->name, i, em28xx_boards[i].name);
+ }
+ }
+
+ /* allocate device struct */
+ retval = em28xx_init_dev(&dev, udev, nr, model);
+ if (retval)
+ return retval;
+
+ em28xx_info("Found %s\n", em28xx_boards[model].name);
+
+ /* save our data pointer in this interface device */
+ usb_set_intfdata(interface, dev);
+ return 0;
+}
+
+/*
+ * em28xx_usb_disconnect()
+ * called when the device gets diconencted
+ * video device will be unregistered on v4l2_close in case it is still open
+ */
+static void em28xx_usb_disconnect(struct usb_interface *interface)
+{
+ struct em28xx *dev = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ if (!dev)
+ return;
+
+ down_write(&em28xx_disconnect);
+
+ down(&dev->lock);
+
+ em28xx_info("disconnecting %s\n", dev->vdev->name);
+
+ wake_up_interruptible_all(&dev->open);
+
+ if (dev->users) {
+ em28xx_warn
+ ("device /dev/video%d is open! Deregistration and memory "
+ "deallocation are deferred on close.\n", dev->vdev->minor);
+ dev->state |= DEV_MISCONFIGURED;
+ em28xx_uninit_isoc(dev);
+ dev->state |= DEV_DISCONNECTED;
+ wake_up_interruptible(&dev->wait_frame);
+ wake_up_interruptible(&dev->wait_stream);
+ } else {
+ dev->state |= DEV_DISCONNECTED;
+ em28xx_release_resources(dev);
+ }
+
+ up(&dev->lock);
+
+ if (!dev->users) {
+ kfree(dev->alt_max_pkt_size);
+ kfree(dev);
+ }
+
+ up_write(&em28xx_disconnect);
+}
+
+static struct usb_driver em28xx_usb_driver = {
+ .owner = THIS_MODULE,
+ .name = "em28xx",
+ .probe = em28xx_usb_probe,
+ .disconnect = em28xx_usb_disconnect,
+ .id_table = em28xx_id_table,
+};
+
+static int __init em28xx_module_init(void)
+{
+ int result;
+
+ printk(KERN_INFO DRIVER_NAME " v4l2 driver version %d.%d.%d loaded\n",
+ (EM28XX_VERSION_CODE >> 16) & 0xff,
+ (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+ printk(KERN_INFO DRIVER_NAME " snapshot date %04d-%02d-%02d\n",
+ SNAPSHOT / 10000, (SNAPSHOT / 100) % 100, SNAPSHOT % 100);
+#endif
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&em28xx_usb_driver);
+ if (result)
+ em28xx_err(DRIVER_NAME
+ " usb_register failed. Error number %d.\n", result);
+
+ return result;
+}
+
+static void __exit em28xx_module_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&em28xx_usb_driver);
+}
+
+module_init(em28xx_module_init);
+module_exit(em28xx_module_exit);
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
new file mode 100644
index 00000000000..5c7a41ce69f
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -0,0 +1,513 @@
+/*
+ em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+
+ Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
+ Ludovico Cavedon <cavedon@sssup.it>
+ Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+
+ Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.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; 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 _EM28XX_H
+#define _EM28XX_H
+
+#include <linux/videodev.h>
+#include <linux/i2c.h>
+#include <media/ir-kbd-i2c.h>
+
+/* Boards supported by driver */
+
+#define EM2800_BOARD_UNKNOWN 0
+#define EM2820_BOARD_UNKNOWN 1
+#define EM2820_BOARD_TERRATEC_CINERGY_250 2
+#define EM2820_BOARD_PINNACLE_USB_2 3
+#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4
+#define EM2820_BOARD_MSI_VOX_USB_2 5
+#define EM2800_BOARD_TERRATEC_CINERGY_200 6
+#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7
+#define EM2800_BOARD_KWORLD_USB2800 8
+#define EM2820_BOARD_PINNACLE_DVC_90 9
+
+#define UNSET -1
+
+/* maximum number of em28xx boards */
+#define EM28XX_MAXBOARDS 1 /*FIXME: should be bigger */
+
+/* maximum number of frames that can be queued */
+#define EM28XX_NUM_FRAMES 5
+/* number of frames that get used for v4l2_read() */
+#define EM28XX_NUM_READ_FRAMES 2
+
+/* number of buffers for isoc transfers */
+#define EM28XX_NUM_BUFS 5
+
+/* number of packets for each buffer
+ windows requests only 40 packets .. so we better do the same
+ this is what I found out for all alternate numbers there!
+ */
+#define EM28XX_NUM_PACKETS 40
+
+/* default alternate; 0 means choose the best */
+#define EM28XX_PINOUT 0
+
+#define EM28XX_INTERLACED_DEFAULT 1
+
+/*
+#define (use usbview if you want to get the other alternate number infos)
+#define
+#define alternate number 2
+#define Endpoint Address: 82
+ Direction: in
+ Attribute: 1
+ Type: Isoc
+ Max Packet Size: 1448
+ Interval: 125us
+
+ alternate number 7
+
+ Endpoint Address: 82
+ Direction: in
+ Attribute: 1
+ Type: Isoc
+ Max Packet Size: 3072
+ Interval: 125us
+*/
+
+/* time to wait when stopping the isoc transfer */
+#define EM28XX_URB_TIMEOUT msecs_to_jiffies(EM28XX_NUM_BUFS * EM28XX_NUM_PACKETS)
+
+/* time in msecs to wait for i2c writes to finish */
+#define EM2800_I2C_WRITE_TIMEOUT 20
+
+/* the various frame states */
+enum em28xx_frame_state {
+ F_UNUSED = 0,
+ F_QUEUED,
+ F_GRABBING,
+ F_DONE,
+ F_ERROR,
+};
+
+/* stream states */
+enum em28xx_stream_state {
+ STREAM_OFF,
+ STREAM_INTERRUPT,
+ STREAM_ON,
+};
+
+/* frames */
+struct em28xx_frame_t {
+ void *bufmem;
+ struct v4l2_buffer buf;
+ enum em28xx_frame_state state;
+ struct list_head frame;
+ unsigned long vma_use_count;
+ int top_field;
+ int fieldbytesused;
+};
+
+/* io methods */
+enum em28xx_io_method {
+ IO_NONE,
+ IO_READ,
+ IO_MMAP,
+};
+
+/* inputs */
+
+#define MAX_EM28XX_INPUT 4
+enum enum28xx_itype {
+ EM28XX_VMUX_COMPOSITE1 = 1,
+ EM28XX_VMUX_COMPOSITE2,
+ EM28XX_VMUX_COMPOSITE3,
+ EM28XX_VMUX_COMPOSITE4,
+ EM28XX_VMUX_SVIDEO,
+ EM28XX_VMUX_TELEVISION,
+ EM28XX_VMUX_CABLE,
+ EM28XX_VMUX_DVB,
+ EM28XX_VMUX_DEBUG,
+ EM28XX_RADIO,
+};
+
+struct em28xx_input {
+ enum enum28xx_itype type;
+ unsigned int vmux;
+ unsigned int amux;
+};
+
+#define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
+
+enum em28xx_decoder {
+ EM28XX_TVP5150,
+ EM28XX_SAA7113,
+ EM28XX_SAA7114
+};
+
+struct em28xx_board {
+ char *name;
+ int vchannels;
+ int norm;
+ int tuner_type;
+
+ /* i2c flags */
+ unsigned int is_em2800;
+ unsigned int tda9887_conf;
+
+ unsigned int has_tuner:1;
+ unsigned int has_msp34xx:1;
+
+ enum em28xx_decoder decoder;
+
+ struct em28xx_input input[MAX_EM28XX_INPUT];
+};
+
+struct em28xx_eeprom {
+ u32 id; /* 0x9567eb1a */
+ u16 vendor_ID;
+ u16 product_ID;
+
+ u16 chip_conf;
+
+ u16 board_conf;
+
+ u16 string1, string2, string3;
+
+ u8 string_idx_table;
+};
+
+/* device states */
+enum em28xx_dev_state {
+ DEV_INITIALIZED = 0x01,
+ DEV_DISCONNECTED = 0x02,
+ DEV_MISCONFIGURED = 0x04,
+};
+
+/* tvnorms */
+struct em28xx_tvnorm {
+ char *name;
+ v4l2_std_id id;
+ /* mode for saa7113h */
+ int mode;
+};
+
+/* main device struct */
+struct em28xx {
+ /* generic device properties */
+ char name[30]; /* name (including minor) of the device */
+ int model; /* index in the device_data struct */
+ unsigned int is_em2800;
+ int video_inputs; /* number of video inputs */
+ struct list_head devlist;
+ unsigned int has_tuner:1;
+ unsigned int has_msp34xx:1;
+ unsigned int has_tda9887:1;
+
+ enum em28xx_decoder decoder;
+
+ int tuner_type; /* type of the tuner */
+ int tuner_addr; /* tuner address */
+ int tda9887_conf;
+ /* i2c i/o */
+ struct i2c_adapter i2c_adap;
+ struct i2c_client i2c_client;
+ /* video for linux */
+ int users; /* user count for exclusive use */
+ struct video_device *vdev; /* video for linux device struct */
+ struct video_picture vpic; /* picture settings only used to init saa7113h */
+ struct em28xx_tvnorm *tvnorm; /* selected tv norm */
+ int ctl_freq; /* selected frequency */
+ unsigned int ctl_input; /* selected input */
+ unsigned int ctl_ainput; /* slected audio input */
+ int mute;
+ int volume;
+ /* frame properties */
+ struct em28xx_frame_t frame[EM28XX_NUM_FRAMES]; /* list of frames */
+ int num_frames; /* number of frames currently in use */
+ unsigned int frame_count; /* total number of transfered frames */
+ struct em28xx_frame_t *frame_current; /* the frame that is being filled */
+ int width; /* current frame width */
+ int height; /* current frame height */
+ int frame_size; /* current frame size */
+ int field_size; /* current field size */
+ int bytesperline;
+ int hscale; /* horizontal scale factor (see datasheet) */
+ int vscale; /* vertical scale factor (see datasheet) */
+ int interlaced; /* 1=interlace fileds, 0=just top fileds */
+ int type;
+
+ /* states */
+ enum em28xx_dev_state state;
+ enum em28xx_stream_state stream;
+ enum em28xx_io_method io;
+ /* locks */
+ struct semaphore lock, fileop_lock;
+ spinlock_t queue_lock;
+ struct list_head inqueue, outqueue;
+ wait_queue_head_t open, wait_frame, wait_stream;
+ struct video_device *vbi_dev;
+
+ unsigned char eedata[256];
+
+ /* usb transfer */
+ struct usb_device *udev; /* the usb device */
+ int alt; /* alternate */
+ int max_pkt_size; /* max packet size of isoc transaction */
+ int num_alt; /* Number of alternative settings */
+ unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
+ struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */
+ char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc transfer */
+ /* helper funcs that call usb_control_msg */
+ int (*em28xx_write_regs) (struct em28xx * dev, u16 reg, char *buf,
+ int len);
+ int (*em28xx_read_reg) (struct em28xx * dev, u16 reg);
+ int (*em28xx_read_reg_req_len) (struct em28xx * dev, u8 req, u16 reg,
+ char *buf, int len);
+ int (*em28xx_write_regs_req) (struct em28xx * dev, u8 req, u16 reg,
+ char *buf, int len);
+ int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg);
+};
+
+/* Provided by em28xx-i2c.c */
+
+void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg);
+int em28xx_i2c_register(struct em28xx *dev);
+int em28xx_i2c_unregister(struct em28xx *dev);
+
+/* Provided by em28xx-input.c */
+
+void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir);
+
+/* Provided by em28xx-core.c */
+
+void em28xx_print_ioctl(char *name, unsigned int cmd);
+
+u32 em28xx_request_buffers(struct em28xx *dev, u32 count);
+void em28xx_queue_unusedframes(struct em28xx *dev);
+void em28xx_release_buffers(struct em28xx *dev);
+
+int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
+ char *buf, int len);
+int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg);
+int em28xx_read_reg(struct em28xx *dev, u16 reg);
+int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
+ int len);
+int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
+int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
+ u8 bitmask);
+int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val);
+int em28xx_audio_analog_set(struct em28xx *dev);
+int em28xx_colorlevels_set_default(struct em28xx *dev);
+int em28xx_capture_start(struct em28xx *dev, int start);
+int em28xx_outfmt_set_yuv422(struct em28xx *dev);
+int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
+ u8 ymax);
+int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+ u16 width, u16 height);
+int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v);
+int em28xx_resolution_set(struct em28xx *dev);
+void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs);
+int em28xx_init_isoc(struct em28xx *dev);
+void em28xx_uninit_isoc(struct em28xx *dev);
+int em28xx_set_alternate(struct em28xx *dev);
+
+/* Provided by em28xx-cards.c */
+extern int em2800_variant_detect(struct usb_device* udev,int model);
+extern void em28xx_card_setup(struct em28xx *dev);
+extern struct em28xx_board em28xx_boards[];
+extern struct usb_device_id em28xx_id_table[];
+extern const unsigned int em28xx_bcount;
+
+/* em28xx registers */
+#define CHIPID_REG 0x0a
+#define USBSUSP_REG 0x0c /* */
+
+#define AUDIOSRC_REG 0x0e
+#define XCLK_REG 0x0f
+
+#define VINMODE_REG 0x10
+#define VINCTRL_REG 0x11
+#define VINENABLE_REG 0x12 /* */
+
+#define GAMMA_REG 0x14
+#define RGAIN_REG 0x15
+#define GGAIN_REG 0x16
+#define BGAIN_REG 0x17
+#define ROFFSET_REG 0x18
+#define GOFFSET_REG 0x19
+#define BOFFSET_REG 0x1a
+
+#define OFLOW_REG 0x1b
+#define HSTART_REG 0x1c
+#define VSTART_REG 0x1d
+#define CWIDTH_REG 0x1e
+#define CHEIGHT_REG 0x1f
+
+#define YGAIN_REG 0x20
+#define YOFFSET_REG 0x21
+#define UVGAIN_REG 0x22
+#define UOFFSET_REG 0x23
+#define VOFFSET_REG 0x24
+#define SHARPNESS_REG 0x25
+
+#define COMPR_REG 0x26
+#define OUTFMT_REG 0x27
+
+#define XMIN_REG 0x28
+#define XMAX_REG 0x29
+#define YMIN_REG 0x2a
+#define YMAX_REG 0x2b
+
+#define HSCALELOW_REG 0x30
+#define HSCALEHIGH_REG 0x31
+#define VSCALELOW_REG 0x32
+#define VSCALEHIGH_REG 0x33
+
+#define AC97LSB_REG 0x40
+#define AC97MSB_REG 0x41
+#define AC97ADDR_REG 0x42
+#define AC97BUSY_REG 0x43
+
+/* em202 registers */
+#define MASTER_AC97 0x02
+#define VIDEO_AC97 0x14
+
+/* register settings */
+#define EM28XX_AUDIO_SRC_TUNER 0xc0
+#define EM28XX_AUDIO_SRC_LINE 0x80
+
+/* printk macros */
+
+#define em28xx_err(fmt, arg...) do {\
+ printk(KERN_ERR fmt , ##arg); } while (0)
+
+#define em28xx_errdev(fmt, arg...) do {\
+ printk(KERN_ERR "%s: "fmt,\
+ dev->name , ##arg); } while (0)
+
+#define em28xx_info(fmt, arg...) do {\
+ printk(KERN_INFO "%s: "fmt,\
+ dev->name , ##arg); } while (0)
+#define em28xx_warn(fmt, arg...) do {\
+ printk(KERN_WARNING "%s: "fmt,\
+ dev->name , ##arg); } while (0)
+
+inline static int em28xx_audio_source(struct em28xx *dev, int input)
+{
+ return em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
+}
+
+inline static int em28xx_audio_usb_mute(struct em28xx *dev, int mute)
+{
+ return em28xx_write_reg_bits(dev, XCLK_REG, mute ? 0x00 : 0x80, 0x80);
+}
+
+inline static int em28xx_audio_analog_setup(struct em28xx *dev)
+{
+ /* unmute video mixer with default volume level */
+ return em28xx_write_ac97(dev, VIDEO_AC97, "\x08\x08");
+}
+
+inline static int em28xx_compression_disable(struct em28xx *dev)
+{
+ /* side effect of disabling scaler and mixer */
+ return em28xx_write_regs(dev, COMPR_REG, "\x00", 1);
+}
+
+inline static int em28xx_contrast_get(struct em28xx *dev)
+{
+ return em28xx_read_reg(dev, YGAIN_REG) & 0x1f;
+}
+
+inline static int em28xx_brightness_get(struct em28xx *dev)
+{
+ return em28xx_read_reg(dev, YOFFSET_REG);
+}
+
+inline static int em28xx_saturation_get(struct em28xx *dev)
+{
+ return em28xx_read_reg(dev, UVGAIN_REG) & 0x1f;
+}
+
+inline static int em28xx_u_balance_get(struct em28xx *dev)
+{
+ return em28xx_read_reg(dev, UOFFSET_REG);
+}
+
+inline static int em28xx_v_balance_get(struct em28xx *dev)
+{
+ return em28xx_read_reg(dev, VOFFSET_REG);
+}
+
+inline static int em28xx_gamma_get(struct em28xx *dev)
+{
+ return em28xx_read_reg(dev, GAMMA_REG) & 0x3f;
+}
+
+inline static int em28xx_contrast_set(struct em28xx *dev, s32 val)
+{
+ u8 tmp = (u8) val;
+ return em28xx_write_regs(dev, YGAIN_REG, &tmp, 1);
+}
+
+inline static int em28xx_brightness_set(struct em28xx *dev, s32 val)
+{
+ u8 tmp = (u8) val;
+ return em28xx_write_regs(dev, YOFFSET_REG, &tmp, 1);
+}
+
+inline static int em28xx_saturation_set(struct em28xx *dev, s32 val)
+{
+ u8 tmp = (u8) val;
+ return em28xx_write_regs(dev, UVGAIN_REG, &tmp, 1);
+}
+
+inline static int em28xx_u_balance_set(struct em28xx *dev, s32 val)
+{
+ u8 tmp = (u8) val;
+ return em28xx_write_regs(dev, UOFFSET_REG, &tmp, 1);
+}
+
+inline static int em28xx_v_balance_set(struct em28xx *dev, s32 val)
+{
+ u8 tmp = (u8) val;
+ return em28xx_write_regs(dev, VOFFSET_REG, &tmp, 1);
+}
+
+inline static int em28xx_gamma_set(struct em28xx *dev, s32 val)
+{
+ u8 tmp = (u8) val;
+ return em28xx_write_regs(dev, GAMMA_REG, &tmp, 1);
+}
+
+/*FIXME: maxw should be dependent of alt mode */
+inline static unsigned int norm_maxw(struct em28xx *dev)
+{
+ switch(dev->model){
+ case (EM2820_BOARD_MSI_VOX_USB_2): return(640);
+ default: return(720);
+ }
+}
+
+inline static unsigned int norm_maxh(struct em28xx *dev)
+{
+ switch(dev->model){
+ case (EM2820_BOARD_MSI_VOX_USB_2): return(480);
+ default: return (dev->tvnorm->id & V4L2_STD_625_50) ? 576 : 480;
+ }
+}
+
+#endif
diff --git a/drivers/media/video/ir-kbd-gpio.c b/drivers/media/video/ir-kbd-gpio.c
index 234151e48ed..ed81934ef3c 100644
--- a/drivers/media/video/ir-kbd-gpio.c
+++ b/drivers/media/video/ir-kbd-gpio.c
@@ -156,6 +156,71 @@ static IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
/* ---------------------------------------------------------------------- */
+/* Ricardo Cerqueira <v4l@cerqueira.org> */
+/* Weird matching, since the remote has "uncommon" keys */
+
+static IR_KEYTAB_TYPE ir_codes_conceptronic[IR_KEYTAB_SIZE] = {
+
+ [ 30 ] = KEY_POWER, // power
+ [ 7 ] = KEY_MEDIA, // source
+ [ 28 ] = KEY_SEARCH, // scan
+
+/* FIXME: duplicate keycodes?
+ *
+ * These four keys seem to share the same GPIO as CH+, CH-, <<< and >>>
+ * The GPIO values are
+ * 6397fb for both "Scan <" and "CH -",
+ * 639ffb for "Scan >" and "CH+",
+ * 6384fb for "Tune <" and "<<<",
+ * 638cfb for "Tune >" and ">>>", regardless of the mask.
+ *
+ * [ 23 ] = KEY_BACK, // fm scan <<
+ * [ 31 ] = KEY_FORWARD, // fm scan >>
+ *
+ * [ 4 ] = KEY_LEFT, // fm tuning <
+ * [ 12 ] = KEY_RIGHT, // fm tuning >
+ *
+ * For now, these four keys are disabled. Pressing them will generate
+ * the CH+/CH-/<<</>>> events
+ */
+
+ [ 3 ] = KEY_TUNER, // TV/FM
+
+ [ 0 ] = KEY_RECORD,
+ [ 8 ] = KEY_STOP,
+ [ 17 ] = KEY_PLAY,
+
+ [ 26 ] = KEY_PLAYPAUSE, // freeze
+ [ 25 ] = KEY_ZOOM, // zoom
+ [ 15 ] = KEY_TEXT, // min
+
+ [ 1 ] = KEY_KP1,
+ [ 11 ] = KEY_KP2,
+ [ 27 ] = KEY_KP3,
+ [ 5 ] = KEY_KP4,
+ [ 9 ] = KEY_KP5,
+ [ 21 ] = KEY_KP6,
+ [ 6 ] = KEY_KP7,
+ [ 10 ] = KEY_KP8,
+ [ 18 ] = KEY_KP9,
+ [ 2 ] = KEY_KP0,
+ [ 16 ] = KEY_LAST, // +100
+ [ 19 ] = KEY_LIST, // recall
+
+ [ 31 ] = KEY_CHANNELUP, // chn down
+ [ 23 ] = KEY_CHANNELDOWN, // chn up
+ [ 22 ] = KEY_VOLUMEUP, // vol down
+ [ 20 ] = KEY_VOLUMEDOWN, // vol up
+
+ [ 4 ] = KEY_KPMINUS, // <<<
+ [ 14 ] = KEY_SETUP, // function
+ [ 12 ] = KEY_KPPLUS, // >>>
+
+ [ 13 ] = KEY_GOTO, // mts
+ [ 29 ] = KEY_REFRESH, // reset
+ [ 24 ] = KEY_MUTE // mute/unmute
+};
+
struct IR {
struct bttv_sub_device *sub;
struct input_dev *input;
@@ -282,53 +347,59 @@ static int ir_probe(struct device *dev)
/* detect & configure */
switch (sub->core->type) {
- case BTTV_AVERMEDIA:
- case BTTV_AVPHONE98:
- case BTTV_AVERMEDIA98:
+ case BTTV_BOARD_AVERMEDIA:
+ case BTTV_BOARD_AVPHONE98:
+ case BTTV_BOARD_AVERMEDIA98:
ir_codes = ir_codes_avermedia;
ir->mask_keycode = 0xf88000;
ir->mask_keydown = 0x010000;
ir->polling = 50; // ms
break;
- case BTTV_AVDVBT_761:
- case BTTV_AVDVBT_771:
+ case BTTV_BOARD_AVDVBT_761:
+ case BTTV_BOARD_AVDVBT_771:
ir_codes = ir_codes_avermedia_dvbt;
ir->mask_keycode = 0x0f00c0;
ir->mask_keydown = 0x000020;
ir->polling = 50; // ms
break;
- case BTTV_PXELVWPLTVPAK:
+ case BTTV_BOARD_PXELVWPLTVPAK:
ir_codes = ir_codes_pixelview;
ir->mask_keycode = 0x003e00;
ir->mask_keyup = 0x010000;
ir->polling = 50; // ms
- break;
- case BTTV_PV_BT878P_9B:
- case BTTV_PV_BT878P_PLUS:
+ break;
+ case BTTV_BOARD_PV_BT878P_9B:
+ case BTTV_BOARD_PV_BT878P_PLUS:
ir_codes = ir_codes_pixelview;
ir->mask_keycode = 0x001f00;
ir->mask_keyup = 0x008000;
ir->polling = 50; // ms
- break;
+ break;
- case BTTV_WINFAST2000:
+ case BTTV_BOARD_WINFAST2000:
ir_codes = ir_codes_winfast;
ir->mask_keycode = 0x1f8;
break;
- case BTTV_MAGICTVIEW061:
- case BTTV_MAGICTVIEW063:
+ case BTTV_BOARD_MAGICTVIEW061:
+ case BTTV_BOARD_MAGICTVIEW063:
ir_codes = ir_codes_winfast;
ir->mask_keycode = 0x0008e000;
ir->mask_keydown = 0x00200000;
break;
- case BTTV_APAC_VIEWCOMP:
+ case BTTV_BOARD_APAC_VIEWCOMP:
ir_codes = ir_codes_apac_viewcomp;
ir->mask_keycode = 0x001f00;
ir->mask_keyup = 0x008000;
ir->polling = 50; // ms
break;
+ case BTTV_BOARD_CONCEPTRONIC_CTVFMI2:
+ ir_codes = ir_codes_conceptronic;
+ ir->mask_keycode = 0x001F00;
+ ir->mask_keyup = 0x006000;
+ ir->polling = 50; // ms
+ break;
}
if (NULL == ir_codes) {
kfree(ir);
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 9703d3d351f..0085567a142 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -8,6 +8,8 @@
* Christoph Bartelmus <lirc@bartelmus.de>
* modified for KNC ONE TV Station/Anubis Typhoon TView Tuner by
* Ulrich Mueller <ulrich.mueller42@web.de>
+ * modified for em2820 based USB TV tuners by
+ * Markus Rechberger <mrechberger@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -37,10 +39,9 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
-
#include <asm/semaphore.h>
-
#include <media/ir-common.h>
+#include <media/ir-kbd-i2c.h>
/* Mark Phalan <phalanm@o2.ie> */
static IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
@@ -81,57 +82,6 @@ static IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
[ 28 ] = KEY_MEDIA, /* PC/TV */
};
-static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
- [ 0x3 ] = KEY_POWER,
- [ 0x6f ] = KEY_MUTE,
- [ 0x10 ] = KEY_BACKSPACE, /* Recall */
-
- [ 0x11 ] = KEY_KP0,
- [ 0x4 ] = KEY_KP1,
- [ 0x5 ] = KEY_KP2,
- [ 0x6 ] = KEY_KP3,
- [ 0x8 ] = KEY_KP4,
- [ 0x9 ] = KEY_KP5,
- [ 0xa ] = KEY_KP6,
- [ 0xc ] = KEY_KP7,
- [ 0xd ] = KEY_KP8,
- [ 0xe ] = KEY_KP9,
- [ 0x12 ] = KEY_KPDOT, /* 100+ */
-
- [ 0x7 ] = KEY_VOLUMEUP,
- [ 0xb ] = KEY_VOLUMEDOWN,
- [ 0x1a ] = KEY_KPPLUS,
- [ 0x18 ] = KEY_KPMINUS,
- [ 0x15 ] = KEY_UP,
- [ 0x1d ] = KEY_DOWN,
- [ 0xf ] = KEY_CHANNELUP,
- [ 0x13 ] = KEY_CHANNELDOWN,
- [ 0x48 ] = KEY_ZOOM,
-
- [ 0x1b ] = KEY_VIDEO, /* Video source */
- [ 0x49 ] = KEY_LANGUAGE, /* MTS Select */
- [ 0x19 ] = KEY_SEARCH, /* Auto Scan */
-
- [ 0x4b ] = KEY_RECORD,
- [ 0x46 ] = KEY_PLAY,
- [ 0x45 ] = KEY_PAUSE, /* Pause */
- [ 0x44 ] = KEY_STOP,
- [ 0x40 ] = KEY_FORWARD, /* Forward ? */
- [ 0x42 ] = KEY_REWIND, /* Backward ? */
-
-};
-
-struct IR {
- struct i2c_client c;
- struct input_dev *input;
- struct ir_input_state ir;
-
- struct work_struct work;
- struct timer_list timer;
- char phys[32];
- int (*get_key)(struct IR*, u32*, u32*);
-};
-
/* ----------------------------------------------------------------------- */
/* insmod parameters */
@@ -144,7 +94,7 @@ module_param(debug, int, 0644); /* debug level (0,1,2) */
/* ----------------------------------------------------------------------- */
-static int get_key_haup(struct IR *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char buf[3];
int start, toggle, dev, code;
@@ -171,9 +121,9 @@ static int get_key_haup(struct IR *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-static int get_key_pixelview(struct IR *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
- unsigned char b;
+ unsigned char b;
/* poll IR chip */
if (1 != i2c_master_recv(&ir->c,&b,1)) {
@@ -185,9 +135,9 @@ static int get_key_pixelview(struct IR *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-static int get_key_pv951(struct IR *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
- unsigned char b;
+ unsigned char b;
/* poll IR chip */
if (1 != i2c_master_recv(&ir->c,&b,1)) {
@@ -205,7 +155,7 @@ static int get_key_pv951(struct IR *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-static int get_key_knc1(struct IR *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char b;
@@ -216,15 +166,15 @@ static int get_key_knc1(struct IR *ir, u32 *ir_key, u32 *ir_raw)
}
/* it seems that 0xFE indicates that a button is still hold
- down, while 0xFF indicates that no button is hold
- down. 0xFE sequences are sometimes interrupted by 0xFF */
+ down, while 0xff indicates that no button is hold
+ down. 0xfe sequences are sometimes interrupted by 0xFF */
dprintk(2,"key %02x\n", b);
- if (b == 0xFF)
+ if (b == 0xff)
return 0;
- if (b == 0xFE)
+ if (b == 0xfe)
/* keep old data */
return 1;
@@ -233,31 +183,9 @@ static int get_key_knc1(struct IR *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-static int get_key_purpletv(struct IR *ir, u32 *ir_key, u32 *ir_raw)
-{
- unsigned char b;
-
- /* poll IR chip */
- if (1 != i2c_master_recv(&ir->c,&b,1)) {
- dprintk(1,"read error\n");
- return -EIO;
- }
-
- /* no button press */
- if (b==0)
- return 0;
-
- /* repeating */
- if (b & 0x80)
- return 1;
-
- *ir_key = b;
- *ir_raw = b;
- return 1;
-}
/* ----------------------------------------------------------------------- */
-static void ir_key_poll(struct IR *ir)
+static void ir_key_poll(struct IR_i2c *ir)
{
static u32 ir_key, ir_raw;
int rc;
@@ -278,13 +206,13 @@ static void ir_key_poll(struct IR *ir)
static void ir_timer(unsigned long data)
{
- struct IR *ir = (struct IR*)data;
+ struct IR_i2c *ir = (struct IR_i2c*)data;
schedule_work(&ir->work);
}
static void ir_work(void *data)
{
- struct IR *ir = data;
+ struct IR_i2c *ir = data;
ir_key_poll(ir);
mod_timer(&ir->timer, jiffies+HZ/10);
}
@@ -297,17 +225,17 @@ static int ir_detach(struct i2c_client *client);
static int ir_probe(struct i2c_adapter *adap);
static struct i2c_driver driver = {
- .name = "ir remote kbd driver",
- .id = I2C_DRIVERID_EXP3, /* FIXME */
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = ir_probe,
- .detach_client = ir_detach,
+ .name = "ir remote kbd driver",
+ .id = I2C_DRIVERID_EXP3, /* FIXME */
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = ir_probe,
+ .detach_client = ir_detach,
};
static struct i2c_client client_template =
{
- .name = "unset",
- .driver = &driver
+ .name = "unset",
+ .driver = &driver
};
static int ir_attach(struct i2c_adapter *adap, int addr,
@@ -316,10 +244,10 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
IR_KEYTAB_TYPE *ir_codes = NULL;
char *name;
int ir_type;
- struct IR *ir;
+ struct IR_i2c *ir;
struct input_dev *input_dev;
- ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
+ ir = kzalloc(sizeof(struct IR_i2c), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ir || !input_dev) {
kfree(ir);
@@ -361,10 +289,10 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
ir_codes = ir_codes_empty;
break;
case 0x7a:
- name = "Purple TV";
- ir->get_key = get_key_purpletv;
+ case 0x47:
+ /* Handled by saa7134-input */
+ name = "SAA713x remote";
ir_type = IR_TYPE_OTHER;
- ir_codes = ir_codes_purpletv;
break;
default:
/* shouldn't happen */
@@ -373,9 +301,24 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
return -1;
}
- /* register i2c device */
- i2c_attach_client(&ir->c);
+ /* Sets name */
snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (%s)", name);
+ ir->ir_codes=ir_codes;
+
+ /* register i2c device
+ * At device register, IR codes may be changed to be
+ * board dependent.
+ */
+ i2c_attach_client(&ir->c);
+
+ /* If IR not supported or disabled, unregisters driver */
+ if (ir->get_key == NULL) {
+ i2c_detach_client(&ir->c);
+ kfree(ir);
+ return -1;
+ }
+
+ /* Phys addr can only be set after attaching (for ir->c.dev.bus_id) */
snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0",
ir->c.adapter->dev.bus_id,
ir->c.dev.bus_id);
@@ -386,6 +329,7 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
input_dev->name = ir->c.name;
input_dev->phys = ir->phys;
+ /* register event device */
input_register_device(ir->input);
/* start polling via eventd */
@@ -400,7 +344,7 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
static int ir_detach(struct i2c_client *client)
{
- struct IR *ir = i2c_get_clientdata(client);
+ struct IR_i2c *ir = i2c_get_clientdata(client);
/* kill outstanding polls */
del_timer(&ir->timer);
@@ -428,9 +372,12 @@ static int ir_probe(struct i2c_adapter *adap)
*/
static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
- static const int probe_saa7134[] = { 0x7a, -1 };
+ static const int probe_saa7134[] = { 0x7a, 0x47, -1 };
+ static const int probe_em28XX[] = { 0x30, 0x47, -1 };
const int *probe = NULL;
- struct i2c_client c; char buf; int i,rc;
+ struct i2c_client c;
+ unsigned char buf;
+ int i,rc;
switch (adap->id) {
case I2C_HW_B_BT848:
@@ -439,6 +386,9 @@ static int ir_probe(struct i2c_adapter *adap)
case I2C_HW_SAA7134:
probe = probe_saa7134;
break;
+ case I2C_HW_B_EM28XX:
+ probe = probe_em28XX;
+ break;
}
if (NULL == probe)
return 0;
@@ -447,11 +397,11 @@ static int ir_probe(struct i2c_adapter *adap)
c.adapter = adap;
for (i = 0; -1 != probe[i]; i++) {
c.addr = probe[i];
- rc = i2c_master_recv(&c,&buf,1);
+ rc = i2c_master_recv(&c,&buf,0);
dprintk(1,"probe 0x%02x @ %s: %s\n",
probe[i], adap->name,
- (1 == rc) ? "yes" : "no");
- if (1 == rc) {
+ (0 == rc) ? "yes" : "no");
+ if (0 == rc) {
ir_attach(adap,probe[i],0,0);
break;
}
diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c
index e75e7948fd9..a23fb033898 100644
--- a/drivers/media/video/msp3400.c
+++ b/drivers/media/video/msp3400.c
@@ -54,9 +54,41 @@
#include <asm/pgtable.h>
#include <media/audiochip.h>
-#include <media/id.h>
#include "msp3400.h"
+#define msp3400_dbg(fmt, arg...) \
+ do { \
+ if (debug) \
+ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); \
+ } while (0)
+
+/* Medium volume debug. */
+#define msp3400_dbg_mediumvol(fmt, arg...) \
+ do { \
+ if (debug >= 2) \
+ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); \
+ } while (0)
+
+/* High volume debug. Use with care. */
+#define msp3400_dbg_highvol(fmt, arg...) \
+ do { \
+ if (debug >= 16) \
+ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); \
+ } while (0)
+
+#define msp3400_err(fmt, arg...) do { \
+ printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define msp3400_warn(fmt, arg...) do { \
+ printk(KERN_WARNING "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define msp3400_info(fmt, arg...) do { \
+ printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
#define OPMODE_AUTO -1
#define OPMODE_MANUAL 0
#define OPMODE_SIMPLE 1 /* use short programming (>= msp3410 only) */
@@ -73,15 +105,26 @@ static int dolby = 0;
static int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual
(msp34xxg only) 0x00a0-0x03c0 */
+#define DFP_COUNT 0x41
+static const int bl_dfp[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x06, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0d, 0x0e, 0x10
+};
+
+#define IS_MSP34XX_G(msp) ((msp)->opmode==2)
struct msp3400c {
int rev1,rev2;
int opmode;
+ int nicam;
int mode;
int norm;
+ int stereo;
int nicam_on;
int acb;
+ int in_scart;
+ int i2s_mode;
int main, second; /* sound carrier */
int input;
int source; /* see msp34xxg_set_source */
@@ -91,9 +134,12 @@ struct msp3400c {
int rxsubchans;
int muted;
- int volume, balance;
+ int left, right; /* volume */
int bass, treble;
+ /* shadow register set */
+ int dfp_regs[DFP_COUNT];
+
/* thread */
struct task_struct *kthread;
wait_queue_head_t wq;
@@ -101,6 +147,8 @@ struct msp3400c {
int watch_stereo:1;
};
+#define MIN(a,b) (((a)>(b))?(b):(a))
+#define MAX(a,b) (((a)>(b))?(a):(b))
#define HAVE_NICAM(msp) (((msp->rev2>>8) & 0xff) != 00)
#define HAVE_SIMPLE(msp) ((msp->rev1 & 0xff) >= 'D'-'@')
#define HAVE_SIMPLER(msp) ((msp->rev1 & 0xff) >= 'G'-'@')
@@ -110,9 +158,6 @@ struct msp3400c {
/* ---------------------------------------------------------------------- */
-#define dprintk if (debug >= 1) printk
-#define d2printk if (debug >= 2) printk
-
/* read-only */
module_param(opmode, int, 0444);
@@ -132,11 +177,6 @@ MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Defau
MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan");
MODULE_PARM_DESC(dolby, "Activates Dolby processsing");
-
-MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("Dual BSD/GPL"); /* FreeBSD uses this too */
-
/* ---------------------------------------------------------------------- */
#define I2C_MSP3400C 0x80
@@ -153,6 +193,10 @@ static unsigned short normal_i2c[] = {
};
I2C_CLIENT_INSMOD;
+MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
+MODULE_AUTHOR("Gerd Knorr");
+MODULE_LICENSE("GPL");
+
/* ----------------------------------------------------------------------- */
/* functions for talking to the MSP3400C Sound processor */
@@ -172,68 +216,73 @@ static int msp3400c_reset(struct i2c_client *client)
{ client->addr, I2C_M_RD, 2, read },
};
+ msp3400_dbg_highvol("msp3400c_reset\n");
if ( (1 != i2c_transfer(client->adapter,&reset[0],1)) ||
(1 != i2c_transfer(client->adapter,&reset[1],1)) ||
(2 != i2c_transfer(client->adapter,test,2)) ) {
- printk(KERN_ERR "msp3400: chip reset failed\n");
+ msp3400_err("chip reset failed\n");
return -1;
- }
+ }
return 0;
}
-static int
-msp3400c_read(struct i2c_client *client, int dev, int addr)
+static int msp3400c_read(struct i2c_client *client, int dev, int addr)
{
- int err;
+ int err,retval;
+
+ unsigned char write[3];
+ unsigned char read[2];
+ struct i2c_msg msgs[2] = {
+ { client->addr, 0, 3, write },
+ { client->addr, I2C_M_RD, 2, read }
+ };
- unsigned char write[3];
- unsigned char read[2];
- struct i2c_msg msgs[2] = {
- { client->addr, 0, 3, write },
- { client->addr, I2C_M_RD, 2, read }
- };
- write[0] = dev+1;
- write[1] = addr >> 8;
- write[2] = addr & 0xff;
+ write[0] = dev+1;
+ write[1] = addr >> 8;
+ write[2] = addr & 0xff;
for (err = 0; err < 3;) {
if (2 == i2c_transfer(client->adapter,msgs,2))
break;
err++;
- printk(KERN_WARNING "msp34xx: I/O error #%d (read 0x%02x/0x%02x)\n",
- err, dev, addr);
- msleep(10);
+ msp3400_warn("I/O error #%d (read 0x%02x/0x%02x)\n", err,
+ dev, addr);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(msecs_to_jiffies(10));
}
if (3 == err) {
- printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n");
+ msp3400_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n");
msp3400c_reset(client);
return -1;
}
- return read[0] << 8 | read[1];
+ retval = read[0] << 8 | read[1];
+ msp3400_dbg_highvol("msp3400c_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval);
+ return retval;
}
-static int
-msp3400c_write(struct i2c_client *client, int dev, int addr, int val)
+static int msp3400c_write(struct i2c_client *client, int dev, int addr, int val)
{
int err;
- unsigned char buffer[5];
+ unsigned char buffer[5];
- buffer[0] = dev;
- buffer[1] = addr >> 8;
- buffer[2] = addr & 0xff;
- buffer[3] = val >> 8;
- buffer[4] = val & 0xff;
+ buffer[0] = dev;
+ buffer[1] = addr >> 8;
+ buffer[2] = addr & 0xff;
+ buffer[3] = val >> 8;
+ buffer[4] = val & 0xff;
+ msp3400_dbg_highvol("msp3400c_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val);
for (err = 0; err < 3;) {
if (5 == i2c_master_send(client, buffer, 5))
break;
err++;
- printk(KERN_WARNING "msp34xx: I/O error #%d (write 0x%02x/0x%02x)\n",
- err, dev, addr);
- msleep(10);
+ msp3400_warn("I/O error #%d (write 0x%02x/0x%02x)\n", err,
+ dev, addr);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(msecs_to_jiffies(10));
}
if (3 == err) {
- printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n");
+ msp3400_warn("giving up, reseting chip. Sound will go off, sorry folks :-|\n");
msp3400c_reset(client);
return -1;
}
@@ -266,45 +315,47 @@ static struct MSP_INIT_DATA_DEM {
int dfp_src;
int dfp_matrix;
} msp_init_data[] = {
- /* AM (for carrier detect / msp3400) */
- { { 75, 19, 36, 35, 39, 40 }, { 75, 19, 36, 35, 39, 40 },
- MSP_CARRIER(5.5), MSP_CARRIER(5.5),
- 0x00d0, 0x0500, 0x0020, 0x3000},
-
- /* AM (for carrier detect / msp3410) */
- { { -1, -1, -8, 2, 59, 126 }, { -1, -1, -8, 2, 59, 126 },
- MSP_CARRIER(5.5), MSP_CARRIER(5.5),
- 0x00d0, 0x0100, 0x0020, 0x3000},
-
- /* FM Radio */
- { { -8, -8, 4, 6, 78, 107 }, { -8, -8, 4, 6, 78, 107 },
- MSP_CARRIER(10.7), MSP_CARRIER(10.7),
- 0x00d0, 0x0480, 0x0020, 0x3000 },
-
- /* Terrestial FM-mono + FM-stereo */
- { { 3, 18, 27, 48, 66, 72 }, { 3, 18, 27, 48, 66, 72 },
- MSP_CARRIER(5.5), MSP_CARRIER(5.5),
- 0x00d0, 0x0480, 0x0030, 0x3000},
-
- /* Sat FM-mono */
- { { 1, 9, 14, 24, 33, 37 }, { 3, 18, 27, 48, 66, 72 },
- MSP_CARRIER(6.5), MSP_CARRIER(6.5),
- 0x00c6, 0x0480, 0x0000, 0x3000},
-
- /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */
- { { -2, -8, -10, 10, 50, 86 }, { 3, 18, 27, 48, 66, 72 },
- MSP_CARRIER(5.5), MSP_CARRIER(5.5),
- 0x00d0, 0x0040, 0x0120, 0x3000},
-
- /* NICAM/FM -- I (6.0/6.552) */
- { { 2, 4, -6, -4, 40, 94 }, { 3, 18, 27, 48, 66, 72 },
- MSP_CARRIER(6.0), MSP_CARRIER(6.0),
- 0x00d0, 0x0040, 0x0120, 0x3000},
-
- /* NICAM/AM -- L (6.5/5.85) */
- { { -2, -8, -10, 10, 50, 86 }, { -4, -12, -9, 23, 79, 126 },
- MSP_CARRIER(6.5), MSP_CARRIER(6.5),
- 0x00c6, 0x0140, 0x0120, 0x7c03},
+ { /* AM (for carrier detect / msp3400) */
+ {75, 19, 36, 35, 39, 40},
+ {75, 19, 36, 35, 39, 40},
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 0x00d0, 0x0500, 0x0020, 0x3000
+ },{ /* AM (for carrier detect / msp3410) */
+ {-1, -1, -8, 2, 59, 126},
+ {-1, -1, -8, 2, 59, 126},
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 0x00d0, 0x0100, 0x0020, 0x3000
+ },{ /* FM Radio */
+ {-8, -8, 4, 6, 78, 107},
+ {-8, -8, 4, 6, 78, 107},
+ MSP_CARRIER(10.7), MSP_CARRIER(10.7),
+ 0x00d0, 0x0480, 0x0020, 0x3000
+ },{ /* Terrestial FM-mono + FM-stereo */
+ {3, 18, 27, 48, 66, 72},
+ {3, 18, 27, 48, 66, 72},
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 0x00d0, 0x0480, 0x0030, 0x3000
+ },{ /* Sat FM-mono */
+ { 1, 9, 14, 24, 33, 37},
+ { 3, 18, 27, 48, 66, 72},
+ MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+ 0x00c6, 0x0480, 0x0000, 0x3000
+ },{ /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */
+ {-2, -8, -10, 10, 50, 86},
+ {3, 18, 27, 48, 66, 72},
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 0x00d0, 0x0040, 0x0120, 0x3000
+ },{ /* NICAM/FM -- I (6.0/6.552) */
+ {2, 4, -6, -4, 40, 94},
+ {3, 18, 27, 48, 66, 72},
+ MSP_CARRIER(6.0), MSP_CARRIER(6.0),
+ 0x00d0, 0x0040, 0x0120, 0x3000
+ },{ /* NICAM/AM -- L (6.5/5.85) */
+ {-2, -8, -10, 10, 50, 86},
+ {-4, -12, -9, 23, 79, 126},
+ MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+ 0x00c6, 0x0140, 0x0120, 0x7c03
+ },
};
struct CARRIER_DETECT {
@@ -338,32 +389,68 @@ static struct CARRIER_DETECT carrier_detect_65[] = {
#define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT))
-/* ----------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- *
+ * bits 9 8 5 - SCART DSP input Select:
+ * 0 0 0 - SCART 1 to DSP input (reset position)
+ * 0 1 0 - MONO to DSP input
+ * 1 0 0 - SCART 2 to DSP input
+ * 1 1 1 - Mute DSP input
+ *
+ * bits 11 10 6 - SCART 1 Output Select:
+ * 0 0 0 - undefined (reset position)
+ * 0 1 0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS)
+ * 1 0 0 - MONO input to SCART 1 Output
+ * 1 1 0 - SCART 1 DA to SCART 1 Output
+ * 0 0 1 - SCART 2 DA to SCART 1 Output
+ * 0 1 1 - SCART 1 Input to SCART 1 Output
+ * 1 1 1 - Mute SCART 1 Output
+ *
+ * bits 13 12 7 - SCART 2 Output Select (for devices with 2 Output SCART):
+ * 0 0 0 - SCART 1 DA to SCART 2 Output (reset position)
+ * 0 1 0 - SCART 1 Input to SCART 2 Output
+ * 1 0 0 - MONO input to SCART 2 Output
+ * 0 0 1 - SCART 2 DA to SCART 2 Output
+ * 0 1 1 - SCART 2 Input to SCART 2 Output
+ * 1 1 0 - Mute SCART 2 Output
+ *
+ * Bits 4 to 0 should be zero.
+ * ----------------------------------------------------------------------- */
static int scarts[3][9] = {
- /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */
- { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 },
- { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
- { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
+ /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */
+ /* SCART DSP Input select */
+ { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 },
+ /* SCART1 Output select */
+ { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
+ /* SCART2 Output select */
+ { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
};
static char *scart_names[] = {
- "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute"
+ "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute"
};
-static void
-msp3400c_set_scart(struct i2c_client *client, int in, int out)
+static void msp3400c_set_scart(struct i2c_client *client, int in, int out)
{
struct msp3400c *msp = i2c_get_clientdata(client);
- if (-1 == scarts[out][in])
- return;
+ msp->in_scart=in;
+
+ if (in >= 1 && in <= 8 && out >= 0 && out <= 2) {
+ if (-1 == scarts[out][in])
+ return;
- dprintk(KERN_DEBUG
- "msp34xx: scart switch: %s => %d\n",scart_names[in],out);
- msp->acb &= ~scarts[out][SCART_MASK];
- msp->acb |= scarts[out][in];
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, msp->acb);
+ msp->acb &= ~scarts[out][SCART_MASK];
+ msp->acb |= scarts[out][in];
+ } else
+ msp->acb = 0xf60; /* Mute Input and SCART 1 Output */
+
+ msp3400_dbg("scart switch: %s => %d (ACB=0x%04x)\n",
+ scart_names[in], out, msp->acb);
+ msp3400c_write(client,I2C_MSP3400C_DFP, 0x13, msp->acb);
+
+ /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */
+ msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
}
/* ------------------------------------------------------------------------ */
@@ -378,33 +465,34 @@ static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2)
}
static void msp3400c_setvolume(struct i2c_client *client,
- int muted, int volume, int balance)
-{
- int val = 0, bal = 0;
+ int muted, int left, int right)
+ {
+ int vol = 0, val = 0, balance = 0;
if (!muted) {
/* 0x7f instead if 0x73 here has sound quality issues,
* probably due to overmodulation + clipping ... */
- val = (volume * 0x73 / 65535) << 8;
+ vol = (left > right) ? left : right;
+ val = (vol * 0x73 / 65535) << 8;
}
- if (val) {
- bal = (balance / 256) - 128;
+ if (vol > 0) {
+ balance = ((right - left) * 127) / vol;
}
- dprintk(KERN_DEBUG
- "msp34xx: setvolume: mute=%s %d:%d v=0x%02x b=0x%02x\n",
- muted ? "on" : "off", volume, balance, val>>8, bal);
+
+ msp3400_dbg("setvolume: mute=%s %d:%d v=0x%02x b=0x%02x\n",
+ muted ? "on" : "off", left, right, val >> 8, balance);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007,
- muted ? 0x01 : (val | 0x01));
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0001, bal << 8);
+ muted ? 0x1 : (val | 0x1));
+ msp3400c_write(client, I2C_MSP3400C_DFP, 0x0001, balance << 8);
}
static void msp3400c_setbass(struct i2c_client *client, int bass)
{
int val = ((bass-32768) * 0x60 / 65535) << 8;
- dprintk(KERN_DEBUG "msp34xx: setbass: %d 0x%02x\n",bass, val>>8);
+ msp3400_dbg("setbass: %d 0x%02x\n", bass, val >> 8);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */
}
@@ -412,7 +500,7 @@ static void msp3400c_settreble(struct i2c_client *client, int treble)
{
int val = ((treble-32768) * 0x60 / 65535) << 8;
- dprintk(KERN_DEBUG "msp34xx: settreble: %d 0x%02x\n",treble, val>>8);
+ msp3400_dbg("settreble: %d 0x%02x\n",treble, val>>8);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */
}
@@ -421,7 +509,7 @@ static void msp3400c_setmode(struct i2c_client *client, int type)
struct msp3400c *msp = i2c_get_clientdata(client);
int i;
- dprintk(KERN_DEBUG "msp3400: setmode: %d\n",type);
+ msp3400_dbg("setmode: %d\n",type);
msp->mode = type;
msp->audmode = V4L2_TUNER_MODE_MONO;
msp->rxsubchans = V4L2_TUNER_SUB_MONO;
@@ -474,7 +562,8 @@ static void msp3400c_setmode(struct i2c_client *client, int type)
}
}
-static int best_audio_mode(int rxsubchans)
+/* given a bitmask of VIDEO_SOUND_XXX returns the "best" in the bitmask */
+static int best_video_sound(int rxsubchans)
{
if (rxsubchans & V4L2_TUNER_SUB_STEREO)
return V4L2_TUNER_MODE_STEREO;
@@ -486,31 +575,31 @@ static int best_audio_mode(int rxsubchans)
}
/* turn on/off nicam + stereo */
-static void msp3400c_set_audmode(struct i2c_client *client, int audmode)
+static void msp3400c_setstereo(struct i2c_client *client, int mode)
{
- static char *strmode[16] = {
-#if __GNUC__ >= 3
- [ 0 ... 15 ] = "invalid",
-#endif
- [ V4L2_TUNER_MODE_MONO ] = "mono",
- [ V4L2_TUNER_MODE_STEREO ] = "stereo",
- [ V4L2_TUNER_MODE_LANG1 ] = "lang1",
- [ V4L2_TUNER_MODE_LANG2 ] = "lang2",
+ static char *strmode[] = { "0", "mono", "stereo", "3",
+ "lang1", "5", "6", "7", "lang2"
};
struct msp3400c *msp = i2c_get_clientdata(client);
- int nicam=0; /* channel source: FM/AM or nicam */
- int src=0;
+ int nicam = 0; /* channel source: FM/AM or nicam */
+ int src = 0;
- BUG_ON(msp->opmode == OPMODE_SIMPLER);
- msp->audmode = audmode;
+ if (IS_MSP34XX_G(msp)) {
+ /* this method would break everything, let's make sure
+ * it's never called
+ */
+ msp3400_dbg
+ ("DEBUG WARNING setstereo called with mode=%d instead of set_source (ignored)\n",
+ mode);
+ return;
+ }
/* switch demodulator */
switch (msp->mode) {
case MSP_MODE_FM_TERRA:
- dprintk(KERN_DEBUG "msp3400: FM setstereo: %s\n",
- strmode[audmode]);
+ msp3400_dbg("FM setstereo: %s\n", strmode[mode]);
msp3400c_setcarrier(client,msp->second,msp->main);
- switch (audmode) {
+ switch (mode) {
case V4L2_TUNER_MODE_STEREO:
msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3001);
break;
@@ -522,9 +611,8 @@ static void msp3400c_set_audmode(struct i2c_client *client, int audmode)
}
break;
case MSP_MODE_FM_SAT:
- dprintk(KERN_DEBUG "msp3400: SAT setstereo: %s\n",
- strmode[audmode]);
- switch (audmode) {
+ msp3400_dbg("SAT setstereo: %s\n", strmode[mode]);
+ switch (mode) {
case V4L2_TUNER_MODE_MONO:
msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
break;
@@ -542,39 +630,35 @@ static void msp3400c_set_audmode(struct i2c_client *client, int audmode)
case MSP_MODE_FM_NICAM1:
case MSP_MODE_FM_NICAM2:
case MSP_MODE_AM_NICAM:
- dprintk(KERN_DEBUG "msp3400: NICAM setstereo: %s\n",
- strmode[audmode]);
+ msp3400_dbg("NICAM setstereo: %s\n",strmode[mode]);
msp3400c_setcarrier(client,msp->second,msp->main);
if (msp->nicam_on)
nicam=0x0100;
break;
case MSP_MODE_BTSC:
- dprintk(KERN_DEBUG "msp3400: BTSC setstereo: %s\n",
- strmode[audmode]);
+ msp3400_dbg("BTSC setstereo: %s\n",strmode[mode]);
nicam=0x0300;
break;
case MSP_MODE_EXTERN:
- dprintk(KERN_DEBUG "msp3400: extern setstereo: %s\n",
- strmode[audmode]);
+ msp3400_dbg("extern setstereo: %s\n",strmode[mode]);
nicam = 0x0200;
break;
case MSP_MODE_FM_RADIO:
- dprintk(KERN_DEBUG "msp3400: FM-Radio setstereo: %s\n",
- strmode[audmode]);
+ msp3400_dbg("FM-Radio setstereo: %s\n",strmode[mode]);
break;
default:
- dprintk(KERN_DEBUG "msp3400: mono setstereo\n");
+ msp3400_dbg("mono setstereo\n");
return;
}
/* switch audio */
- switch (audmode) {
+ switch (best_video_sound(mode)) {
case V4L2_TUNER_MODE_STEREO:
src = 0x0020 | nicam;
break;
case V4L2_TUNER_MODE_MONO:
if (msp->mode == MSP_MODE_AM_NICAM) {
- dprintk("msp3400: switching to AM mono\n");
+ msp3400_dbg("switching to AM mono\n");
/* AM mono decoding is handled by tuner, not MSP chip */
/* SCART switching control register */
msp3400c_set_scart(client,SCART_MONO,0);
@@ -588,8 +672,7 @@ static void msp3400c_set_audmode(struct i2c_client *client, int audmode)
src = 0x0010 | nicam;
break;
}
- dprintk(KERN_DEBUG
- "msp3400: setstereo final source/matrix = 0x%x\n", src);
+ msp3400_dbg("setstereo final source/matrix = 0x%x\n", src);
if (dolby) {
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520);
@@ -605,29 +688,55 @@ static void msp3400c_set_audmode(struct i2c_client *client, int audmode)
}
static void
-msp3400c_print_mode(struct msp3400c *msp)
+msp3400c_print_mode(struct i2c_client *client)
{
+ struct msp3400c *msp = i2c_get_clientdata(client);
+
if (msp->main == msp->second) {
- printk(KERN_DEBUG "msp3400: mono sound carrier: %d.%03d MHz\n",
+ msp3400_dbg("mono sound carrier: %d.%03d MHz\n",
msp->main/910000,(msp->main/910)%1000);
} else {
- printk(KERN_DEBUG "msp3400: main sound carrier: %d.%03d MHz\n",
+ msp3400_dbg("main sound carrier: %d.%03d MHz\n",
msp->main/910000,(msp->main/910)%1000);
}
- if (msp->mode == MSP_MODE_FM_NICAM1 ||
- msp->mode == MSP_MODE_FM_NICAM2)
- printk(KERN_DEBUG "msp3400: NICAM/FM carrier : %d.%03d MHz\n",
+ if (msp->mode == MSP_MODE_FM_NICAM1 || msp->mode == MSP_MODE_FM_NICAM2)
+ msp3400_dbg("NICAM/FM carrier : %d.%03d MHz\n",
msp->second/910000,(msp->second/910)%1000);
if (msp->mode == MSP_MODE_AM_NICAM)
- printk(KERN_DEBUG "msp3400: NICAM/AM carrier : %d.%03d MHz\n",
+ msp3400_dbg("NICAM/AM carrier : %d.%03d MHz\n",
msp->second/910000,(msp->second/910)%1000);
if (msp->mode == MSP_MODE_FM_TERRA &&
msp->main != msp->second) {
- printk(KERN_DEBUG "msp3400: FM-stereo carrier : %d.%03d MHz\n",
+ msp3400_dbg("FM-stereo carrier : %d.%03d MHz\n",
msp->second/910000,(msp->second/910)%1000);
}
}
+#define MSP3400_MAX 4
+static struct i2c_client *msps[MSP3400_MAX];
+static void msp3400c_restore_dfp(struct i2c_client *client)
+{
+ struct msp3400c *msp = i2c_get_clientdata(client);
+ int i;
+
+ for (i = 0; i < DFP_COUNT; i++) {
+ if (-1 == msp->dfp_regs[i])
+ continue;
+ msp3400c_write(client, I2C_MSP3400C_DFP, i, msp->dfp_regs[i]);
+ }
+}
+
+/* if the dfp_regs is set, set what's in there. Otherwise, set the default value */
+static int msp3400c_write_dfp_with_default(struct i2c_client *client,
+ int addr, int default_value)
+{
+ struct msp3400c *msp = i2c_get_clientdata(client);
+ int value = default_value;
+ if (addr < DFP_COUNT && -1 != msp->dfp_regs[addr])
+ value = msp->dfp_regs[addr];
+ return msp3400c_write(client, I2C_MSP3400C_DFP, addr, value);
+}
+
/* ----------------------------------------------------------------------- */
struct REGISTER_DUMP {
@@ -635,8 +744,15 @@ struct REGISTER_DUMP {
char *name;
};
-static int
-autodetect_stereo(struct i2c_client *client)
+struct REGISTER_DUMP d1[] = {
+ {0x007e, "autodetect"},
+ {0x0023, "C_AD_BITS "},
+ {0x0038, "ADD_BITS "},
+ {0x003e, "CIB_BITS "},
+ {0x0057, "ERROR_RATE"},
+};
+
+static int autodetect_stereo(struct i2c_client *client)
{
struct msp3400c *msp = i2c_get_clientdata(client);
int val;
@@ -649,8 +765,7 @@ autodetect_stereo(struct i2c_client *client)
val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18);
if (val > 32767)
val -= 65536;
- dprintk(KERN_DEBUG
- "msp34xx: stereo detect register: %d\n",val);
+ msp3400_dbg("stereo detect register: %d\n",val);
if (val > 4096) {
rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
} else if (val < -4096) {
@@ -664,8 +779,7 @@ autodetect_stereo(struct i2c_client *client)
case MSP_MODE_FM_NICAM2:
case MSP_MODE_AM_NICAM:
val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23);
- dprintk(KERN_DEBUG
- "msp34xx: nicam sync=%d, mode=%d\n",
+ msp3400_dbg("nicam sync=%d, mode=%d\n",
val & 1, (val & 0x1e) >> 1);
if (val & 1) {
@@ -698,8 +812,7 @@ autodetect_stereo(struct i2c_client *client)
break;
case MSP_MODE_BTSC:
val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200);
- dprintk(KERN_DEBUG
- "msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
+ msp3400_dbg("status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
val,
(val & 0x0002) ? "no" : "yes",
(val & 0x0004) ? "no" : "yes",
@@ -713,13 +826,13 @@ autodetect_stereo(struct i2c_client *client)
}
if (rxsubchans != msp->rxsubchans) {
update = 1;
- dprintk(KERN_DEBUG "msp34xx: watch: rxsubchans %d => %d\n",
+ msp3400_dbg("watch: rxsubchans %d => %d\n",
msp->rxsubchans,rxsubchans);
msp->rxsubchans = rxsubchans;
}
if (newnicam != msp->nicam_on) {
update = 1;
- dprintk(KERN_DEBUG "msp34xx: watch: nicam %d => %d\n",
+ msp3400_dbg("watch: nicam %d => %d\n",
msp->nicam_on,newnicam);
msp->nicam_on = newnicam;
}
@@ -756,8 +869,15 @@ static void watch_stereo(struct i2c_client *client)
{
struct msp3400c *msp = i2c_get_clientdata(client);
- if (autodetect_stereo(client))
- msp3400c_set_audmode(client,best_audio_mode(msp->rxsubchans));
+ if (autodetect_stereo(client)) {
+ if (msp->stereo & V4L2_TUNER_MODE_STEREO)
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO);
+ else if (msp->stereo & VIDEO_SOUND_LANG1)
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1);
+ else
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
+ }
+
if (once)
msp->watch_stereo = 0;
}
@@ -769,14 +889,14 @@ static int msp3400c_thread(void *data)
struct CARRIER_DETECT *cd;
int count, max1,max2,val1,val2, val,this;
- printk("msp3400: kthread started\n");
+ msp3400_info("msp3400 daemon started\n");
for (;;) {
- d2printk("msp3400: thread: sleep\n");
+ msp3400_dbg_mediumvol("msp3400 thread: sleep\n");
msp34xx_sleep(msp,-1);
- d2printk("msp3400: thread: wakeup\n");
+ msp3400_dbg_mediumvol("msp3400 thread: wakeup\n");
restart:
- dprintk("msp3410: thread: restart scan\n");
+ msp3400_dbg("thread: restart scan\n");
msp->restart = 0;
if (kthread_should_stop())
break;
@@ -784,9 +904,8 @@ static int msp3400c_thread(void *data)
if (VIDEO_MODE_RADIO == msp->norm ||
MSP_MODE_EXTERN == msp->mode) {
/* no carrier scan, just unmute */
- printk("msp3400: thread: no carrier scan\n");
- msp3400c_setvolume(client, msp->muted,
- msp->volume, msp->balance);
+ msp3400_info("thread: no carrier scan\n");
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
continue;
}
@@ -802,13 +921,14 @@ static int msp3400c_thread(void *data)
goto restart;
/* carrier detect pass #1 -- main carrier */
- cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main);
+ cd = carrier_detect_main;
+ count = CARRIER_COUNT(carrier_detect_main);
if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
/* autodetect doesn't work well with AM ... */
max1 = 3;
count = 0;
- dprintk("msp3400: AM sound override\n");
+ msp3400_dbg("AM sound override\n");
}
for (this = 0; this < count; this++) {
@@ -820,7 +940,7 @@ static int msp3400c_thread(void *data)
val -= 65536;
if (val1 < val)
val1 = val, max1 = this;
- dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name);
+ msp3400_dbg("carrier1 val: %5d / %s\n", val,cd[this].name);
}
/* carrier detect pass #2 -- second (stereo) carrier */
@@ -836,13 +956,16 @@ static int msp3400c_thread(void *data)
case 0: /* 4.5 */
case 2: /* 6.0 */
default:
- cd = NULL; count = 0;
+ cd = NULL;
+ count = 0;
break;
}
if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
/* autodetect doesn't work well with AM ... */
- cd = NULL; count = 0; max2 = 0;
+ cd = NULL;
+ count = 0;
+ max2 = 0;
}
for (this = 0; this < count; this++) {
msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
@@ -853,7 +976,7 @@ static int msp3400c_thread(void *data)
val -= 65536;
if (val2 < val)
val2 = val, max2 = this;
- dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name);
+ msp3400_dbg("carrier2 val: %5d / %s\n", val,cd[this].name);
}
/* programm the msp3400 according to the results */
@@ -865,7 +988,7 @@ static int msp3400c_thread(void *data)
msp->second = carrier_detect_55[max2].cdo;
msp3400c_setmode(client, MSP_MODE_FM_TERRA);
msp->nicam_on = 0;
- msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO);
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
msp->watch_stereo = 1;
} else if (max2 == 1 && HAVE_NICAM(msp)) {
/* B/G NICAM */
@@ -892,7 +1015,7 @@ static int msp3400c_thread(void *data)
msp->second = carrier_detect_65[max2].cdo;
msp3400c_setmode(client, MSP_MODE_FM_TERRA);
msp->nicam_on = 0;
- msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO);
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
msp->watch_stereo = 1;
} else if (max2 == 0 &&
msp->norm == VIDEO_MODE_SECAM) {
@@ -900,7 +1023,7 @@ static int msp3400c_thread(void *data)
msp->second = carrier_detect_65[max2].cdo;
msp3400c_setmode(client, MSP_MODE_AM_NICAM);
msp->nicam_on = 0;
- msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO);
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
msp3400c_setcarrier(client, msp->second, msp->main);
/* volume prescale for SCART (AM mono input) */
msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900);
@@ -924,15 +1047,16 @@ static int msp3400c_thread(void *data)
msp->nicam_on = 0;
msp3400c_setcarrier(client, msp->second, msp->main);
msp->rxsubchans = V4L2_TUNER_SUB_MONO;
- msp3400c_set_audmode(client, V4L2_TUNER_MODE_MONO);
+ msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO);
break;
}
/* unmute */
- msp3400c_setvolume(client, msp->muted,
- msp->volume, msp->balance);
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
+ msp3400c_restore_dfp(client);
+
if (debug)
- msp3400c_print_mode(msp);
+ msp3400c_print_mode(client);
/* monitor tv audio mode */
while (msp->watch_stereo) {
@@ -941,7 +1065,7 @@ static int msp3400c_thread(void *data)
watch_stereo(client);
}
}
- dprintk(KERN_DEBUG "msp3400: thread: exit\n");
+ msp3400_dbg("thread: exit\n");
return 0;
}
@@ -985,10 +1109,12 @@ static inline const char *msp34xx_standard_mode_name(int mode)
return "unknown";
}
-static int msp34xx_modus(int norm)
+static int msp34xx_modus(struct i2c_client *client, int norm)
{
switch (norm) {
case VIDEO_MODE_PAL:
+ msp3400_dbg("video mode selected to PAL\n");
+
#if 1
/* experimental: not sure this works with all chip versions */
return 0x7003;
@@ -997,12 +1123,16 @@ static int msp34xx_modus(int norm)
return 0x1003;
#endif
case VIDEO_MODE_NTSC: /* BTSC */
+ msp3400_dbg("video mode selected to NTSC\n");
return 0x2003;
case VIDEO_MODE_SECAM:
+ msp3400_dbg("video mode selected to SECAM\n");
return 0x0003;
case VIDEO_MODE_RADIO:
+ msp3400_dbg("video mode selected to Radio\n");
return 0x0003;
case VIDEO_MODE_AUTO:
+ msp3400_dbg("video mode selected to Auto\n");
return 0x2003;
default:
return 0x0003;
@@ -1031,23 +1161,22 @@ static int msp3410d_thread(void *data)
struct msp3400c *msp = i2c_get_clientdata(client);
int mode,val,i,std;
- printk("msp3410: daemon started\n");
+ msp3400_info("msp3410 daemon started\n");
for (;;) {
- d2printk(KERN_DEBUG "msp3410: thread: sleep\n");
+ msp3400_dbg_mediumvol("msp3410 thread: sleep\n");
msp34xx_sleep(msp,-1);
- d2printk(KERN_DEBUG "msp3410: thread: wakeup\n");
+ msp3400_dbg_mediumvol("msp3410 thread: wakeup\n");
restart:
- dprintk("msp3410: thread: restart scan\n");
+ msp3400_dbg("thread: restart scan\n");
msp->restart = 0;
if (kthread_should_stop())
break;
if (msp->mode == MSP_MODE_EXTERN) {
/* no carrier scan needed, just unmute */
- dprintk(KERN_DEBUG "msp3410: thread: no carrier scan\n");
- msp3400c_setvolume(client, msp->muted,
- msp->volume, msp->balance);
+ msp3400_dbg("thread: no carrier scan\n");
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
continue;
}
@@ -1059,14 +1188,14 @@ static int msp3410d_thread(void *data)
goto restart;
/* start autodetect */
- mode = msp34xx_modus(msp->norm);
+ mode = msp34xx_modus(client, msp->norm);
std = msp34xx_standard(msp->norm);
msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode);
msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std);
msp->watch_stereo = 0;
if (debug)
- printk(KERN_DEBUG "msp3410: setting mode: %s (0x%04x)\n",
+ msp3400_dbg("setting mode: %s (0x%04x)\n",
msp34xx_standard_mode_name(std) ,std);
if (std != 1) {
@@ -1082,13 +1211,13 @@ static int msp3410d_thread(void *data)
val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);
if (val < 0x07ff)
break;
- dprintk(KERN_DEBUG "msp3410: detection still in progress\n");
+ msp3400_dbg("detection still in progress\n");
}
}
for (i = 0; modelist[i].name != NULL; i++)
if (modelist[i].retval == val)
break;
- dprintk(KERN_DEBUG "msp3410: current mode: %s (0x%04x)\n",
+ msp3400_dbg("current mode: %s (0x%04x)\n",
modelist[i].name ? modelist[i].name : "unknown",
val);
msp->main = modelist[i].main;
@@ -1096,7 +1225,7 @@ static int msp3410d_thread(void *data)
if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) {
/* autodetection has failed, let backup */
- dprintk(KERN_DEBUG "msp3410: autodetection failed,"
+ msp3400_dbg("autodetection failed,"
" switching to backup mode: %s (0x%04x)\n",
modelist[8].name ? modelist[8].name : "unknown",val);
val = 0x0009;
@@ -1120,13 +1249,13 @@ static int msp3410d_thread(void *data)
msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
msp->nicam_on = 1;
msp->watch_stereo = 1;
- msp3400c_set_audmode(client,V4L2_TUNER_MODE_STEREO);
+ msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
break;
case 0x0009:
msp->mode = MSP_MODE_AM_NICAM;
msp->rxsubchans = V4L2_TUNER_SUB_MONO;
msp->nicam_on = 1;
- msp3400c_set_audmode(client,V4L2_TUNER_MODE_MONO);
+ msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO);
msp->watch_stereo = 1;
break;
case 0x0020: /* BTSC */
@@ -1135,7 +1264,7 @@ static int msp3410d_thread(void *data)
msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
msp->nicam_on = 0;
msp->watch_stereo = 1;
- msp3400c_set_audmode(client,V4L2_TUNER_MODE_STEREO);
+ msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO);
break;
case 0x0040: /* FM radio */
msp->mode = MSP_MODE_FM_RADIO;
@@ -1169,9 +1298,10 @@ static int msp3410d_thread(void *data)
/* unmute, restore misc registers */
msp3400c_setbass(client, msp->bass);
msp3400c_settreble(client, msp->treble);
- msp3400c_setvolume(client, msp->muted,
- msp->volume, msp->balance);
- msp3400c_write(client, I2C_MSP3400C_DFP, 0x0013, msp->acb);
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
+ msp3400c_write(client, I2C_MSP3400C_DFP, 0x13, msp->acb);
+ msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
+ msp3400c_restore_dfp(client);
/* monitor tv audio mode */
while (msp->watch_stereo) {
@@ -1180,7 +1310,7 @@ static int msp3410d_thread(void *data)
watch_stereo(client);
}
}
- dprintk(KERN_DEBUG "msp3410: thread: exit\n");
+ msp3400_dbg("thread: exit\n");
return 0;
}
@@ -1195,7 +1325,7 @@ static void msp34xxg_set_source(struct i2c_client *client, int source);
/* (re-)initialize the msp34xxg, according to the current norm in msp->norm
* return 0 if it worked, -1 if it failed
*/
-static int msp34xxg_init(struct i2c_client *client)
+static int msp34xxg_reset(struct i2c_client *client)
{
struct msp3400c *msp = i2c_get_clientdata(client);
int modus,std;
@@ -1210,8 +1340,10 @@ static int msp34xxg_init(struct i2c_client *client)
0x0f20 /* mute DSP input, mute SCART 1 */))
return -1;
+ msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
+
/* step-by-step initialisation, as described in the manual */
- modus = msp34xx_modus(msp->norm);
+ modus = msp34xx_modus(client, msp->norm);
std = msp34xx_standard(msp->norm);
modus &= ~0x03; /* STATUS_CHANGE=0 */
modus |= 0x01; /* AUTOMATIC_SOUND_DETECTION=1 */
@@ -1222,7 +1354,7 @@ static int msp34xxg_init(struct i2c_client *client)
return -1;
if (msp3400c_write(client,
I2C_MSP3400C_DEM,
- 0x20/*stanard*/,
+ 0x20/*standard*/,
std))
return -1;
@@ -1230,21 +1362,18 @@ static int msp34xxg_init(struct i2c_client *client)
standard/audio autodetection right now */
msp34xxg_set_source(client, msp->source);
- if (msp3400c_write(client, I2C_MSP3400C_DFP,
- 0x0e, /* AM/FM Prescale */
- 0x3000 /* default: [15:8] 75khz deviation */))
+ if (msp3400c_write_dfp_with_default(client, 0x0e, /* AM/FM Prescale */
+ 0x3000
+ /* default: [15:8] 75khz deviation */
+ ))
return -1;
- if (msp3400c_write(client, I2C_MSP3400C_DFP,
- 0x10, /* NICAM Prescale */
- 0x5a00 /* default: 9db gain (as recommended) */))
+ if (msp3400c_write_dfp_with_default(client, 0x10, /* NICAM Prescale */
+ 0x5a00
+ /* default: 9db gain (as recommended) */
+ ))
return -1;
- if (msp3400c_write(client,
- I2C_MSP3400C_DEM,
- 0x20, /* STANDARD SELECT */
- standard /* default: 0x01 for automatic standard select*/))
- return -1;
return 0;
}
@@ -1254,27 +1383,27 @@ static int msp34xxg_thread(void *data)
struct msp3400c *msp = i2c_get_clientdata(client);
int val, std, i;
- printk("msp34xxg: daemon started\n");
+ msp3400_info("msp34xxg daemon started\n");
msp->source = 1; /* default */
for (;;) {
- d2printk(KERN_DEBUG "msp34xxg: thread: sleep\n");
+ msp3400_dbg_mediumvol("msp34xxg thread: sleep\n");
msp34xx_sleep(msp,-1);
- d2printk(KERN_DEBUG "msp34xxg: thread: wakeup\n");
+ msp3400_dbg_mediumvol("msp34xxg thread: wakeup\n");
restart:
- dprintk("msp34xxg: thread: restart scan\n");
+ msp3400_dbg("thread: restart scan\n");
msp->restart = 0;
if (kthread_should_stop())
break;
/* setup the chip*/
- msp34xxg_init(client);
+ msp34xxg_reset(client);
std = standard;
if (std != 0x01)
goto unmute;
/* watch autodetect */
- dprintk("msp34xxg: triggered autodetect, waiting for result\n");
+ msp3400_dbg("triggered autodetect, waiting for result\n");
for (i = 0; i < 10; i++) {
if (msp34xx_sleep(msp,100))
goto restart;
@@ -1285,23 +1414,23 @@ static int msp34xxg_thread(void *data)
std = val;
break;
}
- dprintk("msp34xxg: detection still in progress\n");
+ msp3400_dbg("detection still in progress\n");
}
if (0x01 == std) {
- dprintk("msp34xxg: detection still in progress after 10 tries. giving up.\n");
+ msp3400_dbg("detection still in progress after 10 tries. giving up.\n");
continue;
}
unmute:
- dprintk("msp34xxg: current mode: %s (0x%04x)\n",
+ msp3400_dbg("current mode: %s (0x%04x)\n",
msp34xx_standard_mode_name(std), std);
/* unmute: dispatch sound to scart output, set scart volume */
- dprintk("msp34xxg: unmute\n");
+ msp3400_dbg("unmute\n");
msp3400c_setbass(client, msp->bass);
msp3400c_settreble(client, msp->treble);
- msp3400c_setvolume(client, msp->muted, msp->volume, msp->balance);
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
/* restore ACB */
if (msp3400c_write(client,
@@ -1309,8 +1438,10 @@ static int msp34xxg_thread(void *data)
0x13, /* ACB */
msp->acb))
return -1;
+
+ msp3400c_write(client,I2C_MSP3400C_DEM, 0x40, msp->i2s_mode);
}
- dprintk(KERN_DEBUG "msp34xxg: thread: exit\n");
+ msp3400_dbg("thread: exit\n");
return 0;
}
@@ -1329,7 +1460,7 @@ static void msp34xxg_set_source(struct i2c_client *client, int source)
* for MONO (source==0) downmixing set bit[7:0] to 0x30
*/
int value = (source&0x07)<<8|(source==0 ? 0x30:0x20);
- dprintk("msp34xxg: set source to %d (0x%x)\n", source, value);
+ msp3400_dbg("set source to %d (0x%x)\n", source, value);
msp3400c_write(client,
I2C_MSP3400C_DFP,
0x08, /* Loudspeaker Output */
@@ -1380,7 +1511,7 @@ static void msp34xxg_detect_stereo(struct i2c_client *client)
* this is a problem, I'll handle SAP just like lang1/lang2.
*/
}
- dprintk("msp34xxg: status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
+ msp3400_dbg("status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
status, is_stereo, is_bilingual, msp->rxsubchans);
}
@@ -1427,7 +1558,7 @@ static void msp_wake_thread(struct i2c_client *client);
static struct i2c_driver driver = {
.owner = THIS_MODULE,
- .name = "i2c msp3400 driver",
+ .name = "msp3400",
.id = I2C_DRIVERID_MSP3400,
.flags = I2C_DF_NOTIFY,
.attach_adapter = msp_probe,
@@ -1449,57 +1580,64 @@ static struct i2c_client client_template =
static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct msp3400c *msp;
- struct i2c_client *c;
+ struct i2c_client *client = &client_template;
int (*thread_func)(void *data) = NULL;
+ int i;
- client_template.adapter = adap;
- client_template.addr = addr;
+ client_template.adapter = adap;
+ client_template.addr = addr;
- if (-1 == msp3400c_reset(&client_template)) {
- dprintk("msp34xx: no chip found\n");
- return -1;
- }
+ if (-1 == msp3400c_reset(&client_template)) {
+ msp3400_dbg("no chip found\n");
+ return -1;
+ }
- if (NULL == (c = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
- return -ENOMEM;
- memcpy(c,&client_template,sizeof(struct i2c_client));
+ if (NULL == (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
+ return -ENOMEM;
+ memcpy(client,&client_template,sizeof(struct i2c_client));
if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) {
- kfree(c);
+ kfree(client);
return -ENOMEM;
}
memset(msp,0,sizeof(struct msp3400c));
- msp->volume = 58880; /* 0db gain */
- msp->balance = 32768;
- msp->bass = 32768;
- msp->treble = 32768;
- msp->input = -1;
- msp->muted = 1;
-
- i2c_set_clientdata(c, msp);
+ msp->norm = VIDEO_MODE_NTSC;
+ msp->left = 58880; /* 0db gain */
+ msp->right = 58880; /* 0db gain */
+ msp->bass = 32768;
+ msp->treble = 32768;
+ msp->input = -1;
+ msp->muted = 0;
+ msp->i2s_mode = 0;
+ for (i = 0; i < DFP_COUNT; i++)
+ msp->dfp_regs[i] = -1;
+
+ i2c_set_clientdata(client, msp);
init_waitqueue_head(&msp->wq);
- if (-1 == msp3400c_reset(c)) {
+ if (-1 == msp3400c_reset(client)) {
kfree(msp);
- kfree(c);
- dprintk("msp34xx: no chip found\n");
+ kfree(client);
+ msp3400_dbg("no chip found\n");
return -1;
}
- msp->rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e);
+ msp->rev1 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1e);
if (-1 != msp->rev1)
- msp->rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f);
+ msp->rev2 = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1f);
if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) {
kfree(msp);
- kfree(c);
- dprintk("msp34xx: error while reading chip version\n");
+ kfree(client);
+ msp3400_dbg("error while reading chip version\n");
return -1;
}
+ msp3400_dbg("rev1=0x%04x, rev2=0x%04x\n", msp->rev1, msp->rev2);
- msp3400c_setvolume(c, msp->muted, msp->volume, msp->balance);
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
- snprintf(c->name, sizeof(c->name), "MSP34%02d%c-%c%d",
- (msp->rev2>>8)&0xff, (msp->rev1&0xff)+'@',
+ snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d",
+ ((msp->rev1>>4)&0x0f) + '3',
+ (msp->rev2>>8)&0xff, (msp->rev1&0x0f)+'@',
((msp->rev1>>8)&0xff)+'@', msp->rev2&0x1f);
msp->opmode = opmode;
@@ -1513,7 +1651,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
}
/* hello world :-) */
- printk(KERN_INFO "msp34xx: init: chip=%s", c->name);
+ msp3400_info("chip=%s", client->name);
if (HAVE_NICAM(msp))
printk(" +nicam");
if (HAVE_SIMPLE(msp))
@@ -1542,29 +1680,49 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
/* startup control thread if needed */
if (thread_func) {
- msp->kthread = kthread_run(thread_func, c, "msp34xx");
+ msp->kthread = kthread_run(thread_func, client, "msp34xx");
+
if (NULL == msp->kthread)
- printk(KERN_WARNING "msp34xx: kernel_thread() failed\n");
- msp_wake_thread(c);
+ msp3400_warn("kernel_thread() failed\n");
+ msp_wake_thread(client);
}
/* done */
- i2c_attach_client(c);
+ i2c_attach_client(client);
+
+ /* update our own array */
+ for (i = 0; i < MSP3400_MAX; i++) {
+ if (NULL == msps[i]) {
+ msps[i] = client;
+ break;
+ }
+ }
+
return 0;
}
static int msp_detach(struct i2c_client *client)
{
struct msp3400c *msp = i2c_get_clientdata(client);
+ int i;
/* shutdown control thread */
- if (msp->kthread >= 0) {
+ if (msp->kthread) {
msp->restart = 1;
kthread_stop(msp->kthread);
}
- msp3400c_reset(client);
+ msp3400c_reset(client);
+
+ /* update our own array */
+ for (i = 0; i < MSP3400_MAX; i++) {
+ if (client == msps[i]) {
+ msps[i] = NULL;
+ break;
+ }
+ }
i2c_detach_client(client);
+
kfree(msp);
kfree(client);
return 0;
@@ -1640,7 +1798,7 @@ static void msp_any_set_audmode(struct i2c_client *client, int audmode)
case OPMODE_MANUAL:
case OPMODE_SIMPLE:
msp->watch_stereo = 0;
- msp3400c_set_audmode(client, audmode);
+ msp3400c_setstereo(client, audmode);
break;
case OPMODE_SIMPLER:
msp34xxg_set_audmode(client, audmode);
@@ -1648,16 +1806,18 @@ static void msp_any_set_audmode(struct i2c_client *client, int audmode)
}
}
+
static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct msp3400c *msp = i2c_get_clientdata(client);
- __u16 *sarg = arg;
+ __u16 *sarg = arg;
int scart = 0;
switch (cmd) {
case AUDC_SET_INPUT:
- dprintk(KERN_DEBUG "msp34xx: AUDC_SET_INPUT(%d)\n",*sarg);
+ msp3400_dbg("AUDC_SET_INPUT(%d)\n",*sarg);
+
if (*sarg == msp->input)
break;
msp->input = *sarg;
@@ -1691,15 +1851,15 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
msp3400c_set_scart(client,scart,0);
msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
if (msp->opmode != OPMODE_SIMPLER)
- msp3400c_set_audmode(client, msp->audmode);
+ msp3400c_setstereo(client, msp->audmode);
}
msp_wake_thread(client);
break;
case AUDC_SET_RADIO:
- dprintk(KERN_DEBUG "msp34xx: AUDC_SET_RADIO\n");
+ msp3400_dbg("AUDC_SET_RADIO\n");
msp->norm = VIDEO_MODE_RADIO;
- dprintk(KERN_DEBUG "msp34xx: switching to radio mode\n");
+ msp3400_dbg("switching to radio mode\n");
msp->watch_stereo = 0;
switch (msp->opmode) {
case OPMODE_MANUAL:
@@ -1707,8 +1867,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
msp3400c_setmode(client,MSP_MODE_FM_RADIO);
msp3400c_setcarrier(client, MSP_CARRIER(10.7),
MSP_CARRIER(10.7));
- msp3400c_setvolume(client, msp->muted,
- msp->volume, msp->balance);
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
break;
case OPMODE_SIMPLE:
case OPMODE_SIMPLER:
@@ -1717,6 +1876,30 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
}
break;
+ /* work-in-progress: hook to control the DFP registers */
+ case MSP_SET_DFPREG:
+ {
+ struct msp_dfpreg *r = arg;
+ int i;
+
+ if (r->reg < 0 || r->reg >= DFP_COUNT)
+ return -EINVAL;
+ for (i = 0; i < sizeof(bl_dfp) / sizeof(int); i++)
+ if (r->reg == bl_dfp[i])
+ return -EINVAL;
+ msp->dfp_regs[r->reg] = r->value;
+ msp3400c_write(client, I2C_MSP3400C_DFP, r->reg, r->value);
+ return 0;
+ }
+ case MSP_GET_DFPREG:
+ {
+ struct msp_dfpreg *r = arg;
+
+ if (r->reg < 0 || r->reg >= DFP_COUNT)
+ return -EINVAL;
+ r->value = msp3400c_read(client, I2C_MSP3400C_DFP, r->reg);
+ return 0;
+ }
/* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a
@@ -1725,7 +1908,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct video_audio *va = arg;
- dprintk(KERN_DEBUG "msp34xx: VIDIOCGAUDIO\n");
+ msp3400_dbg("VIDIOCGAUDIO\n");
va->flags |= VIDEO_AUDIO_VOLUME |
VIDEO_AUDIO_BASS |
VIDEO_AUDIO_TREBLE |
@@ -1733,8 +1916,15 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
if (msp->muted)
va->flags |= VIDEO_AUDIO_MUTE;
- va->volume = msp->volume;
- va->balance = (va->volume) ? msp->balance : 32768;
+ if (msp->muted)
+ va->flags |= VIDEO_AUDIO_MUTE;
+ va->volume = MAX(msp->left, msp->right);
+ va->balance = (32768 * MIN(msp->left, msp->right)) /
+ (va->volume ? va->volume : 1);
+ va->balance = (msp->left < msp->right) ?
+ (65535 - va->balance) : va->balance;
+ if (0 == va->volume)
+ va->balance = 32768;
va->bass = msp->bass;
va->treble = msp->treble;
@@ -1746,27 +1936,43 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct video_audio *va = arg;
- dprintk(KERN_DEBUG "msp34xx: VIDIOCSAUDIO\n");
+ msp3400_dbg("VIDIOCSAUDIO\n");
msp->muted = (va->flags & VIDEO_AUDIO_MUTE);
- msp->volume = va->volume;
- msp->balance = va->balance;
+ msp->left = (MIN(65536 - va->balance, 32768) *
+ va->volume) / 32768;
+ msp->right = (MIN(va->balance, 32768) * va->volume) / 32768;
msp->bass = va->bass;
msp->treble = va->treble;
-
- msp3400c_setvolume(client, msp->muted,
- msp->volume, msp->balance);
- msp3400c_setbass(client,msp->bass);
- msp3400c_settreble(client,msp->treble);
+ msp3400_dbg("VIDIOCSAUDIO setting va->volume to %d\n",
+ va->volume);
+ msp3400_dbg("VIDIOCSAUDIO setting va->balance to %d\n",
+ va->balance);
+ msp3400_dbg("VIDIOCSAUDIO setting va->flags to %d\n",
+ va->flags);
+ msp3400_dbg("VIDIOCSAUDIO setting msp->left to %d\n",
+ msp->left);
+ msp3400_dbg("VIDIOCSAUDIO setting msp->right to %d\n",
+ msp->right);
+ msp3400_dbg("VIDIOCSAUDIO setting msp->bass to %d\n",
+ msp->bass);
+ msp3400_dbg("VIDIOCSAUDIO setting msp->treble to %d\n",
+ msp->treble);
+ msp3400_dbg("VIDIOCSAUDIO setting msp->mode to %d\n",
+ msp->mode);
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
+ msp3400c_setbass(client, msp->bass);
+ msp3400c_settreble(client, msp->treble);
if (va->mode != 0 && msp->norm != VIDEO_MODE_RADIO)
msp_any_set_audmode(client,mode_v4l1_to_v4l2(va->mode));
break;
}
+
case VIDIOCSCHAN:
{
struct video_channel *vc = arg;
- dprintk(KERN_DEBUG "msp34xx: VIDIOCSCHAN (norm=%d)\n",vc->norm);
+ msp3400_dbg("VIDIOCSCHAN (norm=%d)\n",vc->norm);
msp->norm = vc->norm;
msp_wake_thread(client);
break;
@@ -1776,12 +1982,135 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
case VIDIOC_S_FREQUENCY:
{
/* new channel -- kick audio carrier scan */
- dprintk(KERN_DEBUG "msp34xx: VIDIOCSFREQ\n");
+ msp3400_dbg("VIDIOCSFREQ\n");
msp_wake_thread(client);
break;
}
+ /* msp34xx specific */
+ case MSP_SET_MATRIX:
+ {
+ struct msp_matrix *mspm = arg;
+
+ msp3400_dbg("MSP_SET_MATRIX\n");
+ msp3400c_set_scart(client, mspm->input, mspm->output);
+ break;
+ }
+
/* --- v4l2 ioctls --- */
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id *id = arg;
+
+ /*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/
+ if (*id & V4L2_STD_PAL) {
+ msp->norm=VIDEO_MODE_PAL;
+ } else if (*id & V4L2_STD_SECAM) {
+ msp->norm=VIDEO_MODE_SECAM;
+ } else {
+ msp->norm=VIDEO_MODE_NTSC;
+ }
+
+ msp_wake_thread(client);
+ return 0;
+ }
+
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *i = arg;
+
+ if (i->index != 0)
+ return -EINVAL;
+
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ switch (i->index) {
+ case AUDIO_RADIO:
+ strcpy(i->name,"Radio");
+ break;
+ case AUDIO_EXTERN_1:
+ strcpy(i->name,"Extern 1");
+ break;
+ case AUDIO_EXTERN_2:
+ strcpy(i->name,"Extern 2");
+ break;
+ case AUDIO_TUNER:
+ strcpy(i->name,"Television");
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ case VIDIOC_G_AUDIO:
+ {
+ struct v4l2_audio *a = arg;
+
+ memset(a,0,sizeof(*a));
+
+ switch (a->index) {
+ case AUDIO_RADIO:
+ strcpy(a->name,"Radio");
+ break;
+ case AUDIO_EXTERN_1:
+ strcpy(a->name,"Extern 1");
+ break;
+ case AUDIO_EXTERN_2:
+ strcpy(a->name,"Extern 2");
+ break;
+ case AUDIO_TUNER:
+ strcpy(a->name,"Television");
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ msp_any_detect_stereo(client);
+ if (msp->audmode == V4L2_TUNER_MODE_STEREO) {
+ a->capability=V4L2_AUDCAP_STEREO;
+ }
+
+ break;
+ }
+ case VIDIOC_S_AUDIO:
+ {
+ struct v4l2_audio *sarg = arg;
+
+ switch (sarg->index) {
+ case AUDIO_RADIO:
+ /* Hauppauge uses IN2 for the radio */
+ msp->mode = MSP_MODE_FM_RADIO;
+ scart = SCART_IN2;
+ break;
+ case AUDIO_EXTERN_1:
+ /* IN1 is often used for external input ... */
+ msp->mode = MSP_MODE_EXTERN;
+ scart = SCART_IN1;
+ break;
+ case AUDIO_EXTERN_2:
+ /* ... sometimes it is IN2 through ;) */
+ msp->mode = MSP_MODE_EXTERN;
+ scart = SCART_IN2;
+ break;
+ case AUDIO_TUNER:
+ msp->mode = -1;
+ break;
+ }
+ if (scart) {
+ msp->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ msp->audmode = V4L2_TUNER_MODE_STEREO;
+ msp3400c_set_scart(client,scart,0);
+ msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
+ }
+ if (sarg->capability==V4L2_AUDCAP_STEREO) {
+ msp->audmode = V4L2_TUNER_MODE_STEREO;
+ } else {
+ msp->audmode &= ~V4L2_TUNER_MODE_STEREO;
+ }
+ msp_any_set_audmode(client, msp->audmode);
+ msp_wake_thread(client);
+ break;
+ }
case VIDIOC_G_TUNER:
{
struct v4l2_tuner *vt = arg;
@@ -1804,13 +2133,46 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
}
- /* msp34xx specific */
- case MSP_SET_MATRIX:
+ case VIDIOC_G_AUDOUT:
{
- struct msp_matrix *mspm = arg;
+ struct v4l2_audioout *a=(struct v4l2_audioout *)arg;
+ int idx=a->index;
+
+ memset(a,0,sizeof(*a));
+
+ switch (idx) {
+ case 0:
+ strcpy(a->name,"Scart1 Out");
+ break;
+ case 1:
+ strcpy(a->name,"Scart2 Out");
+ break;
+ case 2:
+ strcpy(a->name,"I2S Out");
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ }
+ case VIDIOC_S_AUDOUT:
+ {
+ struct v4l2_audioout *a=(struct v4l2_audioout *)arg;
+
+ if (a->index<0||a->index>2)
+ return -EINVAL;
+
+ if (a->index==2) {
+ if (a->mode == V4L2_AUDMODE_32BITS)
+ msp->i2s_mode=1;
+ else
+ msp->i2s_mode=0;
+ }
+ msp3400_dbg("Setting audio out on msp34xx to input %i, mode %i\n",
+ a->index,msp->i2s_mode);
+ msp3400c_set_scart(client,msp->in_scart,a->index+1);
- dprintk(KERN_DEBUG "msp34xx: MSP_SET_MATRIX\n");
- msp3400c_set_scart(client, mspm->input, mspm->output);
break;
}
@@ -1823,19 +2185,19 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
static int msp_suspend(struct device * dev, pm_message_t state)
{
- struct i2c_client *c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
- dprintk("msp34xx: suspend\n");
- msp3400c_reset(c);
+ msp3400_dbg("msp34xx: suspend\n");
+ msp3400c_reset(client);
return 0;
}
static int msp_resume(struct device * dev)
{
- struct i2c_client *c = container_of(dev, struct i2c_client, dev);
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
- dprintk("msp34xx: resume\n");
- msp_wake_thread(c);
+ msp3400_dbg("msp34xx: resume\n");
+ msp_wake_thread(client);
return 0;
}
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
index 972aa5e0aee..2180018f06d 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/video/mt20xx.c
@@ -76,17 +76,17 @@ static int mt2032_compute_freq(struct i2c_client *c,
unsigned int xogc) //all in Hz
{
struct tuner *t = i2c_get_clientdata(c);
- unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
+ unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq;
- fref= 5250 *1000; //5.25MHz
+ fref= 5250 *1000; //5.25MHz
desired_lo1=rfin+if1;
lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000);
- lo1n=lo1/8;
- lo1a=lo1-(lo1n*8);
+ lo1n=lo1/8;
+ lo1a=lo1-(lo1n*8);
- s=rfin/1000/1000+1090;
+ s=rfin/1000/1000+1090;
if(optimize_vco) {
if(s>1890) sel=0;
@@ -96,34 +96,34 @@ static int mt2032_compute_freq(struct i2c_client *c,
else sel=4; // >1090
}
else {
- if(s>1790) sel=0; // <1958
- else if(s>1617) sel=1;
- else if(s>1449) sel=2;
- else if(s>1291) sel=3;
- else sel=4; // >1090
+ if(s>1790) sel=0; // <1958
+ else if(s>1617) sel=1;
+ else if(s>1449) sel=2;
+ else if(s>1291) sel=3;
+ else sel=4; // >1090
}
*ret_sel=sel;
- lo1freq=(lo1a+8*lo1n)*fref;
+ lo1freq=(lo1a+8*lo1n)*fref;
tuner_dbg("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n",
rfin,lo1,lo1n,lo1a,sel,lo1freq);
- desired_lo2=lo1freq-rfin-if2;
- lo2=(desired_lo2)/fref;
- lo2n=lo2/8;
- lo2a=lo2-(lo2n*8);
- lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith
- lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000;
+ desired_lo2=lo1freq-rfin-if2;
+ lo2=(desired_lo2)/fref;
+ lo2n=lo2/8;
+ lo2a=lo2-(lo2n*8);
+ lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith
+ lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000;
tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n",
rfin,lo2,lo2n,lo2a,lo2num,lo2freq);
- if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) {
+ if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) {
tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n",
lo1a, lo1n, lo2a,lo2n);
- return(-1);
- }
+ return(-1);
+ }
mt2032_spurcheck(c, lo1freq, desired_lo2, spectrum_from, spectrum_to);
// should recalculate lo1 (one step up/down)
@@ -135,10 +135,10 @@ static int mt2032_compute_freq(struct i2c_client *c,
buf[3]=0x0f; //reserved
buf[4]=0x1f;
buf[5]=(lo2n-1) | (lo2a<<5);
- if(rfin >400*1000*1000)
- buf[6]=0xe4;
- else
- buf[6]=0xf4; // set PKEN per rev 1.2
+ if(rfin >400*1000*1000)
+ buf[6]=0xe4;
+ else
+ buf[6]=0xf4; // set PKEN per rev 1.2
buf[7]=8+xogc;
buf[8]=0xc3; //reserved
buf[9]=0x4e; //reserved
@@ -168,7 +168,7 @@ static int mt2032_check_lo_lock(struct i2c_client *c)
tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]);
udelay(1000);
}
- return lock;
+ return lock;
}
static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock)
@@ -202,7 +202,7 @@ static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock)
buf[0]=0x0f;
buf[1]=sel;
- i2c_master_send(c,buf,2);
+ i2c_master_send(c,buf,2);
lock=mt2032_check_lo_lock(c);
return lock;
}
@@ -219,23 +219,23 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",
rfin,if1,if2,from,to);
- buf[0]=0;
- ret=i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,21);
+ buf[0]=0;
+ ret=i2c_master_send(c,buf,1);
+ i2c_master_recv(c,buf,21);
buf[0]=0;
ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,t->xogc);
if (ret<0)
return;
- // send only the relevant registers per Rev. 1.2
- buf[0]=0;
- ret=i2c_master_send(c,buf,4);
- buf[5]=5;
- ret=i2c_master_send(c,buf+5,4);
- buf[11]=11;
- ret=i2c_master_send(c,buf+11,3);
- if(ret!=3)
+ // send only the relevant registers per Rev. 1.2
+ buf[0]=0;
+ ret=i2c_master_send(c,buf,4);
+ buf[5]=5;
+ ret=i2c_master_send(c,buf+5,4);
+ buf[11]=11;
+ ret=i2c_master_send(c,buf+11,3);
+ if(ret!=3)
tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret);
// wait for PLLs to lock (per manual), retry LINT if not.
@@ -253,7 +253,7 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
mdelay(10);
buf[1]=8+t->xogc;
i2c_master_send(c,buf,2);
- }
+ }
if (lock!=6)
tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n");
@@ -284,7 +284,7 @@ static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq)
if2 = 38900*1000;
}
- mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
+ mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
1090*1000*1000, if2, from, to);
}
@@ -294,7 +294,7 @@ static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
int if2 = t->radio_if2;
// per Manual for FM tuning: first if center freq. 1085 MHz
- mt2032_set_if_freq(c, freq * 1000 / 16,
+ mt2032_set_if_freq(c, freq * 1000 / 16,
1085*1000*1000,if2,if2,if2);
}
@@ -302,57 +302,57 @@ static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
static int mt2032_init(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
- unsigned char buf[21];
- int ret,xogc,xok=0;
+ unsigned char buf[21];
+ int ret,xogc,xok=0;
// Initialize Registers per spec.
- buf[1]=2; // Index to register 2
- buf[2]=0xff;
- buf[3]=0x0f;
- buf[4]=0x1f;
- ret=i2c_master_send(c,buf+1,4);
-
- buf[5]=6; // Index register 6
- buf[6]=0xe4;
- buf[7]=0x8f;
- buf[8]=0xc3;
- buf[9]=0x4e;
- buf[10]=0xec;
- ret=i2c_master_send(c,buf+5,6);
-
- buf[12]=13; // Index register 13
- buf[13]=0x32;
- ret=i2c_master_send(c,buf+12,2);
-
- // Adjust XOGC (register 7), wait for XOK
- xogc=7;
- do {
+ buf[1]=2; // Index to register 2
+ buf[2]=0xff;
+ buf[3]=0x0f;
+ buf[4]=0x1f;
+ ret=i2c_master_send(c,buf+1,4);
+
+ buf[5]=6; // Index register 6
+ buf[6]=0xe4;
+ buf[7]=0x8f;
+ buf[8]=0xc3;
+ buf[9]=0x4e;
+ buf[10]=0xec;
+ ret=i2c_master_send(c,buf+5,6);
+
+ buf[12]=13; // Index register 13
+ buf[13]=0x32;
+ ret=i2c_master_send(c,buf+12,2);
+
+ // Adjust XOGC (register 7), wait for XOK
+ xogc=7;
+ do {
tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
- mdelay(10);
- buf[0]=0x0e;
- i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,1);
- xok=buf[0]&0x01;
- tuner_dbg("mt2032: xok = 0x%02x\n",xok);
- if (xok == 1) break;
-
- xogc--;
- tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
- if (xogc == 3) {
- xogc=4; // min. 4 per spec
- break;
- }
- buf[0]=0x07;
- buf[1]=0x88 + xogc;
- ret=i2c_master_send(c,buf,2);
- if (ret!=2)
+ mdelay(10);
+ buf[0]=0x0e;
+ i2c_master_send(c,buf,1);
+ i2c_master_recv(c,buf,1);
+ xok=buf[0]&0x01;
+ tuner_dbg("mt2032: xok = 0x%02x\n",xok);
+ if (xok == 1) break;
+
+ xogc--;
+ tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
+ if (xogc == 3) {
+ xogc=4; // min. 4 per spec
+ break;
+ }
+ buf[0]=0x07;
+ buf[1]=0x88 + xogc;
+ ret=i2c_master_send(c,buf,2);
+ if (ret!=2)
tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
- } while (xok != 1 );
+ } while (xok != 1 );
t->xogc=xogc;
t->tv_freq = mt2032_set_tv_freq;
t->radio_freq = mt2032_set_radio_freq;
- return(1);
+ return(1);
}
static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna)
@@ -426,7 +426,7 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned
}
ret=i2c_master_send(c,buf,6);
- if (ret!=6)
+ if (ret!=6)
tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret);
}
@@ -437,11 +437,11 @@ static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq)
if (t->std & V4L2_STD_525_60) {
// NTSC
- if2 = 45750*1000;
- } else {
- // PAL
- if2 = 38900*1000;
- }
+ if2 = 45750*1000;
+ } else {
+ // PAL
+ if2 = 38900*1000;
+ }
if (V4L2_TUNER_DIGITAL_TV == t->mode) {
// DVB (pinnacle 300i)
if2 = 36150*1000;
@@ -455,7 +455,7 @@ static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq)
struct tuner *t = i2c_get_clientdata(c);
int if2 = t->radio_if2;
- mt2050_set_if_freq(c, freq*62500, if2);
+ mt2050_set_if_freq(c, freq * 1000 / 16, if2);
mt2050_set_antenna(c, radio_antenna);
}
@@ -487,7 +487,7 @@ int microtune_init(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
char *name;
- unsigned char buf[21];
+ unsigned char buf[21];
int company_code;
memset(buf,0,sizeof(buf));
@@ -496,17 +496,17 @@ int microtune_init(struct i2c_client *c)
t->standby = NULL;
name = "unknown";
- i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,21);
- if (tuner_debug) {
- int i;
+ i2c_master_send(c,buf,1);
+ i2c_master_recv(c,buf,21);
+ if (tuner_debug) {
+ int i;
tuner_dbg("MT20xx hexdump:");
- for(i=0;i<21;i++) {
- printk(" %02x",buf[i]);
- if(((i+1)%8)==0) printk(" ");
- }
- printk("\n");
- }
+ for(i=0;i<21;i++) {
+ printk(" %02x",buf[i]);
+ if(((i+1)%8)==0) printk(" ");
+ }
+ printk("\n");
+ }
company_code = buf[0x11] << 8 | buf[0x12];
tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n",
company_code,buf[0x13],buf[0x14]);
@@ -525,8 +525,8 @@ int microtune_init(struct i2c_client *c)
default:
tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n",
name);
- return 0;
- }
+ return 0;
+ }
strlcpy(c->name, name, sizeof(c->name));
tuner_info("microtune %s found, OK\n",name);
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
index 72b70eb5da1..dca3ddfd510 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -31,7 +31,6 @@
#include <linux/wait.h>
#include <asm/uaccess.h>
-#include <media/id.h>
#include "rds.h"
@@ -246,7 +245,7 @@ static void block_to_buf(struct saa6588 *s, unsigned char *blockbuf)
s->wr_index = 0;
if (s->wr_index == s->rd_index) {
- s->rd_index++;
+ s->rd_index += 3;
if (s->rd_index >= s->buf_size)
s->rd_index = 0;
} else
@@ -328,7 +327,7 @@ static void saa6588_work(void *data)
struct saa6588 *s = (struct saa6588 *)data;
saa6588_i2c_poll(s);
- mod_timer(&s->timer, jiffies + HZ / 50); /* 20 msec */
+ mod_timer(&s->timer, jiffies + msecs_to_jiffies(20));
}
static int saa6588_configure(struct saa6588 *s)
@@ -434,9 +433,9 @@ static int saa6588_probe(struct i2c_adapter *adap)
return i2c_probe(adap, &addr_data, saa6588_attach);
#else
switch (adap->id) {
- case I2C_ALGO_BIT | I2C_HW_B_BT848:
- case I2C_ALGO_BIT | I2C_HW_B_RIVA:
- case I2C_ALGO_SAA7134:
+ case I2C_HW_B_BT848:
+ case I2C_HW_B_RIVA:
+ case I2C_HW_SAA7134:
return i2c_probe(adap, &addr_data, saa6588_attach);
break;
}
diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c
new file mode 100644
index 00000000000..9aa8827de2c
--- /dev/null
+++ b/drivers/media/video/saa711x.c
@@ -0,0 +1,593 @@
+/*
+ * saa711x - Philips SAA711x video decoder driver version 0.0.1
+ *
+ * To do: Now, it handles only saa7113/7114. Should be improved to
+ * handle all Philips saa711x devices.
+ *
+ * Based on saa7113 driver from Dave Perks <dperks@ibm.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+
+MODULE_DESCRIPTION("Philips SAA711x video decoder driver");
+MODULE_AUTHOR("Dave Perks, Jose Ignacio Gijon, Joerg Heckenbach, Mark McClelland, Dwaine Garden");
+MODULE_LICENSE("GPL");
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#define I2C_NAME(s) (s)->name
+
+#include <linux/video_decoder.h>
+
+static int debug = 0;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, " Set the default Debug level. Default: 0 (Off) - (0-1)");
+
+
+#define dprintk(num, format, args...) \
+ do { \
+ if (debug >= num) \
+ printk(format , ##args); \
+ } while (0)
+
+/* ----------------------------------------------------------------------- */
+
+struct saa711x {
+ unsigned char reg[32];
+
+ int norm;
+ int input;
+ int enable;
+ int bright;
+ int contrast;
+ int hue;
+ int sat;
+};
+
+#define I2C_SAA7113 0x4A
+#define I2C_SAA7114 0x42
+
+/* ----------------------------------------------------------------------- */
+
+static inline int
+saa711x_write (struct i2c_client *client,
+ u8 reg,
+ u8 value)
+{
+ struct saa711x *decoder = i2c_get_clientdata(client);
+
+ decoder->reg[reg] = value;
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int
+saa711x_write_block (struct i2c_client *client,
+ const u8 *data,
+ unsigned int len)
+{
+ int ret = -1;
+ u8 reg;
+
+ /* the saa711x has an autoincrement function, use it if
+ * the adapter understands raw I2C */
+ if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ /* do raw I2C, not smbus compatible */
+ struct saa711x *decoder = i2c_get_clientdata(client);
+ struct i2c_msg msg;
+ u8 block_data[32];
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ while (len >= 2) {
+ msg.buf = (char *) block_data;
+ msg.len = 0;
+ block_data[msg.len++] = reg = data[0];
+ do {
+ block_data[msg.len++] =
+ decoder->reg[reg++] = data[1];
+ len -= 2;
+ data += 2;
+ } while (len >= 2 && data[0] == reg &&
+ msg.len < 32);
+ if ((ret = i2c_transfer(client->adapter,
+ &msg, 1)) < 0)
+ break;
+ }
+ } else {
+ /* do some slow I2C emulation kind of thing */
+ while (len >= 2) {
+ reg = *data++;
+ if ((ret = saa711x_write(client, reg,
+ *data++)) < 0)
+ break;
+ len -= 2;
+ }
+ }
+
+ return ret;
+}
+
+static int
+saa711x_init_decoder (struct i2c_client *client,
+ struct video_decoder_init *init)
+{
+ return saa711x_write_block(client, init->data, init->len);
+}
+
+static inline int
+saa711x_read (struct i2c_client *client,
+ u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const unsigned char saa711x_i2c_init[] = {
+ 0x00, 0x00, /* PH711x_CHIP_VERSION 00 - ID byte */
+ 0x01, 0x08, /* PH711x_INCREMENT_DELAY - (1) (1) (1) (1) IDEL3 IDEL2 IDELL1 IDEL0 */
+ 0x02, 0xc0, /* PH711x_ANALOG_INPUT_CONTR_1 - FUSE1 FUSE0 GUDL1 GUDL0 MODE3 MODE2 MODE1 MODE0 */
+ 0x03, 0x23, /* PH711x_ANALOG_INPUT_CONTR_2 - (1) HLNRS VBSL WPOFF HOLDG GAFIX GAI28 GAI18 */
+ 0x04, 0x00, /* PH711x_ANALOG_INPUT_CONTR_3 - GAI17 GAI16 GAI15 GAI14 GAI13 GAI12 GAI11 GAI10 */
+ 0x05, 0x00, /* PH711x_ANALOG_INPUT_CONTR_4 - GAI27 GAI26 GAI25 GAI24 GAI23 GAI22 GAI21 GAI20 */
+ 0x06, 0xeb, /* PH711x_HORIZONTAL_SYNC_START - HSB7 HSB6 HSB5 HSB4 HSB3 HSB2 HSB1 HSB0 */
+ 0x07, 0xe0, /* PH711x_HORIZONTAL_SYNC_STOP - HSS7 HSS6 HSS5 HSS4 HSS3 HSS2 HSS1 HSS0 */
+ 0x08, 0x88, /* PH711x_SYNC_CONTROL - AUFD FSEL FOET HTC1 HTC0 HPLL VNOI1 VNOI0 */
+ 0x09, 0x00, /* PH711x_LUMINANCE_CONTROL - BYPS PREF BPSS1 BPSS0 VBLB UPTCV APER1 APER0 */
+ 0x0a, 0x80, /* PH711x_LUMINANCE_BRIGHTNESS - BRIG7 BRIG6 BRIG5 BRIG4 BRIG3 BRIG2 BRIG1 BRIG0 */
+ 0x0b, 0x47, /* PH711x_LUMINANCE_CONTRAST - CONT7 CONT6 CONT5 CONT4 CONT3 CONT2 CONT1 CONT0 */
+ 0x0c, 0x40, /* PH711x_CHROMA_SATURATION - SATN7 SATN6 SATN5 SATN4 SATN3 SATN2 SATN1 SATN0 */
+ 0x0d, 0x00, /* PH711x_CHROMA_HUE_CONTROL - HUEC7 HUEC6 HUEC5 HUEC4 HUEC3 HUEC2 HUEC1 HUEC0 */
+ 0x0e, 0x01, /* PH711x_CHROMA_CONTROL - CDTO CSTD2 CSTD1 CSTD0 DCCF FCTC CHBW1 CHBW0 */
+ 0x0f, 0xaa, /* PH711x_CHROMA_GAIN_CONTROL - ACGC CGAIN6 CGAIN5 CGAIN4 CGAIN3 CGAIN2 CGAIN1 CGAIN0 */
+ 0x10, 0x00, /* PH711x_FORMAT_DELAY_CONTROL - OFTS1 OFTS0 HDEL1 HDEL0 VRLN YDEL2 YDEL1 YDEL0 */
+ 0x11, 0x1C, /* PH711x_OUTPUT_CONTROL_1 - GPSW1 CM99 GPSW0 HLSEL OEYC OERT VIPB COLO */
+ 0x12, 0x01, /* PH711x_OUTPUT_CONTROL_2 - RTSE13 RTSE12 RTSE11 RTSE10 RTSE03 RTSE02 RTSE01 RTSE00 */
+ 0x13, 0x00, /* PH711x_OUTPUT_CONTROL_3 - ADLSB (1) (1) OLDSB FIDP (1) AOSL1 AOSL0 */
+ 0x14, 0x00, /* RESERVED 14 - (1) (1) (1) (1) (1) (1) (1) (1) */
+ 0x15, 0x00, /* PH711x_V_GATE1_START - VSTA7 VSTA6 VSTA5 VSTA4 VSTA3 VSTA2 VSTA1 VSTA0 */
+ 0x16, 0x00, /* PH711x_V_GATE1_STOP - VSTO7 VSTO6 VSTO5 VSTO4 VSTO3 VSTO2 VSTO1 VSTO0 */
+ 0x17, 0x00, /* PH711x_V_GATE1_MSB - (1) (1) (1) (1) (1) (1) VSTO8 VSTA8 */
+};
+
+static int
+saa711x_command (struct i2c_client *client,
+ unsigned int cmd,
+ void *arg)
+{
+ struct saa711x *decoder = i2c_get_clientdata(client);
+
+ switch (cmd) {
+
+ case 0:
+ case DECODER_INIT:
+ {
+ struct video_decoder_init *init = arg;
+ if (NULL != init)
+ return saa711x_init_decoder(client, init);
+ else {
+ struct video_decoder_init vdi;
+ vdi.data = saa711x_i2c_init;
+ vdi.len = sizeof(saa711x_i2c_init);
+ return saa711x_init_decoder(client, &vdi);
+ }
+ }
+
+ case DECODER_DUMP:
+ {
+ int i;
+
+ for (i = 0; i < 32; i += 16) {
+ int j;
+
+ printk(KERN_DEBUG "%s: %03x", I2C_NAME(client), i);
+ for (j = 0; j < 16; ++j) {
+ printk(" %02x",
+ saa711x_read(client, i + j));
+ }
+ printk("\n");
+ }
+ }
+ break;
+
+ case DECODER_GET_CAPABILITIES:
+ {
+ struct video_decoder_capability *cap = arg;
+
+ cap->flags = VIDEO_DECODER_PAL |
+ VIDEO_DECODER_NTSC |
+ VIDEO_DECODER_SECAM |
+ VIDEO_DECODER_AUTO |
+ VIDEO_DECODER_CCIR;
+ cap->inputs = 8;
+ cap->outputs = 1;
+ }
+ break;
+
+ case DECODER_GET_STATUS:
+ {
+ int *iarg = arg;
+ int status;
+ int res;
+
+ status = saa711x_read(client, 0x1f);
+ dprintk(1, KERN_DEBUG "%s status: 0x%02x\n", I2C_NAME(client),
+ status);
+ res = 0;
+ if ((status & (1 << 6)) == 0) {
+ res |= DECODER_STATUS_GOOD;
+ }
+ switch (decoder->norm) {
+ case VIDEO_MODE_NTSC:
+ res |= DECODER_STATUS_NTSC;
+ break;
+ case VIDEO_MODE_PAL:
+ res |= DECODER_STATUS_PAL;
+ break;
+ case VIDEO_MODE_SECAM:
+ res |= DECODER_STATUS_SECAM;
+ break;
+ default:
+ case VIDEO_MODE_AUTO:
+ if ((status & (1 << 5)) != 0) {
+ res |= DECODER_STATUS_NTSC;
+ } else {
+ res |= DECODER_STATUS_PAL;
+ }
+ break;
+ }
+ if ((status & (1 << 0)) != 0) {
+ res |= DECODER_STATUS_COLOR;
+ }
+ *iarg = res;
+ }
+ break;
+
+ case DECODER_SET_GPIO:
+ {
+ int *iarg = arg;
+ if (0 != *iarg) {
+ saa711x_write(client, 0x11,
+ (decoder->reg[0x11] | 0x80));
+ } else {
+ saa711x_write(client, 0x11,
+ (decoder->reg[0x11] & 0x7f));
+ }
+ break;
+ }
+
+ case DECODER_SET_VBI_BYPASS:
+ {
+ int *iarg = arg;
+ if (0 != *iarg) {
+ saa711x_write(client, 0x13,
+ (decoder->reg[0x13] & 0xf0) | 0x0a);
+ } else {
+ saa711x_write(client, 0x13,
+ (decoder->reg[0x13] & 0xf0));
+ }
+ break;
+ }
+
+ case DECODER_SET_NORM:
+ {
+ int *iarg = arg;
+
+ switch (*iarg) {
+
+ case VIDEO_MODE_NTSC:
+ saa711x_write(client, 0x08,
+ (decoder->reg[0x08] & 0x3f) | 0x40);
+ saa711x_write(client, 0x0e,
+ (decoder->reg[0x0e] & 0x8f));
+ break;
+
+ case VIDEO_MODE_PAL:
+ saa711x_write(client, 0x08,
+ (decoder->reg[0x08] & 0x3f) | 0x00);
+ saa711x_write(client, 0x0e,
+ (decoder->reg[0x0e] & 0x8f));
+ break;
+
+ case VIDEO_MODE_SECAM:
+ saa711x_write(client, 0x08,
+ (decoder->reg[0x0e] & 0x3f) | 0x00);
+ saa711x_write(client, 0x0e,
+ (decoder->reg[0x0e] & 0x8f) | 0x50);
+ break;
+
+ case VIDEO_MODE_AUTO:
+ saa711x_write(client, 0x08,
+ (decoder->reg[0x08] & 0x3f) | 0x80);
+ saa711x_write(client, 0x0e,
+ (decoder->reg[0x0e] & 0x8f));
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+ decoder->norm = *iarg;
+ }
+ break;
+
+ case DECODER_SET_INPUT:
+ {
+ int *iarg = arg;
+ if (*iarg < 0 || *iarg > 9) {
+ return -EINVAL;
+ }
+ if (decoder->input != *iarg) {
+ decoder->input = *iarg;
+ /* select mode */
+ saa711x_write(client, 0x02,
+ (decoder->reg[0x02] & 0xf0) | decoder->input);
+ /* bypass chrominance trap for modes 4..7 */
+ saa711x_write(client, 0x09,
+ (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0));
+ }
+ }
+ break;
+
+ case DECODER_SET_OUTPUT:
+ {
+ int *iarg = arg;
+
+ /* not much choice of outputs */
+ if (*iarg != 0) {
+ return -EINVAL;
+ }
+ }
+ break;
+
+ case DECODER_ENABLE_OUTPUT:
+ {
+ int *iarg = arg;
+ int enable = (*iarg != 0);
+
+ if (decoder->enable != enable) {
+ decoder->enable = enable;
+
+ /* RJ: If output should be disabled (for
+ * playing videos), we also need a open PLL.
+ * The input is set to 0 (where no input
+ * source is connected), although this
+ * is not necessary.
+ *
+ * If output should be enabled, we have to
+ * reverse the above.
+ */
+
+ if (decoder->enable) {
+ saa711x_write(client, 0x02,
+ (decoder->
+ reg[0x02] & 0xf8) |
+ decoder->input);
+ saa711x_write(client, 0x08,
+ (decoder->reg[0x08] & 0xfb));
+ saa711x_write(client, 0x11,
+ (decoder->
+ reg[0x11] & 0xf3) | 0x0c);
+ } else {
+ saa711x_write(client, 0x02,
+ (decoder->reg[0x02] & 0xf8));
+ saa711x_write(client, 0x08,
+ (decoder->
+ reg[0x08] & 0xfb) | 0x04);
+ saa711x_write(client, 0x11,
+ (decoder->reg[0x11] & 0xf3));
+ }
+ }
+ }
+ break;
+
+ case DECODER_SET_PICTURE:
+ {
+ struct video_picture *pic = arg;
+
+ if (decoder->bright != pic->brightness) {
+ /* We want 0 to 255 we get 0-65535 */
+ decoder->bright = pic->brightness;
+ saa711x_write(client, 0x0a, decoder->bright >> 8);
+ }
+ if (decoder->contrast != pic->contrast) {
+ /* We want 0 to 127 we get 0-65535 */
+ decoder->contrast = pic->contrast;
+ saa711x_write(client, 0x0b,
+ decoder->contrast >> 9);
+ }
+ if (decoder->sat != pic->colour) {
+ /* We want 0 to 127 we get 0-65535 */
+ decoder->sat = pic->colour;
+ saa711x_write(client, 0x0c, decoder->sat >> 9);
+ }
+ if (decoder->hue != pic->hue) {
+ /* We want -128 to 127 we get 0-65535 */
+ decoder->hue = pic->hue;
+ saa711x_write(client, 0x0d,
+ (decoder->hue - 32768) >> 8);
+ }
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+/* standard i2c insmod options */
+static unsigned short normal_i2c[] = {
+ I2C_SAA7113>>1, /* saa7113 */
+ I2C_SAA7114>>1, /* saa7114 */
+ I2C_CLIENT_END
+};
+
+I2C_CLIENT_INSMOD;
+
+
+static struct i2c_driver i2c_driver_saa711x;
+
+static int
+saa711x_detect_client (struct i2c_adapter *adapter,
+ int address,
+ int kind)
+{
+ int i;
+ struct i2c_client *client;
+ struct saa711x *decoder;
+ struct video_decoder_init vdi;
+
+ dprintk(1,
+ KERN_INFO
+ "saa711x.c: detecting saa711x client on address 0x%x\n",
+ address << 1);
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+ memset(client, 0, sizeof(struct i2c_client));
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver_saa711x;
+ client->flags = I2C_CLIENT_ALLOW_USE;
+ strlcpy(I2C_NAME(client), "saa711x", sizeof(I2C_NAME(client)));
+ decoder = kmalloc(sizeof(struct saa711x), GFP_KERNEL);
+ if (decoder == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ memset(decoder, 0, sizeof(struct saa711x));
+ decoder->norm = VIDEO_MODE_NTSC;
+ decoder->input = 0;
+ decoder->enable = 1;
+ decoder->bright = 32768;
+ decoder->contrast = 32768;
+ decoder->hue = 32768;
+ decoder->sat = 32768;
+ i2c_set_clientdata(client, decoder);
+
+ i = i2c_attach_client(client);
+ if (i) {
+ kfree(client);
+ kfree(decoder);
+ return i;
+ }
+
+ vdi.data = saa711x_i2c_init;
+ vdi.len = sizeof(saa711x_i2c_init);
+ i = saa711x_init_decoder(client, &vdi);
+ if (i < 0) {
+ dprintk(1, KERN_ERR "%s_attach error: init status %d\n",
+ I2C_NAME(client), i);
+ } else {
+ dprintk(1,
+ KERN_INFO
+ "%s_attach: chip version %x at address 0x%x\n",
+ I2C_NAME(client), saa711x_read(client, 0x00) >> 4,
+ client->addr << 1);
+ }
+
+ return 0;
+}
+
+static int
+saa711x_attach_adapter (struct i2c_adapter *adapter)
+{
+ dprintk(1,
+ KERN_INFO
+ "saa711x.c: starting probe for adapter %s (0x%x)\n",
+ I2C_NAME(adapter), adapter->id);
+ return i2c_probe(adapter, &addr_data, &saa711x_detect_client);
+}
+
+static int
+saa711x_detach_client (struct i2c_client *client)
+{
+ struct saa711x *decoder = i2c_get_clientdata(client);
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ return err;
+ }
+
+ kfree(decoder);
+ kfree(client);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver_saa711x = {
+ .owner = THIS_MODULE,
+ .name = "saa711x",
+
+ .id = I2C_DRIVERID_SAA711X,
+ .flags = I2C_DF_NOTIFY,
+
+ .attach_adapter = saa711x_attach_adapter,
+ .detach_client = saa711x_detach_client,
+ .command = saa711x_command,
+};
+
+static int __init
+saa711x_init (void)
+{
+ return i2c_add_driver(&i2c_driver_saa711x);
+}
+
+static void __exit
+saa711x_exit (void)
+{
+ i2c_del_driver(&i2c_driver_saa711x);
+}
+
+module_init(saa711x_init);
+module_exit(saa711x_exit);
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
new file mode 100644
index 00000000000..624e8808a51
--- /dev/null
+++ b/drivers/media/video/saa7134/Kconfig
@@ -0,0 +1,68 @@
+config VIDEO_SAA7134
+ tristate "Philips SAA7134 support"
+ depends on VIDEO_DEV && PCI && I2C && SOUND
+ select VIDEO_BUF
+ select VIDEO_IR
+ select VIDEO_TUNER
+ select CRC32
+ ---help---
+ This is a video4linux driver for Philips SAA713x based
+ TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7134.
+
+config VIDEO_SAA7134_DVB
+ tristate "DVB/ATSC Support for saa7134 based TV cards"
+ depends on VIDEO_SAA7134 && DVB_CORE
+ select VIDEO_BUF_DVB
+ ---help---
+ This adds support for DVB cards based on the
+ Philips saa7134 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7134-dvb.
+
+ You must also select one or more DVB demodulators.
+ If you are unsure which you need, choose all of them.
+
+config VIDEO_SAA7134_DVB_ALL_FRONTENDS
+ bool "Build all supported frontends for saa7134 based TV cards"
+ default y
+ depends on VIDEO_SAA7134_DVB
+ select DVB_MT352
+ select DVB_TDA1004X
+ select DVB_NXT200X
+ ---help---
+ This builds saa7134-dvb with all currently supported frontend
+ demodulators. If you wish to tweak your configuration, and
+ only include support for the hardware that you need, choose N here.
+
+ If you are unsure, choose Y.
+
+config VIDEO_SAA7134_DVB_MT352
+ tristate "Zarlink MT352 DVB-T Support"
+ default m
+ depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
+ select DVB_MT352
+ ---help---
+ This adds DVB-T support for cards based on the
+ Philips saa7134 chip and the MT352 demodulator.
+
+config VIDEO_SAA7134_DVB_TDA1004X
+ tristate "Phillips TDA10045H/TDA10046H DVB-T Support"
+ default m
+ depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
+ select DVB_TDA1004X
+ ---help---
+ This adds DVB-T support for cards based on the
+ Philips saa7134 chip and the TDA10045H/TDA10046H demodulator.
+
+config VIDEO_SAA7134_DVB_NXT200X
+ tristate "NXT2002/NXT2004 ATSC Support"
+ default m
+ depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
+ select DVB_NXT200X
+ ---help---
+ This adds ATSC 8VSB and QAM64/256 support for cards based on the
+ Philips saa7134 chip and the NXT2002/NXT2004 demodulator.
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
index b778ffd94e6..e0b28f0533a 100644
--- a/drivers/media/video/saa7134/Makefile
+++ b/drivers/media/video/saa7134/Makefile
@@ -3,15 +3,22 @@ saa7134-objs := saa7134-cards.o saa7134-core.o saa7134-i2c.o \
saa7134-oss.o saa7134-ts.o saa7134-tvaudio.o \
saa7134-vbi.o saa7134-video.o saa7134-input.o
-obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o saa6752hs.o
+obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o \
+ saa6752hs.o saa7134-alsa.o
obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
EXTRA_CFLAGS += -I$(src)/..
EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends
+ifneq ($(CONFIG_VIDEO_BUF_DVB),n)
+ EXTRA_CFLAGS += -DHAVE_VIDEO_BUF_DVB=1
+endif
ifneq ($(CONFIG_DVB_MT352),n)
EXTRA_CFLAGS += -DHAVE_MT352=1
endif
ifneq ($(CONFIG_DVB_TDA1004X),n)
EXTRA_CFLAGS += -DHAVE_TDA1004X=1
endif
+ifneq ($(CONFIG_DVB_NXT200X),n)
+ EXTRA_CFLAGS += -DHAVE_NXT200X=1
+endif
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index 382911c6ef2..cdd1ed9c806 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -13,7 +13,6 @@
#include <linux/init.h>
#include <linux/crc32.h>
-#include <media/id.h>
#define MPEG_VIDEO_TARGET_BITRATE_MAX 27000
#define MPEG_VIDEO_MAX_BITRATE_MAX 27000
@@ -57,6 +56,7 @@ struct saa6752hs_state {
struct i2c_client client;
struct v4l2_mpeg_compression params;
enum saa6752hs_videoformat video_format;
+ v4l2_std_id standard;
};
enum saa6752hs_command {
@@ -74,58 +74,58 @@ enum saa6752hs_command {
/* ---------------------------------------------------------------------- */
static u8 PAT[] = {
- 0xc2, // i2c register
- 0x00, // table number for encoder
+ 0xc2, /* i2c register */
+ 0x00, /* table number for encoder */
- 0x47, // sync
- 0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0)
- 0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0)
+ 0x47, /* sync */
+ 0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0) */
+ 0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
- 0x00, // PSI pointer to start of table
+ 0x00, /* PSI pointer to start of table */
- 0x00, // tid(0)
- 0xb0, 0x0d, // section_syntax_indicator(1), section_length(13)
+ 0x00, /* tid(0) */
+ 0xb0, 0x0d, /* section_syntax_indicator(1), section_length(13) */
- 0x00, 0x01, // transport_stream_id(1)
+ 0x00, 0x01, /* transport_stream_id(1) */
- 0xc1, // version_number(0), current_next_indicator(1)
+ 0xc1, /* version_number(0), current_next_indicator(1) */
- 0x00, 0x00, // section_number(0), last_section_number(0)
+ 0x00, 0x00, /* section_number(0), last_section_number(0) */
- 0x00, 0x01, // program_number(1)
+ 0x00, 0x01, /* program_number(1) */
- 0xe0, 0x00, // PMT PID
+ 0xe0, 0x00, /* PMT PID */
- 0x00, 0x00, 0x00, 0x00 // CRC32
+ 0x00, 0x00, 0x00, 0x00 /* CRC32 */
};
static u8 PMT[] = {
- 0xc2, // i2c register
- 0x01, // table number for encoder
+ 0xc2, /* i2c register */
+ 0x01, /* table number for encoder */
- 0x47, // sync
- 0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid
- 0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0)
+ 0x47, /* sync */
+ 0x40, 0x00, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid */
+ 0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */
- 0x00, // PSI pointer to start of table
+ 0x00, /* PSI pointer to start of table */
- 0x02, // tid(2)
- 0xb0, 0x17, // section_syntax_indicator(1), section_length(23)
+ 0x02, /* tid(2) */
+ 0xb0, 0x17, /* section_syntax_indicator(1), section_length(23) */
- 0x00, 0x01, // program_number(1)
+ 0x00, 0x01, /* program_number(1) */
- 0xc1, // version_number(0), current_next_indicator(1)
+ 0xc1, /* version_number(0), current_next_indicator(1) */
- 0x00, 0x00, // section_number(0), last_section_number(0)
+ 0x00, 0x00, /* section_number(0), last_section_number(0) */
- 0xe0, 0x00, // PCR_PID
+ 0xe0, 0x00, /* PCR_PID */
- 0xf0, 0x00, // program_info_length(0)
+ 0xf0, 0x00, /* program_info_length(0) */
- 0x02, 0xe0, 0x00, 0xf0, 0x00, // video stream type(2), pid
- 0x04, 0xe0, 0x00, 0xf0, 0x00, // audio stream type(4), pid
+ 0x02, 0xe0, 0x00, 0xf0, 0x00, /* video stream type(2), pid */
+ 0x04, 0xe0, 0x00, 0xf0, 0x00, /* audio stream type(4), pid */
- 0x00, 0x00, 0x00, 0x00 // CRC32
+ 0x00, 0x00, 0x00, 0x00 /* CRC32 */
};
static struct v4l2_mpeg_compression param_defaults =
@@ -166,33 +166,33 @@ static int saa6752hs_chip_command(struct i2c_client* client,
unsigned long timeout;
int status = 0;
- // execute the command
+ /* execute the command */
switch(command) {
- case SAA6752HS_COMMAND_RESET:
- buf[0] = 0x00;
+ case SAA6752HS_COMMAND_RESET:
+ buf[0] = 0x00;
break;
case SAA6752HS_COMMAND_STOP:
- buf[0] = 0x03;
+ buf[0] = 0x03;
break;
case SAA6752HS_COMMAND_START:
- buf[0] = 0x02;
+ buf[0] = 0x02;
break;
case SAA6752HS_COMMAND_PAUSE:
- buf[0] = 0x04;
+ buf[0] = 0x04;
break;
case SAA6752HS_COMMAND_RECONFIGURE:
buf[0] = 0x05;
break;
- case SAA6752HS_COMMAND_SLEEP:
- buf[0] = 0x06;
+ case SAA6752HS_COMMAND_SLEEP:
+ buf[0] = 0x06;
break;
- case SAA6752HS_COMMAND_RECONFIGURE_FORCE:
+ case SAA6752HS_COMMAND_RECONFIGURE_FORCE:
buf[0] = 0x07;
break;
@@ -200,13 +200,13 @@ static int saa6752hs_chip_command(struct i2c_client* client,
return -EINVAL;
}
- // set it and wait for it to be so
+ /* set it and wait for it to be so */
i2c_master_send(client, buf, 1);
timeout = jiffies + HZ * 3;
for (;;) {
- // get the current status
+ /* get the current status */
buf[0] = 0x10;
- i2c_master_send(client, buf, 1);
+ i2c_master_send(client, buf, 1);
i2c_master_recv(client, buf, 1);
if (!(buf[0] & 0x20))
@@ -216,61 +216,58 @@ static int saa6752hs_chip_command(struct i2c_client* client,
break;
}
- // wait a bit
msleep(10);
}
- // delay a bit to let encoder settle
+ /* delay a bit to let encoder settle */
msleep(50);
- // done
- return status;
+ return status;
}
static int saa6752hs_set_bitrate(struct i2c_client* client,
struct v4l2_mpeg_compression* params)
{
- u8 buf[3];
+ u8 buf[3];
- // set the bitrate mode
+ /* set the bitrate mode */
buf[0] = 0x71;
buf[1] = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ? 0 : 1;
i2c_master_send(client, buf, 2);
- // set the video bitrate
+ /* set the video bitrate */
if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) {
- // set the target bitrate
+ /* set the target bitrate */
buf[0] = 0x80;
buf[1] = params->vi_bitrate.target >> 8;
- buf[2] = params->vi_bitrate.target & 0xff;
+ buf[2] = params->vi_bitrate.target & 0xff;
i2c_master_send(client, buf, 3);
- // set the max bitrate
+ /* set the max bitrate */
buf[0] = 0x81;
buf[1] = params->vi_bitrate.max >> 8;
- buf[2] = params->vi_bitrate.max & 0xff;
+ buf[2] = params->vi_bitrate.max & 0xff;
i2c_master_send(client, buf, 3);
} else {
- // set the target bitrate (no max bitrate for CBR)
- buf[0] = 0x81;
+ /* set the target bitrate (no max bitrate for CBR) */
+ buf[0] = 0x81;
buf[1] = params->vi_bitrate.target >> 8;
- buf[2] = params->vi_bitrate.target & 0xff;
+ buf[2] = params->vi_bitrate.target & 0xff;
i2c_master_send(client, buf, 3);
}
- // set the audio bitrate
- buf[0] = 0x94;
+ /* set the audio bitrate */
+ buf[0] = 0x94;
buf[1] = (256 == params->au_bitrate.target) ? 0 : 1;
i2c_master_send(client, buf, 2);
- // set the total bitrate
+ /* set the total bitrate */
buf[0] = 0xb1;
- buf[1] = params->st_bitrate.target >> 8;
- buf[2] = params->st_bitrate.target & 0xff;
+ buf[1] = params->st_bitrate.target >> 8;
+ buf[2] = params->st_bitrate.target & 0xff;
i2c_master_send(client, buf, 3);
- // return success
return 0;
}
@@ -376,36 +373,43 @@ static int saa6752hs_init(struct i2c_client* client)
h = i2c_get_clientdata(client);
- // Set video format - must be done first as it resets other settings
+ /* Set video format - must be done first as it resets other settings */
buf[0] = 0x41;
buf[1] = h->video_format;
i2c_master_send(client, buf, 2);
- // set bitrate
- saa6752hs_set_bitrate(client, &h->params);
+ /* Set number of lines in input signal */
+ buf[0] = 0x40;
+ buf[1] = 0x00;
+ if (h->standard & V4L2_STD_525_60)
+ buf[1] = 0x01;
+ i2c_master_send(client, buf, 2);
+
+ /* set bitrate */
+ saa6752hs_set_bitrate(client, &h->params);
- // Set GOP structure {3, 13}
+ /* Set GOP structure {3, 13} */
buf[0] = 0x72;
buf[1] = 0x03;
buf[2] = 0x0D;
i2c_master_send(client,buf,3);
- // Set minimum Q-scale {4}
+ /* Set minimum Q-scale {4} */
buf[0] = 0x82;
buf[1] = 0x04;
i2c_master_send(client,buf,2);
- // Set maximum Q-scale {12}
+ /* Set maximum Q-scale {12} */
buf[0] = 0x83;
buf[1] = 0x0C;
i2c_master_send(client,buf,2);
- // Set Output Protocol
+ /* Set Output Protocol */
buf[0] = 0xD0;
buf[1] = 0x81;
i2c_master_send(client,buf,2);
- // Set video output stream format {TS}
+ /* Set video output stream format {TS} */
buf[0] = 0xB0;
buf[1] = 0x05;
i2c_master_send(client,buf,2);
@@ -421,9 +425,9 @@ static int saa6752hs_init(struct i2c_client* client)
localPAT[sizeof(PAT) - 1] = crc & 0xFF;
/* compute PMT */
- memcpy(localPMT, PMT, sizeof(PMT));
- localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
- localPMT[4] = h->params.ts_pid_pmt & 0xff;
+ memcpy(localPMT, PMT, sizeof(PMT));
+ localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f);
+ localPMT[4] = h->params.ts_pid_pmt & 0xff;
localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F);
localPMT[16] = h->params.ts_pid_pcr & 0xFF;
localPMT[20] = 0xE0 | ((h->params.ts_pid_video >> 8) & 0x0F);
@@ -436,39 +440,39 @@ static int saa6752hs_init(struct i2c_client* client)
localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF;
localPMT[sizeof(PMT) - 1] = crc & 0xFF;
- // Set Audio PID
+ /* Set Audio PID */
buf[0] = 0xC1;
buf[1] = (h->params.ts_pid_audio >> 8) & 0xFF;
buf[2] = h->params.ts_pid_audio & 0xFF;
i2c_master_send(client,buf,3);
- // Set Video PID
+ /* Set Video PID */
buf[0] = 0xC0;
buf[1] = (h->params.ts_pid_video >> 8) & 0xFF;
buf[2] = h->params.ts_pid_video & 0xFF;
i2c_master_send(client,buf,3);
- // Set PCR PID
+ /* Set PCR PID */
buf[0] = 0xC4;
buf[1] = (h->params.ts_pid_pcr >> 8) & 0xFF;
buf[2] = h->params.ts_pid_pcr & 0xFF;
i2c_master_send(client,buf,3);
- // Send SI tables
+ /* Send SI tables */
i2c_master_send(client,localPAT,sizeof(PAT));
i2c_master_send(client,localPMT,sizeof(PMT));
- // mute then unmute audio. This removes buzzing artefacts
+ /* mute then unmute audio. This removes buzzing artefacts */
buf[0] = 0xa4;
buf[1] = 1;
i2c_master_send(client, buf, 2);
- buf[1] = 0;
+ buf[1] = 0;
i2c_master_send(client, buf, 2);
- // start it going
+ /* start it going */
saa6752hs_chip_command(client, SAA6752HS_COMMAND_START);
- // readout current state
+ /* readout current state */
buf[0] = 0xE1;
buf[1] = 0xA7;
buf[2] = 0xFE;
@@ -477,7 +481,7 @@ static int saa6752hs_init(struct i2c_client* client)
i2c_master_send(client, buf, 5);
i2c_master_recv(client, buf2, 4);
- // change aspect ratio
+ /* change aspect ratio */
buf[0] = 0xE0;
buf[1] = 0xA7;
buf[2] = 0xFE;
@@ -498,7 +502,6 @@ static int saa6752hs_init(struct i2c_client* client)
buf[8] = buf2[3];
i2c_master_send(client, buf, 9);
- // return success
return 0;
}
@@ -506,16 +509,19 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct saa6752hs_state *h;
- printk("saa6752hs: chip found @ 0x%x\n", addr<<1);
+ printk("saa6752hs: chip found @ 0x%x\n", addr<<1);
- if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL)))
- return -ENOMEM;
+ if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL)))
+ return -ENOMEM;
memset(h,0,sizeof(*h));
h->client = client_template;
h->params = param_defaults;
h->client.adapter = adap;
h->client.addr = addr;
+ /* Assume 625 input lines */
+ h->standard = 0;
+
i2c_set_clientdata(&h->client, h);
i2c_attach_client(&h->client);
return 0;
@@ -545,7 +551,7 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
struct v4l2_mpeg_compression *params = arg;
int err = 0;
- switch (cmd) {
+ switch (cmd) {
case VIDIOC_S_MPEGCOMP:
if (NULL == params) {
/* apply settings and start encoder */
@@ -559,7 +565,7 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
case VIDIOC_G_FMT:
{
- struct v4l2_format *f = arg;
+ struct v4l2_format *f = arg;
if (h->video_format == SAA6752HS_VF_UNKNOWN)
h->video_format = SAA6752HS_VF_D1;
@@ -576,6 +582,9 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
saa6752hs_set_subsampling(client, f);
break;
}
+ case VIDIOC_S_STD:
+ h->standard = *((v4l2_std_id *) arg);
+ break;
default:
/* nothing */
break;
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
new file mode 100644
index 00000000000..4f3c4235432
--- /dev/null
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -0,0 +1,1047 @@
+/*
+ * SAA713x ALSA support for V4L
+ *
+ *
+ * Caveats:
+ * - Volume doesn't work (it's always at max)
+ *
+ * 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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+
+static unsigned int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages [alsa]");
+
+/*
+ * Configuration macros
+ */
+
+/* defaults */
+#define MIXER_ADDR_TVTUNER 0
+#define MIXER_ADDR_LINE1 1
+#define MIXER_ADDR_LINE2 2
+#define MIXER_ADDR_LAST 2
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for SAA7134 capture interface(s).");
+
+#define dprintk(fmt, arg...) if (debug) \
+ printk(KERN_DEBUG "%s/alsa: " fmt, dev->name , ## arg)
+
+/*
+ * Main chip structure
+ */
+typedef struct snd_card_saa7134 {
+ snd_card_t *card;
+ spinlock_t mixer_lock;
+ int mixer_volume[MIXER_ADDR_LAST+1][2];
+ int capture_source[MIXER_ADDR_LAST+1][2];
+ struct pci_dev *pci;
+ struct saa7134_dev *saadev;
+
+ unsigned long iobase;
+ int irq;
+
+ spinlock_t lock;
+} snd_card_saa7134_t;
+
+
+
+/*
+ * PCM structure
+ */
+
+typedef struct snd_card_saa7134_pcm {
+ struct saa7134_dev *saadev;
+
+ spinlock_t lock;
+ unsigned int pcm_size; /* buffer size */
+ unsigned int pcm_count; /* bytes per period */
+ unsigned int pcm_bps; /* bytes per second */
+ snd_pcm_substream_t *substream;
+} snd_card_saa7134_pcm_t;
+
+static snd_card_t *snd_saa7134_cards[SNDRV_CARDS];
+
+
+/*
+ * saa7134 DMA audio stop
+ *
+ * Called when the capture device is released or the buffer overflows
+ *
+ * - Copied verbatim from saa7134-oss's dsp_dma_stop. Can be dropped
+ * if we just share dsp_dma_stop and use it here
+ *
+ */
+
+static void saa7134_dma_stop(struct saa7134_dev *dev)
+
+{
+ dev->dmasound.dma_blk = -1;
+ dev->dmasound.dma_running = 0;
+ saa7134_set_dmabits(dev);
+}
+
+/*
+ * saa7134 DMA audio start
+ *
+ * Called when preparing the capture device for use
+ *
+ * - Copied verbatim from saa7134-oss's dsp_dma_start. Can be dropped
+ * if we just share dsp_dma_start and use it here
+ *
+ */
+
+static void saa7134_dma_start(struct saa7134_dev *dev)
+{
+ dev->dmasound.dma_blk = 0;
+ dev->dmasound.dma_running = 1;
+ saa7134_set_dmabits(dev);
+}
+
+/*
+ * saa7134 audio DMA IRQ handler
+ *
+ * Called whenever we get an SAA7134_IRQ_REPORT_DONE_RA3 interrupt
+ * Handles shifting between the 2 buffers, manages the read counters,
+ * and notifies ALSA when periods elapse
+ *
+ * - Mostly copied from saa7134-oss's saa7134_irq_oss_done.
+ *
+ */
+
+void saa7134_irq_alsa_done(struct saa7134_dev *dev, unsigned long status)
+{
+ int next_blk, reg = 0;
+
+ spin_lock(&dev->slock);
+ if (UNSET == dev->dmasound.dma_blk) {
+ dprintk("irq: recording stopped\n");
+ goto done;
+ }
+ if (0 != (status & 0x0f000000))
+ dprintk("irq: lost %ld\n", (status >> 24) & 0x0f);
+ if (0 == (status & 0x10000000)) {
+ /* odd */
+ if (0 == (dev->dmasound.dma_blk & 0x01))
+ reg = SAA7134_RS_BA1(6);
+ } else {
+ /* even */
+ if (1 == (dev->dmasound.dma_blk & 0x01))
+ reg = SAA7134_RS_BA2(6);
+ }
+ if (0 == reg) {
+ dprintk("irq: field oops [%s]\n",
+ (status & 0x10000000) ? "even" : "odd");
+ goto done;
+ }
+
+ if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) {
+ dprintk("irq: overrun [full=%d/%d] - Blocks in %d\n",dev->dmasound.read_count,
+ dev->dmasound.bufsize, dev->dmasound.blocks);
+ snd_pcm_stop(dev->dmasound.substream,SNDRV_PCM_STATE_XRUN);
+ saa7134_dma_stop(dev);
+ goto done;
+ }
+
+ /* next block addr */
+ next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks;
+ saa_writel(reg,next_blk * dev->dmasound.blksize);
+ if (debug > 2)
+ dprintk("irq: ok, %s, next_blk=%d, addr=%x, blocks=%u, size=%u, read=%u\n",
+ (status & 0x10000000) ? "even" : "odd ", next_blk,
+ next_blk * dev->dmasound.blksize, dev->dmasound.blocks, dev->dmasound.blksize, dev->dmasound.read_count);
+
+ /* update status & wake waiting readers */
+ dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks;
+ dev->dmasound.read_count += dev->dmasound.blksize;
+
+ dev->dmasound.recording_on = reg;
+
+ if (dev->dmasound.read_count >= snd_pcm_lib_period_bytes(dev->dmasound.substream)) {
+ spin_unlock(&dev->slock);
+ snd_pcm_period_elapsed(dev->dmasound.substream);
+ spin_lock(&dev->slock);
+ }
+ done:
+ spin_unlock(&dev->slock);
+
+}
+
+/*
+ * IRQ request handler
+ *
+ * Runs along with saa7134's IRQ handler, discards anything that isn't
+ * DMA sound
+ *
+ */
+
+static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct saa7134_dev *dev = (struct saa7134_dev*) dev_id;
+ unsigned long report, status;
+ int loop, handled = 0;
+
+ for (loop = 0; loop < 10; loop++) {
+ report = saa_readl(SAA7134_IRQ_REPORT);
+ status = saa_readl(SAA7134_IRQ_STATUS);
+
+ if (report & SAA7134_IRQ_REPORT_DONE_RA3) {
+ handled = 1;
+ saa_writel(SAA7134_IRQ_REPORT,report);
+ saa7134_irq_alsa_done(dev, status);
+ } else {
+ goto out;
+ }
+ }
+
+ if (loop == 10) {
+ dprintk("error! looping IRQ!");
+ }
+
+out:
+ return IRQ_RETVAL(handled);
+}
+
+/*
+ * ALSA capture trigger
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called whenever a capture is started or stopped. Must be defined,
+ * but there's nothing we want to do here
+ *
+ */
+
+static int snd_card_saa7134_capture_trigger(snd_pcm_substream_t * substream,
+ int cmd)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
+ struct saa7134_dev *dev=saapcm->saadev;
+ int err = 0;
+
+ spin_lock_irq(&dev->slock);
+ if (cmd == SNDRV_PCM_TRIGGER_START) {
+ /* start dma */
+ saa7134_dma_start(dev);
+ } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+ /* stop dma */
+ saa7134_dma_stop(dev);
+ } else {
+ err = -EINVAL;
+ }
+ spin_unlock_irq(&dev->slock);
+
+ return err;
+}
+
+/*
+ * DMA buffer config
+ *
+ * Sets the values that will later be used as the size of the buffer,
+ * size of the fragments, and total number of fragments.
+ * Must be called during the preparation stage, before memory is
+ * allocated
+ *
+ * - Copied verbatim from saa7134-oss. Can be dropped
+ * if we just share dsp_buffer_conf from OSS.
+ */
+
+static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
+{
+ if (blksize < 0x100)
+ blksize = 0x100;
+ if (blksize > 0x10000)
+ blksize = 0x10000;
+
+ if (blocks < 2)
+ blocks = 2;
+ if ((blksize * blocks) > 1024*1024)
+ blocks = 1024*1024 / blksize;
+
+ dev->dmasound.blocks = blocks;
+ dev->dmasound.blksize = blksize;
+ dev->dmasound.bufsize = blksize * blocks;
+
+ dprintk("buffer config: %d blocks / %d bytes, %d kB total\n",
+ blocks,blksize,blksize * blocks / 1024);
+ return 0;
+}
+
+/*
+ * DMA buffer initialization
+ *
+ * Uses V4L functions to initialize the DMA. Shouldn't be necessary in
+ * ALSA, but I was unable to use ALSA's own DMA, and had to force the
+ * usage of V4L's
+ *
+ * - Copied verbatim from saa7134-oss. Can be dropped
+ * if we just share dsp_buffer_init from OSS.
+ */
+
+static int dsp_buffer_init(struct saa7134_dev *dev)
+{
+ int err;
+
+ if (!dev->dmasound.bufsize)
+ BUG();
+ videobuf_dma_init(&dev->dmasound.dma);
+ err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE,
+ (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
+ if (0 != err)
+ return err;
+ return 0;
+}
+
+/*
+ * ALSA PCM preparation
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called right after the capture device is opened, this function configures
+ * the buffer using the previously defined functions, allocates the memory,
+ * sets up the hardware registers, and then starts the DMA. When this function
+ * returns, the audio should be flowing.
+ *
+ */
+
+static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ int err, bswap, sign;
+ u32 fmt, control;
+ snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+ struct saa7134_dev *dev;
+ snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
+ unsigned int bps;
+ unsigned long size;
+ unsigned count;
+
+ size = snd_pcm_lib_buffer_bytes(substream);
+ count = snd_pcm_lib_period_bytes(substream);
+
+ saapcm->saadev->dmasound.substream = substream;
+ bps = runtime->rate * runtime->channels;
+ bps *= snd_pcm_format_width(runtime->format);
+ bps /= 8;
+ if (bps <= 0)
+ return -EINVAL;
+ saapcm->pcm_bps = bps;
+ saapcm->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+ saapcm->pcm_count = snd_pcm_lib_period_bytes(substream);
+
+
+ dev=saa7134->saadev;
+
+ dsp_buffer_conf(dev,saapcm->pcm_count,(saapcm->pcm_size/saapcm->pcm_count));
+
+ err = dsp_buffer_init(dev);
+ if (0 != err)
+ goto fail2;
+
+ /* prepare buffer */
+ if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->dmasound.dma)))
+ return err;
+ if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt)))
+ goto fail1;
+ if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt,
+ dev->dmasound.dma.sglist,
+ dev->dmasound.dma.sglen,
+ 0)))
+ goto fail2;
+
+
+
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_U8:
+ case SNDRV_PCM_FORMAT_S8:
+ fmt = 0x00;
+ break;
+ case SNDRV_PCM_FORMAT_U16_LE:
+ case SNDRV_PCM_FORMAT_U16_BE:
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_S16_BE:
+ fmt = 0x01;
+ break;
+ default:
+ err = -EINVAL;
+ return 1;
+ }
+
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S8:
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_S16_BE:
+ sign = 1;
+ break;
+ default:
+ sign = 0;
+ break;
+ }
+
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_U16_BE:
+ case SNDRV_PCM_FORMAT_S16_BE:
+ bswap = 1; break;
+ default:
+ bswap = 0; break;
+ }
+
+ switch (dev->pci->device) {
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ if (1 == runtime->channels)
+ fmt |= (1 << 3);
+ if (2 == runtime->channels)
+ fmt |= (3 << 3);
+ if (sign)
+ fmt |= 0x04;
+
+ fmt |= (MIXER_ADDR_TVTUNER == dev->dmasound.input) ? 0xc0 : 0x80;
+ saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff));
+ saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >> 8);
+ saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16);
+ saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
+
+ break;
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ if (1 == runtime->channels)
+ fmt |= (1 << 4);
+ if (2 == runtime->channels)
+ fmt |= (2 << 4);
+ if (!sign)
+ fmt |= 0x04;
+ saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -1);
+ saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24));
+ //saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210);
+ break;
+ }
+
+ dprintk("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n",
+ runtime->format, runtime->channels, fmt,
+ bswap ? 'b' : '-');
+ /* dma: setup channel 6 (= AUDIO) */
+ control = SAA7134_RS_CONTROL_BURST_16 |
+ SAA7134_RS_CONTROL_ME |
+ (dev->dmasound.pt.dma >> 12);
+ if (bswap)
+ control |= SAA7134_RS_CONTROL_BSWAP;
+
+ /* I should be able to use runtime->dma_addr in the control
+ byte, but it doesn't work. So I allocate the DMA using the
+ V4L functions, and force ALSA to use that as the DMA area */
+
+ runtime->dma_area = dev->dmasound.dma.vmalloc;
+
+ saa_writel(SAA7134_RS_BA1(6),0);
+ saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize);
+ saa_writel(SAA7134_RS_PITCH(6),0);
+ saa_writel(SAA7134_RS_CONTROL(6),control);
+
+ dev->dmasound.rate = runtime->rate;
+
+ return 0;
+ fail2:
+ saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
+ fail1:
+ videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
+ return err;
+
+
+}
+
+/*
+ * ALSA pointer fetching
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called whenever a period elapses, it must return the current hardware
+ * position of the buffer.
+ * Also resets the read counter used to prevent overruns
+ *
+ */
+
+static snd_pcm_uframes_t snd_card_saa7134_capture_pointer(snd_pcm_substream_t * substream)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
+ struct saa7134_dev *dev=saapcm->saadev;
+
+
+
+ if (dev->dmasound.read_count) {
+ dev->dmasound.read_count -= snd_pcm_lib_period_bytes(substream);
+ dev->dmasound.read_offset += snd_pcm_lib_period_bytes(substream);
+ if (dev->dmasound.read_offset == dev->dmasound.bufsize)
+ dev->dmasound.read_offset = 0;
+ }
+
+ return bytes_to_frames(runtime, dev->dmasound.read_offset);
+}
+
+/*
+ * ALSA hardware capabilities definition
+ */
+
+static snd_pcm_hardware_t snd_card_saa7134_capture =
+{
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S16_BE | \
+ SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_U8 | \
+ SNDRV_PCM_FMTBIT_U16_LE | \
+ SNDRV_PCM_FMTBIT_U16_BE,
+ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ .rate_min = 32000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = (256*1024),
+ .period_bytes_min = 64,
+ .period_bytes_max = (256*1024),
+ .periods_min = 2,
+ .periods_max = 1024,
+};
+
+static void snd_card_saa7134_runtime_free(snd_pcm_runtime_t *runtime)
+{
+ snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
+
+ kfree(saapcm);
+}
+
+
+/*
+ * ALSA hardware params
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called on initialization, right before the PCM preparation
+ * Usually used in ALSA to allocate the DMA, but since we don't use the
+ * ALSA DMA it does nothing
+ *
+ */
+
+static int snd_card_saa7134_hw_params(snd_pcm_substream_t * substream,
+ snd_pcm_hw_params_t * hw_params)
+{
+
+ return 0;
+
+
+}
+
+/*
+ * ALSA hardware release
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called after closing the device, but before snd_card_saa7134_capture_close
+ * Usually used in ALSA to free the DMA, but since we don't use the
+ * ALSA DMA I'm almost sure this isn't necessary.
+ *
+ */
+
+static int snd_card_saa7134_hw_free(snd_pcm_substream_t * substream)
+{
+ return 0;
+}
+
+/*
+ * DMA buffer release
+ *
+ * Called after closing the device, during snd_card_saa7134_capture_close
+ *
+ */
+
+static int dsp_buffer_free(struct saa7134_dev *dev)
+{
+ if (!dev->dmasound.blksize)
+ BUG();
+
+ videobuf_dma_free(&dev->dmasound.dma);
+
+ dev->dmasound.blocks = 0;
+ dev->dmasound.blksize = 0;
+ dev->dmasound.bufsize = 0;
+
+ return 0;
+}
+
+/*
+ * ALSA capture finish
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called after closing the device. It stops the DMA audio and releases
+ * the buffers
+ *
+ */
+
+static int snd_card_saa7134_capture_close(snd_pcm_substream_t * substream)
+{
+ snd_card_saa7134_t *chip = snd_pcm_substream_chip(substream);
+ struct saa7134_dev *dev = chip->saadev;
+
+ /* unlock buffer */
+ saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
+ videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
+
+ dsp_buffer_free(dev);
+ return 0;
+}
+
+/*
+ * ALSA capture start
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called when opening the device. It creates and populates the PCM
+ * structure
+ *
+ */
+
+static int snd_card_saa7134_capture_open(snd_pcm_substream_t * substream)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ snd_card_saa7134_pcm_t *saapcm;
+ snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+ struct saa7134_dev *dev = saa7134->saadev;
+ int err;
+
+ down(&dev->dmasound.lock);
+
+ dev->dmasound.afmt = SNDRV_PCM_FORMAT_U8;
+ dev->dmasound.channels = 2;
+ dev->dmasound.read_count = 0;
+ dev->dmasound.read_offset = 0;
+
+ up(&dev->dmasound.lock);
+
+ saapcm = kzalloc(sizeof(*saapcm), GFP_KERNEL);
+ if (saapcm == NULL)
+ return -ENOMEM;
+ saapcm->saadev=saa7134->saadev;
+
+ spin_lock_init(&saapcm->lock);
+
+ saapcm->substream = substream;
+ runtime->private_data = saapcm;
+ runtime->private_free = snd_card_saa7134_runtime_free;
+ runtime->hw = snd_card_saa7134_capture;
+
+ if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
+ return err;
+
+ return 0;
+}
+
+/*
+ * ALSA capture callbacks definition
+ */
+
+static snd_pcm_ops_t snd_card_saa7134_capture_ops = {
+ .open = snd_card_saa7134_capture_open,
+ .close = snd_card_saa7134_capture_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_card_saa7134_hw_params,
+ .hw_free = snd_card_saa7134_hw_free,
+ .prepare = snd_card_saa7134_capture_prepare,
+ .trigger = snd_card_saa7134_capture_trigger,
+ .pointer = snd_card_saa7134_capture_pointer,
+};
+
+/*
+ * ALSA PCM setup
+ *
+ * Called when initializing the board. Sets up the name and hooks up
+ * the callbacks
+ *
+ */
+
+static int snd_card_saa7134_pcm(snd_card_saa7134_t *saa7134, int device)
+{
+ snd_pcm_t *pcm;
+ int err;
+
+ if ((err = snd_pcm_new(saa7134->card, "SAA7134 PCM", device, 0, 1, &pcm)) < 0)
+ return err;
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_saa7134_capture_ops);
+ pcm->private_data = saa7134;
+ pcm->info_flags = 0;
+ strcpy(pcm->name, "SAA7134 PCM");
+ return 0;
+}
+
+#define SAA713x_VOLUME(xname, xindex, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+ .info = snd_saa7134_volume_info, \
+ .get = snd_saa7134_volume_get, .put = snd_saa7134_volume_put, \
+ .private_value = addr }
+
+static int snd_saa7134_volume_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 20;
+ return 0;
+}
+
+static int snd_saa7134_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+ int addr = kcontrol->private_value;
+
+ ucontrol->value.integer.value[0] = chip->mixer_volume[addr][0];
+ ucontrol->value.integer.value[1] = chip->mixer_volume[addr][1];
+ return 0;
+}
+
+static int snd_saa7134_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+ int change, addr = kcontrol->private_value;
+ int left, right;
+
+ left = ucontrol->value.integer.value[0];
+ if (left < 0)
+ left = 0;
+ if (left > 20)
+ left = 20;
+ right = ucontrol->value.integer.value[1];
+ if (right < 0)
+ right = 0;
+ if (right > 20)
+ right = 20;
+ spin_lock_irqsave(&chip->mixer_lock, flags);
+ change = chip->mixer_volume[addr][0] != left ||
+ chip->mixer_volume[addr][1] != right;
+ chip->mixer_volume[addr][0] = left;
+ chip->mixer_volume[addr][1] = right;
+ spin_unlock_irqrestore(&chip->mixer_lock, flags);
+ return change;
+}
+
+#define SAA713x_CAPSRC(xname, xindex, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+ .info = snd_saa7134_capsrc_info, \
+ .get = snd_saa7134_capsrc_get, .put = snd_saa7134_capsrc_put, \
+ .private_value = addr }
+
+static int snd_saa7134_capsrc_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int snd_saa7134_capsrc_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+ int addr = kcontrol->private_value;
+
+ spin_lock_irqsave(&chip->mixer_lock, flags);
+ ucontrol->value.integer.value[0] = chip->capture_source[addr][0];
+ ucontrol->value.integer.value[1] = chip->capture_source[addr][1];
+ spin_unlock_irqrestore(&chip->mixer_lock, flags);
+ return 0;
+}
+
+static int snd_saa7134_capsrc_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+ int change, addr = kcontrol->private_value;
+ int left, right;
+ u32 anabar, xbarin;
+ int analog_io, rate;
+ struct saa7134_dev *dev;
+
+ dev = chip->saadev;
+
+ left = ucontrol->value.integer.value[0] & 1;
+ right = ucontrol->value.integer.value[1] & 1;
+ spin_lock_irqsave(&chip->mixer_lock, flags);
+
+ change = chip->capture_source[addr][0] != left ||
+ chip->capture_source[addr][1] != right;
+ chip->capture_source[addr][0] = left;
+ chip->capture_source[addr][1] = right;
+ dev->dmasound.input=addr;
+ spin_unlock_irqrestore(&chip->mixer_lock, flags);
+
+
+ if (change) {
+ switch (dev->pci->device) {
+
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ switch (addr) {
+ case MIXER_ADDR_TVTUNER:
+ saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
+ saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x00);
+ break;
+ case MIXER_ADDR_LINE1:
+ case MIXER_ADDR_LINE2:
+ analog_io = (MIXER_ADDR_LINE1 == addr) ? 0x00 : 0x08;
+ rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03;
+ saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, analog_io);
+ saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80);
+ saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate);
+ break;
+ }
+
+ break;
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ xbarin = 0x03; // adc
+ anabar = 0;
+ switch (addr) {
+ case MIXER_ADDR_TVTUNER:
+ xbarin = 0; // Demodulator
+ anabar = 2; // DACs
+ break;
+ case MIXER_ADDR_LINE1:
+ anabar = 0; // aux1, aux1
+ break;
+ case MIXER_ADDR_LINE2:
+ anabar = 9; // aux2, aux2
+ break;
+ }
+
+ /* output xbar always main channel */
+ saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1, 0xbbbb10);
+
+ if (left || right) { // We've got data, turn the input on
+ saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, xbarin);
+ saa_writel(SAA7133_ANALOG_IO_SELECT, anabar);
+ } else {
+ saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, 0);
+ saa_writel(SAA7133_ANALOG_IO_SELECT, 0);
+ }
+ break;
+ }
+ }
+
+ return change;
+}
+
+static snd_kcontrol_new_t snd_saa7134_controls[] = {
+SAA713x_VOLUME("Video Volume", 0, MIXER_ADDR_TVTUNER),
+SAA713x_CAPSRC("Video Capture Switch", 0, MIXER_ADDR_TVTUNER),
+SAA713x_VOLUME("Line Volume", 1, MIXER_ADDR_LINE1),
+SAA713x_CAPSRC("Line Capture Switch", 1, MIXER_ADDR_LINE1),
+SAA713x_VOLUME("Line Volume", 2, MIXER_ADDR_LINE2),
+SAA713x_CAPSRC("Line Capture Switch", 2, MIXER_ADDR_LINE2),
+};
+
+/*
+ * ALSA mixer setup
+ *
+ * Called when initializing the board. Sets up the name and hooks up
+ * the callbacks
+ *
+ */
+
+static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip)
+{
+ snd_card_t *card = chip->card;
+ unsigned int idx;
+ int err;
+
+ snd_assert(chip != NULL, return -EINVAL);
+ strcpy(card->mixername, "SAA7134 Mixer");
+
+ for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_controls); idx++) {
+ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_saa7134_controls[idx], chip))) < 0)
+ return err;
+ }
+ return 0;
+}
+
+static int snd_saa7134_free(snd_card_saa7134_t *chip)
+{
+ return 0;
+}
+
+static int snd_saa7134_dev_free(snd_device_t *device)
+{
+ snd_card_saa7134_t *chip = device->device_data;
+ return snd_saa7134_free(chip);
+}
+
+/*
+ * ALSA initialization
+ *
+ * Called by saa7134-core, it creates the basic structures and registers
+ * the ALSA devices
+ *
+ */
+
+int alsa_card_saa7134_create (struct saa7134_dev *saadev)
+{
+ static int dev;
+
+ snd_card_t *card;
+ snd_card_saa7134_t *chip;
+ int err;
+ static snd_device_ops_t ops = {
+ .dev_free = snd_saa7134_dev_free,
+ };
+
+
+ if (dev >= SNDRV_CARDS)
+ return -ENODEV;
+ if (!enable[dev])
+ return -ENODEV;
+
+ card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+
+ if (card == NULL)
+ return -ENOMEM;
+
+ strcpy(card->driver, "SAA7134");
+
+ /* Card "creation" */
+
+ chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
+ if (chip == NULL) {
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&chip->lock);
+ spin_lock_init(&chip->mixer_lock);
+
+ chip->saadev = saadev;
+
+ chip->card = card;
+
+ chip->pci = saadev->pci;
+ chip->irq = saadev->pci->irq;
+ chip->iobase = pci_resource_start(saadev->pci, 0);
+
+ err = request_irq(saadev->pci->irq, saa7134_alsa_irq,
+ SA_SHIRQ | SA_INTERRUPT, saadev->name, saadev);
+
+ if (err < 0) {
+ printk(KERN_ERR "%s: can't get IRQ %d for ALSA\n",
+ saadev->name, saadev->pci->irq);
+ goto __nodev;
+ }
+
+ if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+ goto __nodev;
+ }
+
+ if ((err = snd_card_saa7134_new_mixer(chip)) < 0)
+ goto __nodev;
+
+ if ((err = snd_card_saa7134_pcm(chip, 0)) < 0)
+ goto __nodev;
+
+ snd_card_set_dev(card, &chip->pci->dev);
+
+ /* End of "creation" */
+
+ strcpy(card->shortname, "SAA7134");
+ sprintf(card->longname, "%s at 0x%lx irq %d",
+ chip->saadev->name, chip->iobase, chip->irq);
+
+ if ((err = snd_card_register(card)) == 0) {
+ snd_saa7134_cards[dev] = card;
+ return 0;
+ }
+
+__nodev:
+ snd_card_free(card);
+ kfree(chip);
+ return err;
+}
+
+/*
+ * Module initializer
+ *
+ * Loops through present saa7134 cards, and assigns an ALSA device
+ * to each one
+ *
+ */
+
+static int saa7134_alsa_init(void)
+{
+ struct saa7134_dev *saadev = NULL;
+ struct list_head *list;
+
+ printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n");
+
+ list_for_each(list,&saa7134_devlist) {
+ saadev = list_entry(list, struct saa7134_dev, devlist);
+ alsa_card_saa7134_create(saadev);
+ }
+
+ if (saadev == NULL)
+ printk(KERN_INFO "saa7134 ALSA: no saa7134 cards found\n");
+
+ return 0;
+
+}
+
+/*
+ * Module destructor
+ */
+
+void saa7134_alsa_exit(void)
+{
+ int idx;
+
+ for (idx = 0; idx < SNDRV_CARDS; idx++) {
+ snd_card_free(snd_saa7134_cards[idx]);
+ }
+
+ printk(KERN_INFO "saa7134 ALSA driver for DMA sound unloaded\n");
+
+ return;
+}
+
+module_init(saa7134_alsa_init);
+module_exit(saa7134_alsa_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ricardo Cerqueira");
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index acc7a4335e2..663d03e5bc6 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -191,10 +191,14 @@ struct saa7134_board saa7134_boards[] = {
.amux = TV,
.tv = 1,
},{
- .name = name_comp1,
+ .name = name_comp1, /* Composite signal on S-Video input */
.vmux = 0,
.amux = LINE2,
},{
+ .name = name_comp2, /* Composite input */
+ .vmux = 3,
+ .amux = LINE2,
+ },{
.name = name_svideo,
.vmux = 8,
.amux = LINE2,
@@ -2109,8 +2113,423 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x01,
},
},
-};
+ [SAA7134_BOARD_BEHOLD_409FM] = {
+ /* <http://tuner.beholder.ru>, Sergey <skiv@orel.ru> */
+ .name = "Beholder BeholdTV 409 FM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_GOTVIEW_7135] = {
+ /* Mike Baikov <mike@baikov.com> */
+ /* Andrey Cvetcov <ays14@yandex.ru> */
+ .name = "GoTView 7135 PCI",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00200003,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ .gpio = 0x00200003,
+ },{
+ .name = name_tv_mono,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x00200003,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x00200003,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x00200003,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ .gpio = 0x00200003,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ .gpio = 0x00200003,
+ },
+ },
+ [SAA7134_BOARD_PHILIPS_EUROPA] = {
+ .name = "Philips EUROPA V3 reference design",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TD1316,
+ .radio_type = UNSET,
+ .tuner_addr = 0x61,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_VIDEOMATE_DVBT_300] = {
+ .name = "Compro Videomate DVB-T300",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TD1316,
+ .radio_type = UNSET,
+ .tuner_addr = 0x61,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_VIDEOMATE_DVBT_200] = {
+ .name = "Compro Videomate DVB-T200",
+ .tuner_type = TUNER_ABSENT,
+ .audio_clock = 0x00187de7,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_RTD_VFG7350] = {
+ .name = "RTD Embedded Technologies VFG7350",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = "Composite 0",
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .name = "Composite 1",
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .name = "Composite 2",
+ .vmux = 2,
+ .amux = LINE1,
+ },{
+ .name = "Composite 3",
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = "S-Video 0",
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .name = "S-Video 1",
+ .vmux = 9,
+ .amux = LINE2,
+ }},
+ .mpeg = SAA7134_MPEG_EMPRESS,
+ .video_out = CCIR656,
+ .vid_port_opts = ( SET_T_CODE_POLARITY_NON_INVERTED |
+ SET_CLOCK_NOT_DELAYED |
+ SET_CLOCK_INVERTED |
+ SET_VSYNC_OFF ),
+ },
+ [SAA7134_BOARD_RTD_VFG7330] = {
+ .name = "RTD Embedded Technologies VFG7330",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = "Composite 0",
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .name = "Composite 1",
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .name = "Composite 2",
+ .vmux = 2,
+ .amux = LINE1,
+ },{
+ .name = "Composite 3",
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = "S-Video 0",
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .name = "S-Video 1",
+ .vmux = 9,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_FLYTVPLATINUM_MINI2] = {
+ .name = "LifeView FlyTV Platinum Mini2",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1, /* Composite signal on S-Video input */
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .name = name_comp2, /* Composite input */
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180] = {
+ /* Michael Krufky <mkrufky@m1k.net>
+ * Uses Alps Electric TDHU2, containing NXT2004 ATSC Decoder
+ * AFAIK, there is no analog demod, thus,
+ * no support for analog television.
+ */
+ .name = "AVerMedia AVerTVHD MCE A180",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_MONSTERTV_MOBILE] = {
+ .name = "SKNet MonsterTV Mobile",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 6,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_PINNACLE_PCTV_110i] = {
+ .name = "Pinnacle PCTV 110i (saa7133)",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x080200000,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 4,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_ASUSTeK_P7131_DUAL] = {
+ .name = "ASUSTeK P7131 Dual",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 1 << 21,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_SEDNA_PC_TV_CARDBUS] = {
+ /* Paul Tom Zalac <pzalac@gmail.com> */
+ /* Pavel Mihaylov <bin@bash.info> */
+ .name = "Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)",
+ /* Sedna/MuchTV (OEM) Cardbus TV Tuner */
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0xe880c0,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 6,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV] = {
+ /* "Cyril Lacoux (Yack)" <clacoux@ifeelgood.org> */
+ .name = "ASUS Digimatrix TV",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_FQ1216ME,
+ .tda9887_conf = TDA9887_PRESENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_PHILIPS_TIGER] = {
+ .name = "Philips Tiger reference design",
+ .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 = 3,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -2145,19 +2564,19 @@ struct pci_device_id saa7134_pci_tbl[] = {
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = 0x153B,
+ .subvendor = 0x153b,
.subdevice = 0x1142,
.driver_data = SAA7134_BOARD_CINERGY400,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = 0x153B,
+ .subvendor = 0x153b,
.subdevice = 0x1143,
.driver_data = SAA7134_BOARD_CINERGY600,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = 0x153B,
+ .subvendor = 0x153b,
.subdevice = 0x1158,
.driver_data = SAA7134_BOARD_CINERGY600_MK3,
},{
@@ -2193,6 +2612,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x14c0,
+ .subdevice = 0x1212, /* minipci, LR1212 */
+ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI2,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x4e42,
+ .subdevice = 0x0212, /* OEM minipci, LR212 */
+ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x5168, /* Animation Technologies (LifeView) */
.subdevice = 0x0214, /* Standard PCI, LR214WF */
.driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM,
@@ -2369,7 +2800,7 @@ struct pci_device_id saa7134_pci_tbl[] = {
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
- .subvendor = 0x153B,
+ .subvendor = 0x153b,
.subdevice = 0x1152,
.driver_data = SAA7134_BOARD_CINERGY200,
},{
@@ -2434,13 +2865,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subvendor = 0x1421,
.subdevice = 0x0350, /* PCI version */
.driver_data = SAA7134_BOARD_ADS_INSTANT_TV,
-
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x1421,
.subdevice = 0x0370, /* cardbus version */
.driver_data = SAA7134_BOARD_ADS_INSTANT_TV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1421,
+ .subdevice = 0x1370, /* cardbus version */
+ .driver_data = SAA7134_BOARD_ADS_INSTANT_TV,
},{ /* Typhoon DVB-T Duo Digital/Analog Cardbus */
.vendor = PCI_VENDOR_ID_PHILIPS,
@@ -2459,9 +2895,81 @@ struct pci_device_id saa7134_pci_tbl[] = {
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
.subvendor = 0x1043,
.subdevice = 0x0210, /* mini pci PAL/SECAM version */
- .driver_data = SAA7134_BOARD_FLYTV_DIGIMATRIX,
+ .driver_data = SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV,
},{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0000, /* It shouldn't break anything, since subdevice id seems unique */
+ .subdevice = 0x4091,
+ .driver_data = SAA7134_BOARD_BEHOLD_409FM,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5456, /* GoTView */
+ .subdevice = 0x7135,
+ .driver_data = SAA7134_BOARD_GOTVIEW_7135,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2004,
+ .driver_data = SAA7134_BOARD_PHILIPS_EUROPA,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x185b,
+ .subdevice = 0xc900,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_300,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x185b,
+ .subdevice = 0xc901,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_200,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1435,
+ .subdevice = 0x7350,
+ .driver_data = SAA7134_BOARD_RTD_VFG7350,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1435,
+ .subdevice = 0x7330,
+ .driver_data = SAA7134_BOARD_RTD_VFG7330,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461,
+ .subdevice = 0x1044,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1131,
+ .subdevice = 0x4ee9,
+ .driver_data = SAA7134_BOARD_MONSTERTV_MOBILE,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x11bd,
+ .subdevice = 0x002e,
+ .driver_data = SAA7134_BOARD_PINNACLE_PCTV_110i,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1043,
+ .subdevice = 0x4862,
+ .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2018,
+ .driver_data = SAA7134_BOARD_PHILIPS_TIGER,
+ },{
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -2530,9 +3038,10 @@ int saa7134_board_init1(struct saa7134_dev *dev)
switch (dev->board) {
case SAA7134_BOARD_FLYVIDEO2000:
case SAA7134_BOARD_FLYVIDEO3000:
- dev->has_remote = 1;
+ dev->has_remote = SAA7134_REMOTE_GPIO;
board_flyvideo(dev);
break;
+ case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
case SAA7134_BOARD_FLYTVPLATINUM_FM:
case SAA7134_BOARD_CINERGY400:
case SAA7134_BOARD_CINERGY600:
@@ -2550,10 +3059,16 @@ int saa7134_board_init1(struct saa7134_dev *dev)
/* case SAA7134_BOARD_SABRENT_SBTTVFM: */ /* not finished yet */
case SAA7134_BOARD_VIDEOMATE_TV_PVR:
case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200:
case SAA7134_BOARD_MANLI_MTV001:
case SAA7134_BOARD_MANLI_MTV002:
+ case SAA7134_BOARD_BEHOLD_409FM:
case SAA7134_BOARD_AVACSSMARTTV:
- dev->has_remote = 1;
+ case SAA7134_BOARD_GOTVIEW_7135:
+ case SAA7134_BOARD_KWORLD_TERMINATOR:
+ case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
+ dev->has_remote = SAA7134_REMOTE_GPIO;
break;
case SAA7134_BOARD_MD5044:
printk("%s: seems there are two different versions of the MD5044\n"
@@ -2565,11 +3080,14 @@ int saa7134_board_init1(struct saa7134_dev *dev)
/* power-up tuner chip */
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00040000, 0x00040000);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000000);
- msleep(1);
+ case SAA7134_BOARD_MONSTERTV_MOBILE:
+ /* power-up tuner chip */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00040000, 0x00040000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000004);
break;
case SAA7134_BOARD_FLYDVBTDUO:
case SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS:
- /* turn the fan on Hac: static for the time being */
+ /* turn the fan on */
saa_writeb(SAA7134_GPIO_GPMODE3, 0x08);
saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x06);
break;
@@ -2579,6 +3097,22 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
msleep(1);
break;
+ case SAA7134_BOARD_RTD_VFG7350:
+
+ /*
+ * Make sure Production Test Register at offset 0x1D1 is cleared
+ * to take chip out of test mode. Clearing bit 4 (TST_EN_AOUT)
+ * prevents pin 105 from remaining low; keeping pin 105 low
+ * continually resets the SAA6752 chip.
+ */
+
+ saa_writeb (SAA7134_PRODUCTION_TEST_MODE, 0x00);
+ break;
+ /* i2c remotes */
+ case SAA7134_BOARD_PINNACLE_PCTV_110i:
+ case SAA7134_BOARD_UPMOST_PURPLE_TV:
+ dev->has_remote = SAA7134_REMOTE_I2C;
+ break;
}
return 0;
}
@@ -2613,7 +3147,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR, &tun_setup);
}
break;
-case SAA7134_BOARD_MD7134:
+ case SAA7134_BOARD_MD7134:
{
struct tuner_setup tun_setup;
u8 subaddr;
@@ -2680,6 +3214,33 @@ case SAA7134_BOARD_MD7134:
saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
}
break;
+ case SAA7134_BOARD_PHILIPS_EUROPA:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+ /* The Philips EUROPA based hybrid boards have the tuner connected through
+ * the channel decoder. We have to make it transparent to find it
+ */
+ {
+ struct tuner_setup tun_setup;
+ u8 data[] = { 0x07, 0x02};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+ tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
+ tun_setup.type = dev->tuner_type;
+ tun_setup.addr = dev->tuner_addr;
+
+ saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
+ }
+ break;
+ case SAA7134_BOARD_PHILIPS_TIGER:
+ case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+ /* this is a hybrid board, initialize to analog mode */
+ {
+ u8 data[] = { 0x3c, 0x33, 0x68};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ }
+ break;
}
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index e5e36f3c625..19b88744fb3 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -57,6 +57,10 @@ static unsigned int oss = 0;
module_param(oss, int, 0444);
MODULE_PARM_DESC(oss,"register oss devices (default: no)");
+static unsigned int alsa = 0;
+module_param(alsa, int, 0444);
+MODULE_PARM_DESC(alsa,"register alsa devices (default: no)");
+
static unsigned int latency = UNSET;
module_param(latency, int, 0444);
MODULE_PARM_DESC(latency,"pci latency timer");
@@ -190,6 +194,7 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg)
static int need_empress;
static int need_dvb;
+static int need_alsa;
static int pending_call(struct notifier_block *self, unsigned long state,
void *module)
@@ -197,10 +202,12 @@ static int pending_call(struct notifier_block *self, unsigned long state,
if (module != THIS_MODULE || state != MODULE_STATE_LIVE)
return NOTIFY_DONE;
- if (need_empress)
- request_module("saa7134-empress");
- if (need_dvb)
- request_module("saa7134-dvb");
+ if (need_empress)
+ request_module("saa7134-empress");
+ if (need_dvb)
+ request_module("saa7134-dvb");
+ if (need_alsa)
+ request_module("saa7134-alsa");
return NOTIFY_DONE;
}
@@ -275,8 +282,8 @@ unsigned long saa7134_buffer_base(struct saa7134_buf *buf)
int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt)
{
- __le32 *cpu;
- dma_addr_t dma_addr;
+ __le32 *cpu;
+ dma_addr_t dma_addr;
cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr);
if (NULL == cpu)
@@ -436,7 +443,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
ctrl |= SAA7134_MAIN_CTRL_TE0;
irq |= SAA7134_IRQ1_INTE_RA0_1 |
SAA7134_IRQ1_INTE_RA0_0;
- cap = dev->video_q.curr->vb.field;
+ cap = dev->video_q.curr->vb.field;
}
/* video capture -- dma 1+2 (planar modes) */
@@ -465,7 +472,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
}
/* audio capture -- dma 3 */
- if (dev->oss.dma_running) {
+ if (dev->dmasound.dma_running) {
ctrl |= SAA7134_MAIN_CTRL_TE6;
irq |= SAA7134_IRQ1_INTE_RA3_1 |
SAA7134_IRQ1_INTE_RA3_0;
@@ -570,6 +577,17 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
dev->name);
goto out;
}
+
+ /* If alsa support is active and we get a sound report, exit
+ and let the saa7134-alsa module deal with it */
+
+ if ((report & SAA7134_IRQ_REPORT_DONE_RA3) && alsa) {
+ if (irq_debug > 1)
+ printk(KERN_DEBUG "%s/irq: ignoring interrupt for ALSA\n",
+ dev->name);
+ goto out;
+ }
+
handled = 1;
saa_writel(SAA7134_IRQ_REPORT,report);
if (irq_debug)
@@ -591,13 +609,17 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
card_has_mpeg(dev))
saa7134_irq_ts_done(dev,status);
- if ((report & SAA7134_IRQ_REPORT_DONE_RA3))
- saa7134_irq_oss_done(dev,status);
+ if ((report & SAA7134_IRQ_REPORT_DONE_RA3)) {
+ if (oss) {
+ saa7134_irq_oss_done(dev,status);
+ }
+ }
if ((report & (SAA7134_IRQ_REPORT_GPIO16 |
SAA7134_IRQ_REPORT_GPIO18)) &&
dev->remote)
saa7134_input_irq(dev);
+
}
if (10 == loop) {
@@ -636,7 +658,7 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
saa_writel(SAA7134_IRQ1, 0);
saa_writel(SAA7134_IRQ2, 0);
- init_MUTEX(&dev->lock);
+ init_MUTEX(&dev->lock);
spin_lock_init(&dev->slock);
saa7134_track_gpio(dev,"pre-init");
@@ -646,14 +668,6 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
saa7134_ts_init1(dev);
saa7134_input_init1(dev);
- switch (dev->pci->device) {
- case PCI_DEVICE_ID_PHILIPS_SAA7134:
- case PCI_DEVICE_ID_PHILIPS_SAA7133:
- case PCI_DEVICE_ID_PHILIPS_SAA7135:
- saa7134_oss_init1(dev);
- break;
- }
-
/* RAM FIFO config */
saa_writel(SAA7134_FIFO_SIZE, 0x08070503);
saa_writel(SAA7134_THRESHOULD,0x02020202);
@@ -668,6 +682,21 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
SAA7134_MAIN_CTRL_ESFE |
SAA7134_MAIN_CTRL_EBDAC);
+ /*
+ * Initialize OSS _after_ enabling audio clock PLL and audio processing.
+ * OSS initialization writes to registers via the audio DSP; these
+ * writes will fail unless the audio clock has been started. At worst,
+ * audio will not work.
+ */
+
+ switch (dev->pci->device) {
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ saa7134_oss_init1(dev);
+ break;
+ }
+
/* enable peripheral devices */
saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
@@ -687,7 +716,7 @@ static int saa7134_hwinit2(struct saa7134_dev *dev)
saa7134_tvaudio_init2(dev);
/* enable IRQ's */
- irq2_mask =
+ irq2_mask =
SAA7134_IRQ2_INTE_DEC3 |
SAA7134_IRQ2_INTE_DEC2 |
SAA7134_IRQ2_INTE_DEC1 |
@@ -695,10 +724,12 @@ static int saa7134_hwinit2(struct saa7134_dev *dev)
SAA7134_IRQ2_INTE_PE |
SAA7134_IRQ2_INTE_AR;
- if (dev->has_remote)
+ if (dev->has_remote == SAA7134_REMOTE_GPIO)
irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18 |
SAA7134_IRQ2_INTE_GPIO18A |
SAA7134_IRQ2_INTE_GPIO16 );
+ else if (dev->has_remote == SAA7134_REMOTE_I2C)
+ request_module("ir-kbd-i2c");
saa_writel(SAA7134_IRQ1, 0);
saa_writel(SAA7134_IRQ2, irq2_mask);
@@ -872,8 +903,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
/* print pci info */
pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
- pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
- printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
+ pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
+ printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%lx\n", dev->name,
pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
dev->pci_lat,pci_resource_start(pci_dev,0));
@@ -897,7 +928,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf;
if (UNSET != tuner[dev->nr])
dev->tuner_type = tuner[dev->nr];
- printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+ printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
dev->name,pci_dev->subsystem_vendor,
pci_dev->subsystem_device,saa7134_boards[dev->board].name,
dev->board, card[dev->nr] == dev->board ?
@@ -947,14 +978,20 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
request_module("tuner");
if (dev->tda9887_conf)
request_module("tda9887");
- if (card_is_empress(dev)) {
+ if (card_is_empress(dev)) {
request_module("saa6752hs");
request_module_depend("saa7134-empress",&need_empress);
}
- if (card_is_dvb(dev))
+ if (card_is_dvb(dev))
request_module_depend("saa7134-dvb",&need_dvb);
+ if (!oss && alsa) {
+ dprintk("Requesting ALSA module\n");
+ request_module_depend("saa7134-alsa",&need_alsa);
+ }
+
+
v4l2_prio_init(&dev->prio);
/* register v4l devices */
@@ -993,22 +1030,22 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
case PCI_DEVICE_ID_PHILIPS_SAA7133:
case PCI_DEVICE_ID_PHILIPS_SAA7135:
if (oss) {
- err = dev->oss.minor_dsp =
+ err = dev->dmasound.minor_dsp =
register_sound_dsp(&saa7134_dsp_fops,
dsp_nr[dev->nr]);
if (err < 0) {
goto fail4;
}
printk(KERN_INFO "%s: registered device dsp%d\n",
- dev->name,dev->oss.minor_dsp >> 4);
+ dev->name,dev->dmasound.minor_dsp >> 4);
- err = dev->oss.minor_mixer =
+ err = dev->dmasound.minor_mixer =
register_sound_mixer(&saa7134_mixer_fops,
mixer_nr[dev->nr]);
if (err < 0)
goto fail5;
printk(KERN_INFO "%s: registered device mixer%d\n",
- dev->name,dev->oss.minor_mixer >> 4);
+ dev->name,dev->dmasound.minor_mixer >> 4);
}
break;
}
@@ -1035,7 +1072,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
case PCI_DEVICE_ID_PHILIPS_SAA7133:
case PCI_DEVICE_ID_PHILIPS_SAA7135:
if (oss)
- unregister_sound_dsp(dev->oss.minor_dsp);
+ unregister_sound_dsp(dev->dmasound.minor_dsp);
break;
}
fail4:
@@ -1055,7 +1092,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
{
- struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
+ struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
struct list_head *item;
struct saa7134_mpeg_ops *mops;
@@ -1093,8 +1130,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
case PCI_DEVICE_ID_PHILIPS_SAA7133:
case PCI_DEVICE_ID_PHILIPS_SAA7135:
if (oss) {
- unregister_sound_mixer(dev->oss.minor_mixer);
- unregister_sound_dsp(dev->oss.minor_dsp);
+ unregister_sound_mixer(dev->dmasound.minor_mixer);
+ unregister_sound_dsp(dev->dmasound.minor_dsp);
}
break;
}
@@ -1149,10 +1186,10 @@ EXPORT_SYMBOL(saa7134_ts_unregister);
/* ----------------------------------------------------------- */
static struct pci_driver saa7134_pci_driver = {
- .name = "saa7134",
- .id_table = saa7134_pci_tbl,
- .probe = saa7134_initdev,
- .remove = __devexit_p(saa7134_finidev),
+ .name = "saa7134",
+ .id_table = saa7134_pci_tbl,
+ .probe = saa7134_initdev,
+ .remove = __devexit_p(saa7134_finidev),
};
static int saa7134_init(void)
@@ -1188,6 +1225,13 @@ EXPORT_SYMBOL(saa7134_i2c_call_clients);
EXPORT_SYMBOL(saa7134_devlist);
EXPORT_SYMBOL(saa7134_boards);
+/* ----------------- For ALSA -------------------------------- */
+
+EXPORT_SYMBOL(saa7134_pgtable_free);
+EXPORT_SYMBOL(saa7134_pgtable_build);
+EXPORT_SYMBOL(saa7134_pgtable_alloc);
+EXPORT_SYMBOL(saa7134_set_dmabits);
+
/* ----------------------------------------------------------- */
/*
* Local variables:
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 639ae51a052..e016480c346 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -29,7 +29,6 @@
#include <linux/kthread.h>
#include <linux/suspend.h>
-
#include "saa7134-reg.h"
#include "saa7134.h"
@@ -40,6 +39,10 @@
#ifdef HAVE_TDA1004X
# include "tda1004x.h"
#endif
+#ifdef HAVE_NXT200X
+# include "nxt200x.h"
+# include "dvb-pll.h"
+#endif
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
@@ -151,25 +154,12 @@ static struct mt352_config pinnacle_300i = {
/* ------------------------------------------------------------------ */
#ifdef HAVE_TDA1004X
-static int philips_tu1216_pll_init(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
- struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
-
- /* setup PLL configuration */
- if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
- return -EIO;
- msleep(1);
- return 0;
-}
-
-static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct saa7134_dev *dev = fe->dvb->priv;
u8 tuner_buf[4];
- struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len =
+ struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
sizeof(tuner_buf) };
int tuner_frequency = 0;
u8 band, cp, filter;
@@ -242,11 +232,36 @@ static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p
if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
+ msleep(1);
+ return 0;
+}
+static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+ struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
+
+ /* setup PLL configuration */
+ if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
+ return -EIO;
msleep(1);
+
return 0;
}
+/* ------------------------------------------------------------------ */
+
+static int philips_tu1216_pll_60_init(struct dvb_frontend *fe)
+{
+ return philips_tda6651_pll_init(0x60, fe);
+}
+
+static int philips_tu1216_pll_60_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ return philips_tda6651_pll_set(0x60, fe, params);
+}
+
static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
const struct firmware **fw, char *name)
{
@@ -254,22 +269,108 @@ static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
return request_firmware(fw, name, &dev->pci->dev);
}
-static struct tda1004x_config philips_tu1216_config = {
+static struct tda1004x_config philips_tu1216_60_config = {
+
+ .demod_address = 0x8,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
+ .pll_init = philips_tu1216_pll_60_init,
+ .pll_set = philips_tu1216_pll_60_set,
+ .pll_sleep = NULL,
+ .request_firmware = philips_tu1216_request_firmware,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int philips_tu1216_pll_61_init(struct dvb_frontend *fe)
+{
+ return philips_tda6651_pll_init(0x61, fe);
+}
+
+static int philips_tu1216_pll_61_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ return philips_tda6651_pll_set(0x61, fe, params);
+}
+
+static struct tda1004x_config philips_tu1216_61_config = {
.demod_address = 0x8,
.invert = 1,
- .invert_oclk = 1,
+ .invert_oclk = 0,
.xtal_freq = TDA10046_XTAL_4M,
.agc_config = TDA10046_AGC_DEFAULT,
.if_freq = TDA10046_FREQ_3617,
- .pll_init = philips_tu1216_pll_init,
- .pll_set = philips_tu1216_pll_set,
+ .pll_init = philips_tu1216_pll_61_init,
+ .pll_set = philips_tu1216_pll_61_set,
.pll_sleep = NULL,
.request_firmware = philips_tu1216_request_firmware,
};
/* ------------------------------------------------------------------ */
+static int philips_europa_pll_init(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab };
+ struct i2c_msg init_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+ /* setup PLL configuration */
+ if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
+ return -EIO;
+ msleep(1);
+
+ /* switch the board to dvb mode */
+ init_msg.addr = 0x43;
+ init_msg.len = 0x02;
+ msg[0] = 0x00;
+ msg[1] = 0x40;
+ if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
+ return -EIO;
+
+ return 0;
+}
+
+static int philips_td1316_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ return philips_tda6651_pll_set(0x61, fe, params);
+}
+
+static void philips_europa_analog(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ /* this message actually turns the tuner back to analog mode */
+ static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 };
+ struct i2c_msg analog_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+ i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
+ msleep(1);
+
+ /* switch the board to analog mode */
+ analog_msg.addr = 0x43;
+ analog_msg.len = 0x02;
+ msg[0] = 0x00;
+ msg[1] = 0x14;
+ i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
+}
+
+static struct tda1004x_config philips_europa_config = {
+
+ .demod_address = 0x8,
+ .invert = 0,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_IFO_AUTO_POS,
+ .if_freq = TDA10046_FREQ_052,
+ .pll_init = philips_europa_pll_init,
+ .pll_set = philips_td1316_pll_set,
+ .pll_sleep = philips_europa_analog,
+ .request_firmware = NULL,
+};
+
+/* ------------------------------------------------------------------ */
static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
{
@@ -382,7 +483,6 @@ static int philips_fmd1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
return 0;
}
-#ifdef HAVE_TDA1004X
static struct tda1004x_config medion_cardbus = {
.demod_address = 0x08,
.invert = 1,
@@ -395,7 +495,6 @@ static struct tda1004x_config medion_cardbus = {
.pll_sleep = philips_fmd1216_analog,
.request_firmware = NULL,
};
-#endif
/* ------------------------------------------------------------------ */
@@ -452,7 +551,7 @@ static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
u8 tuner_buf[14];
struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,
- .len = sizeof(tuner_buf) };
+ .len = sizeof(tuner_buf) };
int i, tuner_freq, if_freq;
u32 N;
switch (params->u.ofdm.bandwidth) {
@@ -511,7 +610,7 @@ static void philips_tda827x_pll_sleep(struct dvb_frontend *fe)
struct saa7134_dev *dev = fe->dvb->priv;
static u8 tda827x_sleep[] = { 0x30, 0xd0};
struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tda827x_sleep,
- .len = sizeof(tda827x_sleep) };
+ .len = sizeof(tda827x_sleep) };
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
}
@@ -527,6 +626,202 @@ static struct tda1004x_config tda827x_lifeview_config = {
.pll_sleep = philips_tda827x_pll_sleep,
.request_firmware = NULL,
};
+
+/* ------------------------------------------------------------------ */
+
+struct tda827xa_data {
+ u32 lomax;
+ u8 svco;
+ u8 spd;
+ u8 scr;
+ u8 sbs;
+ u8 gc3;
+};
+
+static struct tda827xa_data tda827xa_dvbt[] = {
+ { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1},
+ { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+ { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+ { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
+ { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
+ { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+ { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+ { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+ { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+ { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
+ { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
+ { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
+ { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
+ { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+ { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+ { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
+ { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+ { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
+ { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+ { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+ { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+ { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+ { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+ { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+ { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+ { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
+ { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}};
+
+
+static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ u8 tuner_buf[14];
+ unsigned char reg2[2];
+
+ struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = tuner_buf};
+ int i, tuner_freq, if_freq;
+ u32 N;
+
+ switch (params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ if_freq = 4000000;
+ break;
+ case BANDWIDTH_7_MHZ:
+ if_freq = 4500000;
+ break;
+ default: /* 8 MHz or Auto */
+ if_freq = 5000000;
+ break;
+ }
+ tuner_freq = params->frequency + if_freq;
+
+ i = 0;
+ while (tda827xa_dvbt[i].lomax < tuner_freq) {
+ if(tda827xa_dvbt[i + 1].lomax == 0)
+ break;
+ i++;
+ }
+
+ N = ((tuner_freq + 31250) / 62500) << tda827xa_dvbt[i].spd;
+ tuner_buf[0] = 0; // subaddress
+ tuner_buf[1] = N >> 8;
+ tuner_buf[2] = N & 0xff;
+ tuner_buf[3] = 0;
+ tuner_buf[4] = 0x16;
+ tuner_buf[5] = (tda827xa_dvbt[i].spd << 5) + (tda827xa_dvbt[i].svco << 3) +
+ tda827xa_dvbt[i].sbs;
+ tuner_buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4);
+ tuner_buf[7] = 0x0c;
+ tuner_buf[8] = 0x06;
+ tuner_buf[9] = 0x24;
+ tuner_buf[10] = 0xff;
+ tuner_buf[11] = 0x60;
+ tuner_buf[12] = 0x00;
+ tuner_buf[13] = 0x39; // lpsel
+ msg.len = 14;
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+
+ msg.buf= reg2;
+ msg.len = 2;
+ reg2[0] = 0x60;
+ reg2[1] = 0x3c;
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+ reg2[0] = 0xa0;
+ reg2[1] = 0x40;
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+ msleep(2);
+ /* correct CP value */
+ reg2[0] = 0x30;
+ reg2[1] = 0x10 + tda827xa_dvbt[i].scr;
+ msg.len = 2;
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+ msleep(550);
+ reg2[0] = 0x50;
+ reg2[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4);
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+ return 0;
+
+}
+
+static void philips_tda827xa_pll_sleep(u8 addr, struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 tda827xa_sleep[] = { 0x30, 0x90};
+ struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tda827xa_sleep,
+ .len = sizeof(tda827xa_sleep) };
+ i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
+
+}
+
+/* ------------------------------------------------------------------ */
+
+static int philips_tiger_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ int ret;
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 tda8290_close[] = { 0x21, 0xc0};
+ static u8 tda8290_open[] = { 0x21, 0x80};
+ struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2};
+ /* close tda8290 i2c bridge */
+ tda8290_msg.buf = tda8290_close;
+ ret = i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
+ if (ret != 1)
+ return -EIO;
+ msleep(20);
+ ret = philips_tda827xa_pll_set(0x61, fe, params);
+ if (ret != 0)
+ return ret;
+ /* open tda8290 i2c bridge */
+ tda8290_msg.buf = tda8290_open;
+ i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
+ return ret;
+};
+
+static int philips_tiger_dvb_mode(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 data[] = { 0x3c, 0x33, 0x6a};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static void philips_tiger_analog_mode(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 data[] = { 0x3c, 0x33, 0x68};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ philips_tda827xa_pll_sleep( 0x61, fe);
+}
+
+static struct tda1004x_config philips_tiger_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .if_freq = TDA10046_FREQ_045,
+ .pll_init = philips_tiger_dvb_mode,
+ .pll_set = philips_tiger_pll_set,
+ .pll_sleep = philips_tiger_analog_mode,
+ .request_firmware = NULL,
+};
+
+#endif
+
+/* ------------------------------------------------------------------ */
+
+#ifdef HAVE_NXT200X
+static struct nxt200x_config avertvhda180 = {
+ .demod_address = 0x0a,
+ .pll_address = 0x61,
+ .pll_desc = &dvb_pll_tdhu2,
+};
#endif
/* ------------------------------------------------------------------ */
@@ -558,7 +853,7 @@ static int dvb_init(struct saa7134_dev *dev)
&dev->i2c_adap);
break;
case SAA7134_BOARD_PHILIPS_TOUGH:
- dev->dvb.frontend = tda10046_attach(&philips_tu1216_config,
+ dev->dvb.frontend = tda10046_attach(&philips_tu1216_60_config,
&dev->i2c_adap);
break;
case SAA7134_BOARD_FLYDVBTDUO:
@@ -569,6 +864,31 @@ static int dvb_init(struct saa7134_dev *dev)
dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
&dev->i2c_adap);
break;
+ case SAA7134_BOARD_PHILIPS_EUROPA:
+ dev->dvb.frontend = tda10046_attach(&philips_europa_config,
+ &dev->i2c_adap);
+ break;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+ dev->dvb.frontend = tda10046_attach(&philips_europa_config,
+ &dev->i2c_adap);
+ break;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+ dev->dvb.frontend = tda10046_attach(&philips_tu1216_61_config,
+ &dev->i2c_adap);
+ break;
+ case SAA7134_BOARD_PHILIPS_TIGER:
+ dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
+ &dev->i2c_adap);
+ break;
+ case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+ dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
+ &dev->i2c_adap);
+ break;
+#endif
+#ifdef HAVE_NXT200X
+ case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
+ dev->dvb.frontend = nxt200x_attach(&avertvhda180, &dev->i2c_adap);
+ break;
#endif
default:
printk("%s: Huh? unknown DVB card?\n",dev->name);
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index 77b627eb648..e9ec69efb4c 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -55,7 +55,7 @@ static void ts_reset_encoder(struct saa7134_dev* dev)
saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
msleep(10);
- saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+ saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
msleep(100);
dev->empress_started = 0;
}
@@ -65,7 +65,7 @@ static int ts_init_encoder(struct saa7134_dev* dev)
ts_reset_encoder(dev);
saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, NULL);
dev->empress_started = 1;
- return 0;
+ return 0;
}
/* ------------------------------------------------------------------ */
@@ -169,7 +169,7 @@ static int ts_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_capability *cap = arg;
memset(cap,0,sizeof(*cap));
- strcpy(cap->driver, "saa7134");
+ strcpy(cap->driver, "saa7134");
strlcpy(cap->card, saa7134_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 711aa8e85fa..7575043f087 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -239,7 +239,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
unsigned char data;
int addr,rc,i,byte;
- status = i2c_get_status(dev);
+ status = i2c_get_status(dev);
if (!i2c_is_idle(status))
if (!i2c_reset(dev))
return -EIO;
@@ -296,7 +296,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
rc = -EIO;
if (!i2c_is_busy_wait(dev))
goto err;
- status = i2c_get_status(dev);
+ status = i2c_get_status(dev);
if (i2c_is_error(status))
goto err;
/* ensure that the bus is idle for at least one bit slot */
@@ -335,6 +335,20 @@ static int attach_inform(struct i2c_client *client)
d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
client->driver->name, client->addr, client->name);
+ /* Am I an i2c remote control? */
+
+ switch (client->addr) {
+ case 0x7a:
+ case 0x47:
+ {
+ struct IR_i2c *ir = i2c_get_clientdata(client);
+ d1printk("%s i2c IR detected (%s).\n",
+ client->driver->name,ir->phys);
+ saa7134_set_i2c_ir(dev,ir);
+ break;
+ }
+ }
+
if (!client->driver->command)
return 0;
@@ -348,12 +362,12 @@ static int attach_inform(struct i2c_client *client)
client->driver->command(client, TUNER_SET_TYPE_ADDR, &tun_setup);
}
- }
+ }
if (tuner != UNSET) {
- tun_setup.type = tuner;
- tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
+ tun_setup.type = tuner;
+ tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) {
@@ -361,11 +375,11 @@ static int attach_inform(struct i2c_client *client)
client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup);
}
- }
+ }
client->driver->command(client, TDA9887_SET_CONFIG, &conf);
- return 0;
+ return 0;
}
static struct i2c_algorithm saa7134_algo = {
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 242cb235cf9..329accda6d4 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -39,6 +39,8 @@ MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
#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)
/* ---------------------------------------------------------------------- */
@@ -114,24 +116,24 @@ static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = {
/* Alfons Geser <a.geser@cox.net>
* updates from Job D. R. Borges <jobdrb@ig.com.br> */
static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = {
- [ 18 ] = KEY_POWER,
- [ 1 ] = KEY_TV, // DVR
- [ 21 ] = KEY_DVD, // DVD
- [ 23 ] = KEY_AUDIO, // music
- // DVR mode / DVD mode / music mode
-
- [ 27 ] = KEY_MUTE, // mute
- [ 2 ] = KEY_LANGUAGE, // MTS/SAP / audio / autoseek
- [ 30 ] = KEY_SUBTITLE, // closed captioning / subtitle / seek
- [ 22 ] = KEY_ZOOM, // full screen
- [ 28 ] = KEY_VIDEO, // video source / eject / delall
- [ 29 ] = KEY_RESTART, // playback / angle / del
- [ 47 ] = KEY_SEARCH, // scan / menu / playlist
- [ 48 ] = KEY_CHANNEL, // CH surfing / bookmark / memo
-
- [ 49 ] = KEY_HELP, // help
- [ 50 ] = KEY_MODE, // num/memo
- [ 51 ] = KEY_ESC, // cancel
+ [ 18 ] = KEY_POWER,
+ [ 1 ] = KEY_TV, // DVR
+ [ 21 ] = KEY_DVD, // DVD
+ [ 23 ] = KEY_AUDIO, // music
+ // DVR mode / DVD mode / music mode
+
+ [ 27 ] = KEY_MUTE, // mute
+ [ 2 ] = KEY_LANGUAGE, // MTS/SAP / audio / autoseek
+ [ 30 ] = KEY_SUBTITLE, // closed captioning / subtitle / seek
+ [ 22 ] = KEY_ZOOM, // full screen
+ [ 28 ] = KEY_VIDEO, // video source / eject / delall
+ [ 29 ] = KEY_RESTART, // playback / angle / del
+ [ 47 ] = KEY_SEARCH, // scan / menu / playlist
+ [ 48 ] = KEY_CHANNEL, // CH surfing / bookmark / memo
+
+ [ 49 ] = KEY_HELP, // help
+ [ 50 ] = KEY_MODE, // num/memo
+ [ 51 ] = KEY_ESC, // cancel
[ 12 ] = KEY_UP, // up
[ 16 ] = KEY_DOWN, // down
@@ -148,24 +150,24 @@ static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = {
[ 45 ] = KEY_PLAY, // play
[ 46 ] = KEY_SHUFFLE, // snapshot / shuffle
- [ 0 ] = KEY_KP0,
- [ 5 ] = KEY_KP1,
- [ 6 ] = KEY_KP2,
- [ 7 ] = KEY_KP3,
- [ 9 ] = KEY_KP4,
- [ 10 ] = KEY_KP5,
- [ 11 ] = KEY_KP6,
- [ 13 ] = KEY_KP7,
- [ 14 ] = KEY_KP8,
- [ 15 ] = KEY_KP9,
-
- [ 42 ] = KEY_VOLUMEUP,
- [ 17 ] = KEY_VOLUMEDOWN,
- [ 24 ] = KEY_CHANNELUP, // CH.tracking up
- [ 25 ] = KEY_CHANNELDOWN, // CH.tracking down
-
- [ 19 ] = KEY_KPENTER, // enter
- [ 33 ] = KEY_KPDOT, // . (decimal dot)
+ [ 0 ] = KEY_KP0,
+ [ 5 ] = KEY_KP1,
+ [ 6 ] = KEY_KP2,
+ [ 7 ] = KEY_KP3,
+ [ 9 ] = KEY_KP4,
+ [ 10 ] = KEY_KP5,
+ [ 11 ] = KEY_KP6,
+ [ 13 ] = KEY_KP7,
+ [ 14 ] = KEY_KP8,
+ [ 15 ] = KEY_KP9,
+
+ [ 42 ] = KEY_VOLUMEUP,
+ [ 17 ] = KEY_VOLUMEDOWN,
+ [ 24 ] = KEY_CHANNELUP, // CH.tracking up
+ [ 25 ] = KEY_CHANNELDOWN, // CH.tracking down
+
+ [ 19 ] = KEY_KPENTER, // enter
+ [ 33 ] = KEY_KPDOT, // . (decimal dot)
};
static IR_KEYTAB_TYPE avacssmart_codes[IR_KEYTAB_SIZE] = {
@@ -401,7 +403,183 @@ static IR_KEYTAB_TYPE manli_codes[IR_KEYTAB_SIZE] = {
// 0x1d unused ?
};
-/* ---------------------------------------------------------------------- */
+
+
+/* Mike Baikov <mike@baikov.com> */
+static IR_KEYTAB_TYPE gotview7135_codes[IR_KEYTAB_SIZE] = {
+
+ [ 33 ] = KEY_POWER,
+ [ 105] = KEY_TV,
+ [ 51 ] = KEY_KP0,
+ [ 81 ] = KEY_KP1,
+ [ 49 ] = KEY_KP2,
+ [ 113] = KEY_KP3,
+ [ 59 ] = KEY_KP4,
+ [ 88 ] = KEY_KP5,
+ [ 65 ] = KEY_KP6,
+ [ 72 ] = KEY_KP7,
+ [ 48 ] = KEY_KP8,
+ [ 83 ] = KEY_KP9,
+ [ 115] = KEY_AGAIN, /* LOOP */
+ [ 10 ] = KEY_AUDIO,
+ [ 97 ] = KEY_PRINT, /* PREVIEW */
+ [ 122] = KEY_VIDEO,
+ [ 32 ] = KEY_CHANNELUP,
+ [ 64 ] = KEY_CHANNELDOWN,
+ [ 24 ] = KEY_VOLUMEDOWN,
+ [ 80 ] = KEY_VOLUMEUP,
+ [ 16 ] = KEY_MUTE,
+ [ 74 ] = KEY_SEARCH,
+ [ 123] = KEY_SHUFFLE, /* SNAPSHOT */
+ [ 34 ] = KEY_RECORD,
+ [ 98 ] = KEY_STOP,
+ [ 120] = KEY_PLAY,
+ [ 57 ] = KEY_REWIND,
+ [ 89 ] = KEY_PAUSE,
+ [ 25 ] = KEY_FORWARD,
+ [ 9 ] = KEY_ZOOM,
+
+ [ 82 ] = KEY_F21, /* LIVE TIMESHIFT */
+ [ 26 ] = KEY_F22, /* MIN TIMESHIFT */
+ [ 58 ] = KEY_F23, /* TIMESHIFT */
+ [ 112] = KEY_F24, /* NORMAL TIMESHIFT */
+};
+
+static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
+ [ 0x3 ] = KEY_POWER,
+ [ 0x6f ] = KEY_MUTE,
+ [ 0x10 ] = KEY_BACKSPACE, /* Recall */
+
+ [ 0x11 ] = KEY_KP0,
+ [ 0x4 ] = KEY_KP1,
+ [ 0x5 ] = KEY_KP2,
+ [ 0x6 ] = KEY_KP3,
+ [ 0x8 ] = KEY_KP4,
+ [ 0x9 ] = KEY_KP5,
+ [ 0xa ] = KEY_KP6,
+ [ 0xc ] = KEY_KP7,
+ [ 0xd ] = KEY_KP8,
+ [ 0xe ] = KEY_KP9,
+ [ 0x12 ] = KEY_KPDOT, /* 100+ */
+
+ [ 0x7 ] = KEY_VOLUMEUP,
+ [ 0xb ] = KEY_VOLUMEDOWN,
+ [ 0x1a ] = KEY_KPPLUS,
+ [ 0x18 ] = KEY_KPMINUS,
+ [ 0x15 ] = KEY_UP,
+ [ 0x1d ] = KEY_DOWN,
+ [ 0xf ] = KEY_CHANNELUP,
+ [ 0x13 ] = KEY_CHANNELDOWN,
+ [ 0x48 ] = KEY_ZOOM,
+
+ [ 0x1b ] = KEY_VIDEO, /* Video source */
+ [ 0x49 ] = KEY_LANGUAGE, /* MTS Select */
+ [ 0x19 ] = KEY_SEARCH, /* Auto Scan */
+
+ [ 0x4b ] = KEY_RECORD,
+ [ 0x46 ] = KEY_PLAY,
+ [ 0x45 ] = KEY_PAUSE, /* Pause */
+ [ 0x44 ] = KEY_STOP,
+ [ 0x40 ] = KEY_FORWARD, /* Forward ? */
+ [ 0x42 ] = KEY_REWIND, /* Backward ? */
+
+};
+
+static IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
+ [ 0x59 ] = KEY_MUTE,
+ [ 0x4a ] = KEY_POWER,
+
+ [ 0x18 ] = KEY_TEXT,
+ [ 0x26 ] = KEY_TV,
+ [ 0x3d ] = KEY_PRINT,
+
+ [ 0x48 ] = KEY_RED,
+ [ 0x04 ] = KEY_GREEN,
+ [ 0x11 ] = KEY_YELLOW,
+ [ 0x00 ] = KEY_BLUE,
+
+ [ 0x2d ] = KEY_VOLUMEUP,
+ [ 0x1e ] = KEY_VOLUMEDOWN,
+
+ [ 0x49 ] = KEY_MENU,
+
+ [ 0x16 ] = KEY_CHANNELUP,
+ [ 0x17 ] = KEY_CHANNELDOWN,
+
+ [ 0x20 ] = KEY_UP,
+ [ 0x21 ] = KEY_DOWN,
+ [ 0x22 ] = KEY_LEFT,
+ [ 0x23 ] = KEY_RIGHT,
+ [ 0x0d ] = KEY_SELECT,
+
+
+
+ [ 0x08 ] = KEY_BACK,
+ [ 0x07 ] = KEY_REFRESH,
+
+ [ 0x2f ] = KEY_ZOOM,
+ [ 0x29 ] = KEY_RECORD,
+
+ [ 0x4b ] = KEY_PAUSE,
+ [ 0x4d ] = KEY_REWIND,
+ [ 0x2e ] = KEY_PLAY,
+ [ 0x4e ] = KEY_FORWARD,
+ [ 0x53 ] = KEY_PREVIOUS,
+ [ 0x4c ] = KEY_STOP,
+ [ 0x54 ] = KEY_NEXT,
+
+ [ 0x69 ] = KEY_KP0,
+ [ 0x6a ] = KEY_KP1,
+ [ 0x6b ] = KEY_KP2,
+ [ 0x6c ] = KEY_KP3,
+ [ 0x6d ] = KEY_KP4,
+ [ 0x6e ] = KEY_KP5,
+ [ 0x6f ] = KEY_KP6,
+ [ 0x70 ] = KEY_KP7,
+ [ 0x71 ] = KEY_KP8,
+ [ 0x72 ] = KEY_KP9,
+
+ [ 0x74 ] = KEY_CHANNEL,
+ [ 0x0a ] = KEY_BACKSPACE,
+};
+
+/* Mapping for the 28 key remote control as seen at
+ http://www.sednacomputer.com/photo/cardbus-tv.jpg
+ Pavel Mihaylov <bin@bash.info> */
+static IR_KEYTAB_TYPE pctv_sedna_codes[IR_KEYTAB_SIZE] = {
+ [ 0 ] = KEY_KP0,
+ [ 1 ] = KEY_KP1,
+ [ 2 ] = KEY_KP2,
+ [ 3 ] = KEY_KP3,
+ [ 4 ] = KEY_KP4,
+ [ 5 ] = KEY_KP5,
+ [ 6 ] = KEY_KP6,
+ [ 7 ] = KEY_KP7,
+ [ 8 ] = KEY_KP8,
+ [ 9 ] = KEY_KP9,
+
+ [ 0x0a ] = KEY_AGAIN, /* Recall */
+ [ 0x0b ] = KEY_CHANNELUP,
+ [ 0x0c ] = KEY_VOLUMEUP,
+ [ 0x0d ] = KEY_MODE, /* Stereo */
+ [ 0x0e ] = KEY_STOP,
+ [ 0x0f ] = KEY_PREVIOUSSONG,
+ [ 0x10 ] = KEY_ZOOM,
+ [ 0x11 ] = KEY_TUNER, /* Source */
+ [ 0x12 ] = KEY_POWER,
+ [ 0x13 ] = KEY_MUTE,
+ [ 0x15 ] = KEY_CHANNELDOWN,
+ [ 0x18 ] = KEY_VOLUMEDOWN,
+ [ 0x19 ] = KEY_SHUFFLE, /* Snapshot */
+ [ 0x1a ] = KEY_NEXTSONG,
+ [ 0x1b ] = KEY_TEXT, /* Time Shift */
+ [ 0x1c ] = KEY_RADIO, /* FM Radio */
+ [ 0x1d ] = KEY_RECORD,
+ [ 0x1e ] = KEY_PAUSE,
+};
+
+
+/* -------------------- GPIO generic keycode builder -------------------- */
static int build_key(struct saa7134_dev *dev)
{
@@ -413,13 +591,13 @@ static int build_key(struct saa7134_dev *dev)
saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
- if (ir->polling) {
- if (ir->last_gpio == gpio)
- return 0;
- ir->last_gpio = gpio;
- }
+ if (ir->polling) {
+ if (ir->last_gpio == gpio)
+ return 0;
+ ir->last_gpio = gpio;
+ }
- data = ir_extract_bits(gpio, ir->mask_keycode);
+ data = ir_extract_bits(gpio, ir->mask_keycode);
dprintk("build_key gpio=0x%x mask=0x%x data=%d\n",
gpio, ir->mask_keycode, data);
@@ -432,13 +610,87 @@ static int build_key(struct saa7134_dev *dev)
return 0;
}
-/* ---------------------------------------------------------------------- */
+/* --------------------- Chip specific I2C key builders ----------------- */
+
+static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ unsigned char b;
+
+ /* poll IR chip */
+ if (1 != i2c_master_recv(&ir->c,&b,1)) {
+ i2cdprintk("read error\n");
+ return -EIO;
+ }
+
+ /* no button press */
+ if (b==0)
+ return 0;
+
+ /* repeating */
+ if (b & 0x80)
+ return 1;
+
+ *ir_key = b;
+ *ir_raw = b;
+ return 1;
+}
+
+/* The new pinnacle PCTV remote (with the colored buttons)
+ *
+ * Ricardo Cerqueira <v4l@cerqueira.org>
+ */
+
+static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ unsigned char b[4];
+ unsigned int start = 0,parity = 0,code = 0;
+
+ /* poll IR chip */
+ if (4 != i2c_master_recv(&ir->c,b,4)) {
+ i2cdprintk("read error\n");
+ return -EIO;
+ }
+
+ for (start = 0; start<4; start++) {
+ if (b[start] == 0x80) {
+ code=b[(start+3)%4];
+ parity=b[(start+2)%4];
+ }
+ }
+
+ /* Empty Request */
+ if (parity==0)
+ return 0;
+
+ /* Repeating... */
+ if (ir->old == parity)
+ return 0;
+
+
+ ir->old = parity;
+
+ /* Reduce code value to fit inside IR_KEYTAB_SIZE
+ *
+ * this is the only value that results in 42 unique
+ * codes < 128
+ */
+
+ code %= 0x88;
+
+ *ir_raw = code;
+ *ir_key = code;
+
+ i2cdprintk("Pinnacle PCTV key %02x\n", code);
+
+ return 1;
+}
+
void saa7134_input_irq(struct saa7134_dev *dev)
{
- struct saa7134_ir *ir = dev->remote;
+ struct saa7134_ir *ir = dev->remote;
- if (!ir->polling)
+ if (!ir->polling)
build_key(dev);
}
@@ -464,7 +716,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
int polling = 0;
int ir_type = IR_TYPE_OTHER;
- if (!dev->has_remote)
+ if (dev->has_remote != SAA7134_REMOTE_GPIO)
return -ENODEV;
if (disable_ir)
return -ENODEV;
@@ -473,7 +725,8 @@ int saa7134_input_init1(struct saa7134_dev *dev)
switch (dev->board) {
case SAA7134_BOARD_FLYVIDEO2000:
case SAA7134_BOARD_FLYVIDEO3000:
- case SAA7134_BOARD_FLYTVPLATINUM_FM:
+ case SAA7134_BOARD_FLYTVPLATINUM_FM:
+ case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
ir_codes = flyvideo_codes;
mask_keycode = 0xEC00000;
mask_keydown = 0x0040000;
@@ -514,14 +767,33 @@ int saa7134_input_init1(struct saa7134_dev *dev)
saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
break;
+ case SAA7134_BOARD_KWORLD_TERMINATOR:
+ ir_codes = avacssmart_codes;
+ mask_keycode = 0x00001f;
+ mask_keyup = 0x000060;
+ polling = 50; // ms
+ break;
case SAA7134_BOARD_MANLI_MTV001:
case SAA7134_BOARD_MANLI_MTV002:
+ case SAA7134_BOARD_BEHOLD_409FM:
ir_codes = manli_codes;
mask_keycode = 0x001f00;
mask_keyup = 0x004000;
- mask_keydown = 0x002000;
polling = 50; // ms
break;
+ case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
+ ir_codes = pctv_sedna_codes;
+ mask_keycode = 0x001f00;
+ mask_keyup = 0x004000;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_GOTVIEW_7135:
+ ir_codes = gotview7135_codes;
+ mask_keycode = 0x0003EC;
+ mask_keyup = 0x008000;
+ mask_keydown = 0x000010;
+ polling = 50; // ms
+ break;
case SAA7134_BOARD_VIDEOMATE_TV_PVR:
case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
ir_codes = videomate_tv_pvr_codes;
@@ -529,6 +801,12 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keyup = 0x400000;
polling = 50; // ms
break;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+ ir_codes = videomate_tv_pvr_codes;
+ mask_keycode = 0x003F00;
+ mask_keyup = 0x040000;
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
@@ -548,7 +826,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
ir->mask_keycode = mask_keycode;
ir->mask_keydown = mask_keydown;
ir->mask_keyup = mask_keyup;
- ir->polling = polling;
+ ir->polling = polling;
/* init input device */
snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
@@ -596,6 +874,31 @@ void saa7134_input_fini(struct saa7134_dev *dev)
dev->remote = NULL;
}
+void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
+{
+ if (disable_ir) {
+ dprintk("Found supported i2c remote, but IR has been disabled\n");
+ ir->get_key=NULL;
+ return;
+ }
+
+ switch (dev->board) {
+ case SAA7134_BOARD_PINNACLE_PCTV_110i:
+ snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV");
+ ir->get_key = get_key_pinnacle;
+ ir->ir_codes = ir_codes_pinnacle;
+ break;
+ case SAA7134_BOARD_UPMOST_PURPLE_TV:
+ snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV");
+ ir->get_key = get_key_purpletv;
+ ir->ir_codes = ir_codes_purpletv;
+ break;
+ default:
+ dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board);
+ break;
+ }
+
+}
/* ----------------------------------------------------------------------
* Local variables:
* c-basic-offset: 8
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
index c20630c82f1..fd53dfcc164 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -44,6 +44,7 @@ MODULE_PARM_DESC(oss_rate,"sample rate (valid are: 32000,48000)");
#define dprintk(fmt, arg...) if (oss_debug) \
printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg)
+
/* ------------------------------------------------------------------ */
static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
@@ -58,12 +59,12 @@ static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
if ((blksize * blocks) > 1024*1024)
blocks = 1024*1024 / blksize;
- dev->oss.blocks = blocks;
- dev->oss.blksize = blksize;
- dev->oss.bufsize = blksize * blocks;
+ dev->dmasound.blocks = blocks;
+ dev->dmasound.blksize = blksize;
+ dev->dmasound.bufsize = blksize * blocks;
dprintk("buffer config: %d blocks / %d bytes, %d kB total\n",
- blocks,blksize,blksize * blocks / 1024);
+ blocks,blksize,blksize * blocks / 1024);
return 0;
}
@@ -71,11 +72,11 @@ static int dsp_buffer_init(struct saa7134_dev *dev)
{
int err;
- if (!dev->oss.bufsize)
+ if (!dev->dmasound.bufsize)
BUG();
- videobuf_dma_init(&dev->oss.dma);
- err = videobuf_dma_init_kernel(&dev->oss.dma, PCI_DMA_FROMDEVICE,
- (dev->oss.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
+ videobuf_dma_init(&dev->dmasound.dma);
+ err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE,
+ (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
if (0 != err)
return err;
return 0;
@@ -83,26 +84,26 @@ static int dsp_buffer_init(struct saa7134_dev *dev)
static int dsp_buffer_free(struct saa7134_dev *dev)
{
- if (!dev->oss.blksize)
+ if (!dev->dmasound.blksize)
BUG();
- videobuf_dma_free(&dev->oss.dma);
- dev->oss.blocks = 0;
- dev->oss.blksize = 0;
- dev->oss.bufsize = 0;
+ videobuf_dma_free(&dev->dmasound.dma);
+ dev->dmasound.blocks = 0;
+ dev->dmasound.blksize = 0;
+ dev->dmasound.bufsize = 0;
return 0;
}
static void dsp_dma_start(struct saa7134_dev *dev)
{
- dev->oss.dma_blk = 0;
- dev->oss.dma_running = 1;
+ dev->dmasound.dma_blk = 0;
+ dev->dmasound.dma_running = 1;
saa7134_set_dmabits(dev);
}
static void dsp_dma_stop(struct saa7134_dev *dev)
{
- dev->oss.dma_blk = -1;
- dev->oss.dma_running = 0;
+ dev->dmasound.dma_blk = -1;
+ dev->dmasound.dma_running = 0;
saa7134_set_dmabits(dev);
}
@@ -113,18 +114,18 @@ static int dsp_rec_start(struct saa7134_dev *dev)
unsigned long flags;
/* prepare buffer */
- if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->oss.dma)))
+ if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->dmasound.dma)))
return err;
- if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->oss.pt)))
+ if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt)))
goto fail1;
- if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->oss.pt,
- dev->oss.dma.sglist,
- dev->oss.dma.sglen,
+ if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt,
+ dev->dmasound.dma.sglist,
+ dev->dmasound.dma.sglen,
0)))
goto fail2;
/* sample format */
- switch (dev->oss.afmt) {
+ switch (dev->dmasound.afmt) {
case AFMT_U8:
case AFMT_S8: fmt = 0x00; break;
case AFMT_U16_LE:
@@ -136,14 +137,14 @@ static int dsp_rec_start(struct saa7134_dev *dev)
goto fail2;
}
- switch (dev->oss.afmt) {
+ switch (dev->dmasound.afmt) {
case AFMT_S8:
case AFMT_S16_LE:
case AFMT_S16_BE: sign = 1; break;
default: sign = 0; break;
}
- switch (dev->oss.afmt) {
+ switch (dev->dmasound.afmt) {
case AFMT_U16_BE:
case AFMT_S16_BE: bswap = 1; break;
default: bswap = 0; break;
@@ -151,58 +152,58 @@ static int dsp_rec_start(struct saa7134_dev *dev)
switch (dev->pci->device) {
case PCI_DEVICE_ID_PHILIPS_SAA7134:
- if (1 == dev->oss.channels)
+ if (1 == dev->dmasound.channels)
fmt |= (1 << 3);
- if (2 == dev->oss.channels)
+ if (2 == dev->dmasound.channels)
fmt |= (3 << 3);
if (sign)
fmt |= 0x04;
- fmt |= (TV == dev->oss.input) ? 0xc0 : 0x80;
+ fmt |= (TV == dev->dmasound.input) ? 0xc0 : 0x80;
- saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->oss.blksize - 1) & 0x0000ff));
- saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->oss.blksize - 1) & 0x00ff00) >> 8);
- saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->oss.blksize - 1) & 0xff0000) >> 16);
+ saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff));
+ saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >> 8);
+ saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16);
saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
break;
case PCI_DEVICE_ID_PHILIPS_SAA7133:
case PCI_DEVICE_ID_PHILIPS_SAA7135:
- if (1 == dev->oss.channels)
+ if (1 == dev->dmasound.channels)
fmt |= (1 << 4);
- if (2 == dev->oss.channels)
+ if (2 == dev->dmasound.channels)
fmt |= (2 << 4);
if (!sign)
fmt |= 0x04;
- saa_writel(0x588 >> 2, dev->oss.blksize -4);
- saa_writel(0x58c >> 2, 0x543210 | (fmt << 24));
+ saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -4);
+ saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24));
break;
}
dprintk("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n",
- dev->oss.afmt, dev->oss.channels, fmt,
+ dev->dmasound.afmt, dev->dmasound.channels, fmt,
bswap ? 'b' : '-');
/* dma: setup channel 6 (= AUDIO) */
control = SAA7134_RS_CONTROL_BURST_16 |
SAA7134_RS_CONTROL_ME |
- (dev->oss.pt.dma >> 12);
+ (dev->dmasound.pt.dma >> 12);
if (bswap)
control |= SAA7134_RS_CONTROL_BSWAP;
saa_writel(SAA7134_RS_BA1(6),0);
- saa_writel(SAA7134_RS_BA2(6),dev->oss.blksize);
+ saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize);
saa_writel(SAA7134_RS_PITCH(6),0);
saa_writel(SAA7134_RS_CONTROL(6),control);
/* start dma */
- dev->oss.recording_on = 1;
+ dev->dmasound.recording_on = 1;
spin_lock_irqsave(&dev->slock,flags);
dsp_dma_start(dev);
spin_unlock_irqrestore(&dev->slock,flags);
return 0;
fail2:
- saa7134_pgtable_free(dev->pci,&dev->oss.pt);
+ saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
fail1:
- videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma);
+ videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
return err;
}
@@ -210,17 +211,17 @@ static int dsp_rec_stop(struct saa7134_dev *dev)
{
unsigned long flags;
- dprintk("rec_stop dma_blk=%d\n",dev->oss.dma_blk);
+ dprintk("rec_stop dma_blk=%d\n",dev->dmasound.dma_blk);
/* stop dma */
- dev->oss.recording_on = 0;
+ dev->dmasound.recording_on = 0;
spin_lock_irqsave(&dev->slock,flags);
dsp_dma_stop(dev);
spin_unlock_irqrestore(&dev->slock,flags);
/* unlock buffer */
- saa7134_pgtable_free(dev->pci,&dev->oss.pt);
- videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma);
+ saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
+ videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
return 0;
}
@@ -235,35 +236,35 @@ static int dsp_open(struct inode *inode, struct file *file)
list_for_each(list,&saa7134_devlist) {
h = list_entry(list, struct saa7134_dev, devlist);
- if (h->oss.minor_dsp == minor)
+ if (h->dmasound.minor_dsp == minor)
dev = h;
}
if (NULL == dev)
return -ENODEV;
- down(&dev->oss.lock);
+ down(&dev->dmasound.lock);
err = -EBUSY;
- if (dev->oss.users_dsp)
+ if (dev->dmasound.users_dsp)
goto fail1;
- dev->oss.users_dsp++;
+ dev->dmasound.users_dsp++;
file->private_data = dev;
- dev->oss.afmt = AFMT_U8;
- dev->oss.channels = 1;
- dev->oss.read_count = 0;
- dev->oss.read_offset = 0;
+ dev->dmasound.afmt = AFMT_U8;
+ dev->dmasound.channels = 1;
+ dev->dmasound.read_count = 0;
+ dev->dmasound.read_offset = 0;
dsp_buffer_conf(dev,PAGE_SIZE,64);
err = dsp_buffer_init(dev);
if (0 != err)
goto fail2;
- up(&dev->oss.lock);
+ up(&dev->dmasound.lock);
return 0;
fail2:
- dev->oss.users_dsp--;
+ dev->dmasound.users_dsp--;
fail1:
- up(&dev->oss.lock);
+ up(&dev->dmasound.lock);
return err;
}
@@ -271,13 +272,13 @@ static int dsp_release(struct inode *inode, struct file *file)
{
struct saa7134_dev *dev = file->private_data;
- down(&dev->oss.lock);
- if (dev->oss.recording_on)
+ down(&dev->dmasound.lock);
+ if (dev->dmasound.recording_on)
dsp_rec_stop(dev);
dsp_buffer_free(dev);
- dev->oss.users_dsp--;
+ dev->dmasound.users_dsp--;
file->private_data = NULL;
- up(&dev->oss.lock);
+ up(&dev->dmasound.lock);
return 0;
}
@@ -290,12 +291,12 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
unsigned long flags;
int err,ret = 0;
- add_wait_queue(&dev->oss.wq, &wait);
- down(&dev->oss.lock);
+ add_wait_queue(&dev->dmasound.wq, &wait);
+ down(&dev->dmasound.lock);
while (count > 0) {
/* wait for data if needed */
- if (0 == dev->oss.read_count) {
- if (!dev->oss.recording_on) {
+ if (0 == dev->dmasound.read_count) {
+ if (!dev->dmasound.recording_on) {
err = dsp_rec_start(dev);
if (err < 0) {
if (0 == ret)
@@ -303,8 +304,8 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
break;
}
}
- if (dev->oss.recording_on &&
- !dev->oss.dma_running) {
+ if (dev->dmasound.recording_on &&
+ !dev->dmasound.dma_running) {
/* recover from overruns */
spin_lock_irqsave(&dev->slock,flags);
dsp_dma_start(dev);
@@ -315,12 +316,12 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
ret = -EAGAIN;
break;
}
- up(&dev->oss.lock);
+ up(&dev->dmasound.lock);
set_current_state(TASK_INTERRUPTIBLE);
- if (0 == dev->oss.read_count)
+ if (0 == dev->dmasound.read_count)
schedule();
set_current_state(TASK_RUNNING);
- down(&dev->oss.lock);
+ down(&dev->dmasound.lock);
if (signal_pending(current)) {
if (0 == ret)
ret = -EINTR;
@@ -330,12 +331,12 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
/* copy data to userspace */
bytes = count;
- if (bytes > dev->oss.read_count)
- bytes = dev->oss.read_count;
- if (bytes > dev->oss.bufsize - dev->oss.read_offset)
- bytes = dev->oss.bufsize - dev->oss.read_offset;
+ if (bytes > dev->dmasound.read_count)
+ bytes = dev->dmasound.read_count;
+ if (bytes > dev->dmasound.bufsize - dev->dmasound.read_offset)
+ bytes = dev->dmasound.bufsize - dev->dmasound.read_offset;
if (copy_to_user(buffer + ret,
- dev->oss.dma.vmalloc + dev->oss.read_offset,
+ dev->dmasound.dma.vmalloc + dev->dmasound.read_offset,
bytes)) {
if (0 == ret)
ret = -EFAULT;
@@ -344,13 +345,13 @@ static ssize_t dsp_read(struct file *file, char __user *buffer,
ret += bytes;
count -= bytes;
- dev->oss.read_count -= bytes;
- dev->oss.read_offset += bytes;
- if (dev->oss.read_offset == dev->oss.bufsize)
- dev->oss.read_offset = 0;
+ dev->dmasound.read_count -= bytes;
+ dev->dmasound.read_offset += bytes;
+ if (dev->dmasound.read_offset == dev->dmasound.bufsize)
+ dev->dmasound.read_offset = 0;
}
- up(&dev->oss.lock);
- remove_wait_queue(&dev->oss.wq, &wait);
+ up(&dev->dmasound.lock);
+ remove_wait_queue(&dev->dmasound.wq, &wait);
return ret;
}
@@ -370,53 +371,53 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
if (oss_debug > 1)
saa7134_print_ioctl(dev->name,cmd);
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
- case SNDCTL_DSP_GETCAPS:
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, p);
+ case SNDCTL_DSP_GETCAPS:
return 0;
- case SNDCTL_DSP_SPEED:
+ case SNDCTL_DSP_SPEED:
if (get_user(val, p))
return -EFAULT;
/* fall through */
- case SOUND_PCM_READ_RATE:
- return put_user(dev->oss.rate, p);
+ case SOUND_PCM_READ_RATE:
+ return put_user(dev->dmasound.rate, p);
- case SNDCTL_DSP_STEREO:
+ case SNDCTL_DSP_STEREO:
if (get_user(val, p))
return -EFAULT;
- down(&dev->oss.lock);
- dev->oss.channels = val ? 2 : 1;
- if (dev->oss.recording_on) {
+ down(&dev->dmasound.lock);
+ dev->dmasound.channels = val ? 2 : 1;
+ if (dev->dmasound.recording_on) {
dsp_rec_stop(dev);
dsp_rec_start(dev);
}
- up(&dev->oss.lock);
- return put_user(dev->oss.channels-1, p);
+ up(&dev->dmasound.lock);
+ return put_user(dev->dmasound.channels-1, p);
- case SNDCTL_DSP_CHANNELS:
+ case SNDCTL_DSP_CHANNELS:
if (get_user(val, p))
return -EFAULT;
if (val != 1 && val != 2)
return -EINVAL;
- down(&dev->oss.lock);
- dev->oss.channels = val;
- if (dev->oss.recording_on) {
+ down(&dev->dmasound.lock);
+ dev->dmasound.channels = val;
+ if (dev->dmasound.recording_on) {
dsp_rec_stop(dev);
dsp_rec_start(dev);
}
- up(&dev->oss.lock);
+ up(&dev->dmasound.lock);
/* fall through */
- case SOUND_PCM_READ_CHANNELS:
- return put_user(dev->oss.channels, p);
+ case SOUND_PCM_READ_CHANNELS:
+ return put_user(dev->dmasound.channels, p);
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+ case SNDCTL_DSP_GETFMTS: /* Returns a mask */
return put_user(AFMT_U8 | AFMT_S8 |
AFMT_U16_LE | AFMT_U16_BE |
AFMT_S16_LE | AFMT_S16_BE, p);
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
+ case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
if (get_user(val, p))
return -EFAULT;
switch (val) {
@@ -429,20 +430,20 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
case AFMT_U16_BE:
case AFMT_S16_LE:
case AFMT_S16_BE:
- down(&dev->oss.lock);
- dev->oss.afmt = val;
- if (dev->oss.recording_on) {
+ down(&dev->dmasound.lock);
+ dev->dmasound.afmt = val;
+ if (dev->dmasound.recording_on) {
dsp_rec_stop(dev);
dsp_rec_start(dev);
}
- up(&dev->oss.lock);
- return put_user(dev->oss.afmt, p);
+ up(&dev->dmasound.lock);
+ return put_user(dev->dmasound.afmt, p);
default:
return -EINVAL;
}
- case SOUND_PCM_READ_BITS:
- switch (dev->oss.afmt) {
+ case SOUND_PCM_READ_BITS:
+ switch (dev->dmasound.afmt) {
case AFMT_U8:
case AFMT_S8:
return put_user(8, p);
@@ -455,23 +456,23 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
}
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
+ return 0;
- case SNDCTL_DSP_RESET:
- down(&dev->oss.lock);
- if (dev->oss.recording_on)
+ case SNDCTL_DSP_RESET:
+ down(&dev->dmasound.lock);
+ if (dev->dmasound.recording_on)
dsp_rec_stop(dev);
- up(&dev->oss.lock);
+ up(&dev->dmasound.lock);
return 0;
- case SNDCTL_DSP_GETBLKSIZE:
- return put_user(dev->oss.blksize, p);
+ case SNDCTL_DSP_GETBLKSIZE:
+ return put_user(dev->dmasound.blksize, p);
- case SNDCTL_DSP_SETFRAGMENT:
+ case SNDCTL_DSP_SETFRAGMENT:
if (get_user(val, p))
return -EFAULT;
- if (dev->oss.recording_on)
+ if (dev->dmasound.recording_on)
return -EBUSY;
dsp_buffer_free(dev);
/* used to be arg >> 16 instead of val >> 16; fixed */
@@ -479,16 +480,16 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
dsp_buffer_init(dev);
return 0;
- case SNDCTL_DSP_SYNC:
+ case SNDCTL_DSP_SYNC:
/* NOP */
return 0;
case SNDCTL_DSP_GETISPACE:
{
audio_buf_info info;
- info.fragsize = dev->oss.blksize;
- info.fragstotal = dev->oss.blocks;
- info.bytes = dev->oss.read_count;
+ info.fragsize = dev->dmasound.blksize;
+ info.fragstotal = dev->dmasound.blocks;
+ info.bytes = dev->dmasound.read_count;
info.fragments = info.bytes / info.fragsize;
if (copy_to_user(argp, &info, sizeof(info)))
return -EFAULT;
@@ -504,13 +505,13 @@ static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait)
struct saa7134_dev *dev = file->private_data;
unsigned int mask = 0;
- poll_wait(file, &dev->oss.wq, wait);
+ poll_wait(file, &dev->dmasound.wq, wait);
- if (0 == dev->oss.read_count) {
- down(&dev->oss.lock);
- if (!dev->oss.recording_on)
+ if (0 == dev->dmasound.read_count) {
+ down(&dev->dmasound.lock);
+ if (!dev->dmasound.recording_on)
dsp_rec_start(dev);
- up(&dev->oss.lock);
+ up(&dev->dmasound.lock);
} else
mask |= (POLLIN | POLLRDNORM);
return mask;
@@ -534,7 +535,7 @@ mixer_recsrc_7134(struct saa7134_dev *dev)
{
int analog_io,rate;
- switch (dev->oss.input) {
+ switch (dev->dmasound.input) {
case TV:
saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x00);
@@ -542,8 +543,8 @@ mixer_recsrc_7134(struct saa7134_dev *dev)
case LINE1:
case LINE2:
case LINE2_LEFT:
- analog_io = (LINE1 == dev->oss.input) ? 0x00 : 0x08;
- rate = (32000 == dev->oss.rate) ? 0x01 : 0x03;
+ analog_io = (LINE1 == dev->dmasound.input) ? 0x00 : 0x08;
+ rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03;
saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, analog_io);
saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80);
saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate);
@@ -559,10 +560,10 @@ mixer_recsrc_7133(struct saa7134_dev *dev)
xbarin = 0x03; // adc
anabar = 0;
- switch (dev->oss.input) {
+ switch (dev->dmasound.input) {
case TV:
xbarin = 0; // Demodulator
- anabar = 2; // DACs
+ anabar = 2; // DACs
break;
case LINE1:
anabar = 0; // aux1, aux1
@@ -585,9 +586,9 @@ mixer_recsrc(struct saa7134_dev *dev, enum saa7134_audio_in src)
{
static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" };
- dev->oss.count++;
- dev->oss.input = src;
- dprintk("mixer input = %s\n",iname[dev->oss.input]);
+ dev->dmasound.count++;
+ dev->dmasound.input = src;
+ dprintk("mixer input = %s\n",iname[dev->dmasound.input]);
switch (dev->pci->device) {
case PCI_DEVICE_ID_PHILIPS_SAA7134:
@@ -639,7 +640,7 @@ static int mixer_open(struct inode *inode, struct file *file)
list_for_each(list,&saa7134_devlist) {
h = list_entry(list, struct saa7134_dev, devlist);
- if (h->oss.minor_mixer == minor)
+ if (h->dmasound.minor_mixer == minor)
dev = h;
}
if (NULL == dev)
@@ -666,28 +667,28 @@ static int mixer_ioctl(struct inode *inode, struct file *file,
if (oss_debug > 1)
saa7134_print_ioctl(dev->name,cmd);
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, p);
case SOUND_MIXER_INFO:
{
mixer_info info;
memset(&info,0,sizeof(info));
- strlcpy(info.id, "TV audio", sizeof(info.id));
- strlcpy(info.name, dev->name, sizeof(info.name));
- info.modify_counter = dev->oss.count;
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
+ strlcpy(info.id, "TV audio", sizeof(info.id));
+ strlcpy(info.name, dev->name, sizeof(info.name));
+ info.modify_counter = dev->dmasound.count;
+ if (copy_to_user(argp, &info, sizeof(info)))
+ return -EFAULT;
return 0;
}
case SOUND_OLD_MIXER_INFO:
{
_old_mixer_info info;
memset(&info,0,sizeof(info));
- strlcpy(info.id, "TV audio", sizeof(info.id));
- strlcpy(info.name, dev->name, sizeof(info.name));
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
+ strlcpy(info.id, "TV audio", sizeof(info.id));
+ strlcpy(info.name, dev->name, sizeof(info.name));
+ if (copy_to_user(argp, &info, sizeof(info)))
+ return -EFAULT;
return 0;
}
case MIXER_READ(SOUND_MIXER_CAPS):
@@ -697,26 +698,26 @@ static int mixer_ioctl(struct inode *inode, struct file *file,
case MIXER_READ(SOUND_MIXER_RECMASK):
case MIXER_READ(SOUND_MIXER_DEVMASK):
val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2;
- if (32000 == dev->oss.rate)
+ if (32000 == dev->dmasound.rate)
val |= SOUND_MASK_VIDEO;
return put_user(val, p);
case MIXER_WRITE(SOUND_MIXER_RECSRC):
if (get_user(val, p))
return -EFAULT;
- input = dev->oss.input;
- if (32000 == dev->oss.rate &&
- val & SOUND_MASK_VIDEO && dev->oss.input != TV)
+ input = dev->dmasound.input;
+ if (32000 == dev->dmasound.rate &&
+ val & SOUND_MASK_VIDEO && dev->dmasound.input != TV)
input = TV;
- if (val & SOUND_MASK_LINE1 && dev->oss.input != LINE1)
+ if (val & SOUND_MASK_LINE1 && dev->dmasound.input != LINE1)
input = LINE1;
- if (val & SOUND_MASK_LINE2 && dev->oss.input != LINE2)
+ if (val & SOUND_MASK_LINE2 && dev->dmasound.input != LINE2)
input = LINE2;
- if (input != dev->oss.input)
+ if (input != dev->dmasound.input)
mixer_recsrc(dev,input);
/* fall throuth */
case MIXER_READ(SOUND_MIXER_RECSRC):
- switch (dev->oss.input) {
+ switch (dev->dmasound.input) {
case TV: ret = SOUND_MASK_VIDEO; break;
case LINE1: ret = SOUND_MASK_LINE1; break;
case LINE2: ret = SOUND_MASK_LINE2; break;
@@ -726,7 +727,7 @@ static int mixer_ioctl(struct inode *inode, struct file *file,
case MIXER_WRITE(SOUND_MIXER_VIDEO):
case MIXER_READ(SOUND_MIXER_VIDEO):
- if (32000 != dev->oss.rate)
+ if (32000 != dev->dmasound.rate)
return -EINVAL;
return put_user(100 | 100 << 8, p);
@@ -735,22 +736,22 @@ static int mixer_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
val &= 0xff;
val = (val <= 50) ? 50 : 100;
- dev->oss.line1 = val;
- mixer_level(dev,LINE1,dev->oss.line1);
+ dev->dmasound.line1 = val;
+ mixer_level(dev,LINE1,dev->dmasound.line1);
/* fall throuth */
case MIXER_READ(SOUND_MIXER_LINE1):
- return put_user(dev->oss.line1 | dev->oss.line1 << 8, p);
+ return put_user(dev->dmasound.line1 | dev->dmasound.line1 << 8, p);
case MIXER_WRITE(SOUND_MIXER_LINE2):
if (get_user(val, p))
return -EFAULT;
val &= 0xff;
val = (val <= 50) ? 50 : 100;
- dev->oss.line2 = val;
- mixer_level(dev,LINE2,dev->oss.line2);
+ dev->dmasound.line2 = val;
+ mixer_level(dev,LINE2,dev->dmasound.line2);
/* fall throuth */
case MIXER_READ(SOUND_MIXER_LINE2):
- return put_user(dev->oss.line2 | dev->oss.line2 << 8, p);
+ return put_user(dev->dmasound.line2 | dev->dmasound.line2 << 8, p);
default:
return -EINVAL;
@@ -770,8 +771,8 @@ struct file_operations saa7134_mixer_fops = {
int saa7134_oss_init1(struct saa7134_dev *dev)
{
/* general */
- init_MUTEX(&dev->oss.lock);
- init_waitqueue_head(&dev->oss.wq);
+ init_MUTEX(&dev->dmasound.lock);
+ init_waitqueue_head(&dev->dmasound.wq);
switch (dev->pci->device) {
case PCI_DEVICE_ID_PHILIPS_SAA7133:
@@ -783,17 +784,17 @@ int saa7134_oss_init1(struct saa7134_dev *dev)
}
/* dsp */
- dev->oss.rate = 32000;
+ dev->dmasound.rate = 32000;
if (oss_rate)
- dev->oss.rate = oss_rate;
- dev->oss.rate = (dev->oss.rate > 40000) ? 48000 : 32000;
+ dev->dmasound.rate = oss_rate;
+ dev->dmasound.rate = (dev->dmasound.rate > 40000) ? 48000 : 32000;
/* mixer */
- dev->oss.line1 = 50;
- dev->oss.line2 = 50;
- mixer_level(dev,LINE1,dev->oss.line1);
- mixer_level(dev,LINE2,dev->oss.line2);
- mixer_recsrc(dev, (dev->oss.rate == 32000) ? TV : LINE2);
+ dev->dmasound.line1 = 50;
+ dev->dmasound.line2 = 50;
+ mixer_level(dev,LINE1,dev->dmasound.line1);
+ mixer_level(dev,LINE2,dev->dmasound.line2);
+ mixer_recsrc(dev, (dev->dmasound.rate == 32000) ? TV : LINE2);
return 0;
}
@@ -809,7 +810,7 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
int next_blk, reg = 0;
spin_lock(&dev->slock);
- if (UNSET == dev->oss.dma_blk) {
+ if (UNSET == dev->dmasound.dma_blk) {
dprintk("irq: recording stopped\n");
goto done;
}
@@ -817,11 +818,11 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
dprintk("irq: lost %ld\n", (status >> 24) & 0x0f);
if (0 == (status & 0x10000000)) {
/* odd */
- if (0 == (dev->oss.dma_blk & 0x01))
+ if (0 == (dev->dmasound.dma_blk & 0x01))
reg = SAA7134_RS_BA1(6);
} else {
/* even */
- if (1 == (dev->oss.dma_blk & 0x01))
+ if (1 == (dev->dmasound.dma_blk & 0x01))
reg = SAA7134_RS_BA2(6);
}
if (0 == reg) {
@@ -829,25 +830,25 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
(status & 0x10000000) ? "even" : "odd");
goto done;
}
- if (dev->oss.read_count >= dev->oss.blksize * (dev->oss.blocks-2)) {
- dprintk("irq: overrun [full=%d/%d]\n",dev->oss.read_count,
- dev->oss.bufsize);
+ if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) {
+ dprintk("irq: overrun [full=%d/%d]\n",dev->dmasound.read_count,
+ dev->dmasound.bufsize);
dsp_dma_stop(dev);
goto done;
}
/* next block addr */
- next_blk = (dev->oss.dma_blk + 2) % dev->oss.blocks;
- saa_writel(reg,next_blk * dev->oss.blksize);
+ next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks;
+ saa_writel(reg,next_blk * dev->dmasound.blksize);
if (oss_debug > 2)
dprintk("irq: ok, %s, next_blk=%d, addr=%x\n",
(status & 0x10000000) ? "even" : "odd ", next_blk,
- next_blk * dev->oss.blksize);
+ next_blk * dev->dmasound.blksize);
/* update status & wake waiting readers */
- dev->oss.dma_blk = (dev->oss.dma_blk + 1) % dev->oss.blocks;
- dev->oss.read_count += dev->oss.blksize;
- wake_up(&dev->oss.wq);
+ dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks;
+ dev->dmasound.read_count += dev->dmasound.blksize;
+ wake_up(&dev->dmasound.wq);
done:
spin_unlock(&dev->slock);
diff --git a/drivers/media/video/saa7134/saa7134-reg.h b/drivers/media/video/saa7134/saa7134-reg.h
index ae0c7a16539..ac6431ba4fc 100644
--- a/drivers/media/video/saa7134/saa7134-reg.h
+++ b/drivers/media/video/saa7134/saa7134-reg.h
@@ -27,7 +27,7 @@
/* DMA channels, n = 0 ... 6 */
#define SAA7134_RS_BA1(n) ((0x200 >> 2) + 4*n)
-#define SAA7134_RS_BA2(n) ((0x204 >> 2) + 4*n)
+#define SAA7134_RS_BA2(n) ((0x204 >> 2) + 4*n)
#define SAA7134_RS_PITCH(n) ((0x208 >> 2) + 4*n)
#define SAA7134_RS_CONTROL(n) ((0x20c >> 2) + 4*n)
#define SAA7134_RS_CONTROL_WSWAP (0x01 << 25)
@@ -43,16 +43,24 @@
#define SAA7134_FIFO_SIZE (0x2a0 >> 2)
#define SAA7134_THRESHOULD (0x2a4 >> 2)
+#define SAA7133_NUM_SAMPLES (0x588 >> 2)
+#define SAA7133_AUDIO_CHANNEL (0x58c >> 2)
+#define SAA7133_AUDIO_FORMAT (0x58f >> 2)
+#define SAA7133_DIGITAL_OUTPUT_SEL1 (0x46c >> 2)
+#define SAA7133_DIGITAL_OUTPUT_SEL2 (0x470 >> 2)
+#define SAA7133_DIGITAL_INPUT_XBAR1 (0x464 >> 2)
+#define SAA7133_ANALOG_IO_SELECT (0x594 >> 2)
+
/* main control */
#define SAA7134_MAIN_CTRL (0x2a8 >> 2)
-#define SAA7134_MAIN_CTRL_VPLLE (1 << 15)
-#define SAA7134_MAIN_CTRL_APLLE (1 << 14)
-#define SAA7134_MAIN_CTRL_EXOSC (1 << 13)
-#define SAA7134_MAIN_CTRL_EVFE1 (1 << 12)
-#define SAA7134_MAIN_CTRL_EVFE2 (1 << 11)
-#define SAA7134_MAIN_CTRL_ESFE (1 << 10)
-#define SAA7134_MAIN_CTRL_EBADC (1 << 9)
-#define SAA7134_MAIN_CTRL_EBDAC (1 << 8)
+#define SAA7134_MAIN_CTRL_VPLLE (1 << 15)
+#define SAA7134_MAIN_CTRL_APLLE (1 << 14)
+#define SAA7134_MAIN_CTRL_EXOSC (1 << 13)
+#define SAA7134_MAIN_CTRL_EVFE1 (1 << 12)
+#define SAA7134_MAIN_CTRL_EVFE2 (1 << 11)
+#define SAA7134_MAIN_CTRL_ESFE (1 << 10)
+#define SAA7134_MAIN_CTRL_EBADC (1 << 9)
+#define SAA7134_MAIN_CTRL_EBDAC (1 << 8)
#define SAA7134_MAIN_CTRL_TE6 (1 << 6)
#define SAA7134_MAIN_CTRL_TE5 (1 << 5)
#define SAA7134_MAIN_CTRL_TE4 (1 << 4)
@@ -348,6 +356,7 @@
/* test modes */
#define SAA7134_SPECIAL_MODE 0x1d0
+#define SAA7134_PRODUCTION_TEST_MODE 0x1d1
/* audio -- saa7133 + saa7135 only */
#define SAA7135_DSP_RWSTATE 0x580
diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
index 463885601ab..470903e2f5e 100644
--- a/drivers/media/video/saa7134/saa7134-ts.c
+++ b/drivers/media/video/saa7134/saa7134-ts.c
@@ -46,17 +46,11 @@ static int buffer_activate(struct saa7134_dev *dev,
struct saa7134_buf *buf,
struct saa7134_buf *next)
{
- u32 control;
dprintk("buffer_activate [%p]",buf);
buf->vb.state = STATE_ACTIVE;
buf->top_seen = 0;
- /* dma: setup channel 5 (= TS) */
- control = SAA7134_RS_CONTROL_BURST_16 |
- SAA7134_RS_CONTROL_ME |
- (buf->pt->dma >> 12);
-
if (NULL == next)
next = buf;
if (V4L2_FIELD_TOP == buf->vb.field) {
@@ -68,8 +62,6 @@ static int buffer_activate(struct saa7134_dev *dev,
saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next));
saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf));
}
- saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE);
- saa_writel(SAA7134_RS_CONTROL(5),control);
/* start DMA */
saa7134_set_dmabits(dev);
@@ -84,6 +76,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
struct saa7134_dev *dev = q->priv_data;
struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
unsigned int lines, llength, size;
+ u32 control;
int err;
dprintk("buffer_prepare [%p,%s]\n",buf,v4l2_field_names[field]);
@@ -115,6 +108,18 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
if (err)
goto oops;
}
+
+ /* dma: setup channel 5 (= TS) */
+ control = SAA7134_RS_CONTROL_BURST_16 |
+ SAA7134_RS_CONTROL_ME |
+ (buf->pt->dma >> 12);
+
+ saa_writeb(SAA7134_TS_DMA0, ((lines-1)&0xff));
+ saa_writeb(SAA7134_TS_DMA1, (((lines-1)>>8)&0xff));
+ saa_writeb(SAA7134_TS_DMA2, ((((lines-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */
+ saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE);
+ saa_writel(SAA7134_RS_CONTROL(5),control);
+
buf->vb.state = STATE_PREPARED;
buf->activate = buffer_activate;
buf->vb.field = field;
@@ -164,11 +169,11 @@ EXPORT_SYMBOL_GPL(saa7134_ts_qops);
/* ----------------------------------------------------------- */
/* exported stuff */
-static unsigned int tsbufs = 4;
+static unsigned int tsbufs = 8;
module_param(tsbufs, int, 0444);
MODULE_PARM_DESC(tsbufs,"number of ts buffers, range 2-32");
-static unsigned int ts_nr_packets = 30;
+static unsigned int ts_nr_packets = 64;
module_param(ts_nr_packets, int, 0444);
MODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)");
@@ -220,10 +225,10 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)
if (dev->ts_q.curr) {
field = dev->ts_q.curr->vb.field;
if (field == V4L2_FIELD_TOP) {
- if ((status & 0x100000) != 0x100000)
+ if ((status & 0x100000) != 0x000000)
goto done;
} else {
- if ((status & 0x100000) != 0x000000)
+ if ((status & 0x100000) != 0x100000)
goto done;
}
saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE);
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index 61a2d6b50ee..93268427750 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -207,6 +207,10 @@ static void tvaudio_setcarrier(struct saa7134_dev *dev,
saa_writel(SAA7134_CARRIER2_FREQ0 >> 2, tvaudio_carr2reg(secondary));
}
+#define SAA7134_MUTE_MASK 0xbb
+#define SAA7134_MUTE_ANALOG 0x04
+#define SAA7134_MUTE_I2S 0x40
+
static void mute_input_7134(struct saa7134_dev *dev)
{
unsigned int mute;
@@ -241,7 +245,11 @@ static void mute_input_7134(struct saa7134_dev *dev)
if (PCI_DEVICE_ID_PHILIPS_SAA7134 == dev->pci->device)
/* 7134 mute */
- saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ? 0xbf : 0xbb);
+ saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ?
+ SAA7134_MUTE_MASK |
+ SAA7134_MUTE_ANALOG |
+ SAA7134_MUTE_I2S :
+ SAA7134_MUTE_MASK);
/* switch internal audio mux */
switch (in->amux) {
@@ -753,17 +761,17 @@ static int mute_input_7133(struct saa7134_dev *dev)
/* switch gpio-connected external audio mux */
- if (0 != card(dev).gpiomask) {
- mask = card(dev).gpiomask;
+ if (0 != card(dev).gpiomask) {
+ mask = card(dev).gpiomask;
if (card(dev).mute.name && dev->ctl_mute)
in = &card(dev).mute;
else
in = dev->input;
- saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask);
- saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);
- saa7134_track_gpio(dev,in->name);
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);
+ saa7134_track_gpio(dev,in->name);
}
return 0;
@@ -1016,9 +1024,12 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
return 0;
}
+EXPORT_SYMBOL(saa_dsp_writel);
+
/* ----------------------------------------------------------- */
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
+
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 35e5e85f669..45c852df13e 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -30,6 +30,9 @@
#include "saa7134-reg.h"
#include "saa7134.h"
+/* Include V4L1 specific functions. Should be removed soon */
+#include <linux/videodev.h>
+
/* ------------------------------------------------------------------ */
static unsigned int video_debug = 0;
@@ -48,6 +51,43 @@ MODULE_PARM_DESC(noninterlaced,"video input is noninterlaced");
printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg)
/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x191 */
+
+/* Bit 0: VIP code T bit polarity */
+
+#define VP_T_CODE_P_NON_INVERTED 0x00
+#define VP_T_CODE_P_INVERTED 0x01
+
+/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x195 */
+
+/* Bit 2: Video output clock delay control */
+
+#define VP_CLK_CTRL2_NOT_DELAYED 0x00
+#define VP_CLK_CTRL2_DELAYED 0x04
+
+/* Bit 1: Video output clock invert control */
+
+#define VP_CLK_CTRL1_NON_INVERTED 0x00
+#define VP_CLK_CTRL1_INVERTED 0x02
+
+/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x196 */
+
+/* Bits 2 to 0: VSYNC pin video vertical sync type */
+
+#define VP_VS_TYPE_MASK 0x07
+
+#define VP_VS_TYPE_OFF 0x00
+#define VP_VS_TYPE_V123 0x01
+#define VP_VS_TYPE_V_ITU 0x02
+#define VP_VS_TYPE_VGATE_L 0x03
+#define VP_VS_TYPE_RESERVED1 0x04
+#define VP_VS_TYPE_RESERVED2 0x05
+#define VP_VS_TYPE_F_ITU 0x06
+#define VP_VS_TYPE_SC_FID 0x07
+
+/* ------------------------------------------------------------------ */
/* data structs for video */
static int video_out[][9] = {
@@ -273,12 +313,12 @@ static struct saa7134_tvnorm tvnorms[] = {
.h_start = 0,
.h_stop = 719,
- .video_v_start = 23,
- .video_v_stop = 262,
- .vbi_v_start_0 = 10,
- .vbi_v_stop_0 = 21,
- .vbi_v_start_1 = 273,
- .src_timing = 7,
+ .video_v_start = 23,
+ .video_v_stop = 262,
+ .vbi_v_start_0 = 10,
+ .vbi_v_stop_0 = 21,
+ .vbi_v_start_1 = 273,
+ .src_timing = 7,
.sync_control = 0x18,
.luma_control = 0x40,
@@ -622,7 +662,7 @@ static void set_size(struct saa7134_dev *dev, int task,
prescale = 1;
xscale = 1024 * dev->crop_current.width / prescale / width;
yscale = 512 * div * dev->crop_current.height / height;
- dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale);
+ dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale);
set_h_prescale(dev,task,prescale);
saa_writeb(SAA7134_H_SCALE_INC1(task), xscale & 0xff);
saa_writeb(SAA7134_H_SCALE_INC2(task), xscale >> 8);
@@ -752,20 +792,20 @@ static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win)
maxh = dev->crop_current.height;
if (V4L2_FIELD_ANY == field) {
- field = (win->w.height > maxh/2)
- ? 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;
- }
+ field = (win->w.height > maxh/2)
+ ? 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;
+ }
win->field = field;
if (win->w.width > maxw)
@@ -1306,13 +1346,13 @@ video_poll(struct file *file, struct poll_table_struct *wait)
if (res_locked(fh->dev,RESOURCE_VIDEO)) {
up(&fh->cap.lock);
return POLLERR;
- }
- if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) {
- up(&fh->cap.lock);
- return POLLERR;
- }
- fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
- fh->cap.read_off = 0;
+ }
+ if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) {
+ up(&fh->cap.lock);
+ return POLLERR;
+ }
+ fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
+ fh->cap.read_off = 0;
}
up(&fh->cap.lock);
buf = fh->cap.read_buf;
@@ -1666,9 +1706,10 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_QUERYCAP:
{
struct v4l2_capability *cap = arg;
+ unsigned int tuner_type = dev->tuner_type;
memset(cap,0,sizeof(*cap));
- strcpy(cap->driver, "saa7134");
+ strcpy(cap->driver, "saa7134");
strlcpy(cap->card, saa7134_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
@@ -1677,9 +1718,13 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_VIDEO_OVERLAY |
V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_TUNER |
V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_TUNER;
+
+ if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
+ cap->capabilities &= ~V4L2_CAP_TUNER;
+
return 0;
}
@@ -1793,9 +1838,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
crop->c.height = b->top - crop->c.top + b->height;
if (crop->c.left < b->left)
- crop->c.top = b->left;
+ crop->c.left = b->left;
if (crop->c.left > b->left + b->width)
- crop->c.top = b->left + b->width;
+ crop->c.left = b->left + b->width;
if (crop->c.width > b->left - crop->c.left + b->width)
crop->c.width = b->left - crop->c.left + b->width;
@@ -1817,6 +1862,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
break;
if (NULL != card_in(dev,n).name) {
strcpy(t->name, "Television");
+ t->type = V4L2_TUNER_ANALOG_TV;
t->capability = V4L2_TUNER_CAP_NORM |
V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_LANG1 |
@@ -1892,26 +1938,26 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
}
case VIDIOC_S_AUDIO:
return 0;
- case VIDIOC_G_PARM:
- {
- struct v4l2_captureparm *parm = arg;
- memset(parm,0,sizeof(*parm));
- return 0;
- }
-
- case VIDIOC_G_PRIORITY:
- {
- enum v4l2_priority *p = arg;
-
- *p = v4l2_prio_max(&dev->prio);
- return 0;
- }
- case VIDIOC_S_PRIORITY:
- {
- enum v4l2_priority *prio = arg;
-
- return v4l2_prio_change(&dev->prio, &fh->prio, *prio);
- }
+ case VIDIOC_G_PARM:
+ {
+ struct v4l2_captureparm *parm = arg;
+ memset(parm,0,sizeof(*parm));
+ return 0;
+ }
+
+ case VIDIOC_G_PRIORITY:
+ {
+ enum v4l2_priority *p = arg;
+
+ *p = v4l2_prio_max(&dev->prio);
+ return 0;
+ }
+ case VIDIOC_S_PRIORITY:
+ {
+ enum v4l2_priority *prio = arg;
+
+ return v4l2_prio_change(&dev->prio, &fh->prio, *prio);
+ }
/* --- preview ioctls ---------------------------------------- */
case VIDIOC_ENUM_FMT:
@@ -2018,7 +2064,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_format *f = arg;
return saa7134_try_fmt(dev,fh,f);
}
-
+#ifdef HAVE_V4L1
case VIDIOCGMBUF:
{
struct video_mbuf *mbuf = arg;
@@ -2043,6 +2089,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
}
return 0;
}
+#endif
case VIDIOC_REQBUFS:
return videobuf_reqbufs(saa7134_queue(fh),arg);
@@ -2060,7 +2107,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
{
int res = saa7134_resource(fh);
- if (!res_get(dev,fh,res))
+ if (!res_get(dev,fh,res))
return -EBUSY;
return videobuf_streamon(saa7134_queue(fh));
}
@@ -2102,7 +2149,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_capability *cap = arg;
memset(cap,0,sizeof(*cap));
- strcpy(cap->driver, "saa7134");
+ strcpy(cap->driver, "saa7134");
strlcpy(cap->card, saa7134_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
@@ -2119,6 +2166,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
memset(t,0,sizeof(*t));
strcpy(t->name, "Radio");
+ t->type = V4L2_TUNER_RADIO;
saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
@@ -2233,7 +2281,7 @@ struct video_device saa7134_video_template =
{
.name = "saa7134-video",
.type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY|
- VID_TYPE_CLIPPING|VID_TYPE_SCALES,
+ VID_TYPE_CLIPPING|VID_TYPE_SCALES,
.hardware = 0,
.fops = &video_fops,
.minor = -1,
@@ -2280,7 +2328,7 @@ int saa7134_video_init1(struct saa7134_dev *dev)
dev->tda9887_conf |= TDA9887_AUTOMUTE;
dev->automute = 0;
- INIT_LIST_HEAD(&dev->video_q.queue);
+ INIT_LIST_HEAD(&dev->video_q.queue);
init_timer(&dev->video_q.timeout);
dev->video_q.timeout.function = saa7134_buffer_timeout;
dev->video_q.timeout.data = (unsigned long)(&dev->video_q);
@@ -2289,13 +2337,28 @@ int saa7134_video_init1(struct saa7134_dev *dev)
if (saa7134_boards[dev->board].video_out) {
/* enable video output */
int vo = saa7134_boards[dev->board].video_out;
+ int video_reg;
+ unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
- saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_out[vo][1]);
+ video_reg = video_out[vo][1];
+ if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
+ video_reg &= ~VP_T_CODE_P_INVERTED;
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
- saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_out[vo][5]);
- saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_out[vo][6]);
+ video_reg = video_out[vo][5];
+ if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
+ video_reg &= ~VP_CLK_CTRL2_DELAYED;
+ if (vid_port_opts & SET_CLOCK_INVERTED)
+ video_reg |= VP_CLK_CTRL1_INVERTED;
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg);
+ video_reg = video_out[vo][6];
+ if (vid_port_opts & SET_VSYNC_OFF) {
+ video_reg &= ~VP_VS_TYPE_MASK;
+ video_reg |= VP_VS_TYPE_OFF;
+ }
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg);
saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
}
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 860b89530e2..fb972747166 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -24,16 +24,18 @@
#include <linux/pci.h>
#include <linux/i2c.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <linux/kdev_t.h>
#include <linux/input.h>
+#include <linux/notifier.h>
+#include <linux/delay.h>
#include <asm/io.h>
#include <media/tuner.h>
#include <media/audiochip.h>
-#include <media/id.h>
#include <media/ir-common.h>
+#include <media/ir-kbd-i2c.h>
#include <media/video-buf.h>
#include <media/video-buf-dvb.h>
@@ -45,6 +47,10 @@
#endif
#define UNSET (-1U)
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+
/* ----------------------------------------------------------- */
/* enums */
@@ -187,10 +193,39 @@ struct saa7134_format {
#define SAA7134_BOARD_FLYTV_DIGIMATRIX 64
#define SAA7134_BOARD_KWORLD_TERMINATOR 65
#define SAA7134_BOARD_YUAN_TUN900 66
+#define SAA7134_BOARD_BEHOLD_409FM 67
+#define SAA7134_BOARD_GOTVIEW_7135 68
+#define SAA7134_BOARD_PHILIPS_EUROPA 69
+#define SAA7134_BOARD_VIDEOMATE_DVBT_300 70
+#define SAA7134_BOARD_VIDEOMATE_DVBT_200 71
+#define SAA7134_BOARD_RTD_VFG7350 72
+#define SAA7134_BOARD_RTD_VFG7330 73
+#define SAA7134_BOARD_FLYTVPLATINUM_MINI2 74
+#define SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180 75
+#define SAA7134_BOARD_MONSTERTV_MOBILE 76
+#define SAA7134_BOARD_PINNACLE_PCTV_110i 77
+#define SAA7134_BOARD_ASUSTeK_P7131_DUAL 78
+#define SAA7134_BOARD_SEDNA_PC_TV_CARDBUS 79
+#define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80
+#define SAA7134_BOARD_PHILIPS_TIGER 81
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
+/* ----------------------------------------------------------- */
+/* Since we support 2 remote types, lets tell them apart */
+
+#define SAA7134_REMOTE_GPIO 1
+#define SAA7134_REMOTE_I2C 2
+
+/* ----------------------------------------------------------- */
+/* Video Output Port Register Initialization Options */
+
+#define SET_T_CODE_POLARITY_NON_INVERTED (1 << 0)
+#define SET_CLOCK_NOT_DELAYED (1 << 1)
+#define SET_CLOCK_INVERTED (1 << 2)
+#define SET_VSYNC_OFF (1 << 3)
+
struct saa7134_input {
char *name;
unsigned int vmux;
@@ -226,6 +261,7 @@ struct saa7134_board {
/* peripheral I/O */
enum saa7134_video_out video_out;
enum saa7134_mpeg_type mpeg;
+ unsigned int vid_port_opts;
};
#define card_has_radio(dev) (NULL != saa7134_boards[dev->board].radio.name)
@@ -319,9 +355,9 @@ struct saa7134_fh {
struct saa7134_pgtable pt_vbi;
};
-/* oss dsp status */
-struct saa7134_oss {
- struct semaphore lock;
+/* dmasound dsp status */
+struct saa7134_dmasound {
+ struct semaphore lock;
int minor_mixer;
int minor_dsp;
unsigned int users_dsp;
@@ -347,6 +383,7 @@ struct saa7134_oss {
unsigned int dma_blk;
unsigned int read_offset;
unsigned int read_count;
+ snd_pcm_substream_t *substream;
};
/* IR input */
@@ -358,9 +395,9 @@ struct saa7134_ir {
u32 mask_keycode;
u32 mask_keydown;
u32 mask_keyup;
- int polling;
- u32 last_gpio;
- struct timer_list timer;
+ int polling;
+ u32 last_gpio;
+ struct timer_list timer;
};
/* ts/mpeg status */
@@ -383,8 +420,8 @@ struct saa7134_mpeg_ops {
/* global device status */
struct saa7134_dev {
struct list_head devlist;
- struct semaphore lock;
- spinlock_t slock;
+ struct semaphore lock;
+ spinlock_t slock;
#ifdef VIDIOC_G_PRIORITY
struct v4l2_prio_state prio;
#endif
@@ -394,7 +431,7 @@ struct saa7134_dev {
struct video_device *video_dev;
struct video_device *radio_dev;
struct video_device *vbi_dev;
- struct saa7134_oss oss;
+ struct saa7134_dmasound dmasound;
/* infrared remote */
int has_remote;
@@ -421,7 +458,7 @@ struct saa7134_dev {
/* i2c i/o */
struct i2c_adapter i2c_adap;
struct i2c_client i2c_client;
- unsigned char eedata[64];
+ unsigned char eedata[128];
/* video overlay */
struct v4l2_framebuffer ovbuf;
@@ -626,6 +663,7 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status);
int saa7134_input_init1(struct saa7134_dev *dev);
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:
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
index 255b6088ebf..d32737dd214 100644
--- a/drivers/media/video/tda7432.c
+++ b/drivers/media/video/tda7432.c
@@ -50,7 +50,6 @@
#include "bttv.h"
#include <media/audiochip.h>
-#include <media/id.h>
#ifndef VIDEO_AUDIO_BALANCE
# define VIDEO_AUDIO_BALANCE 32
@@ -310,9 +309,9 @@ static int tda7432_attach(struct i2c_adapter *adap, int addr, int kind)
memset(t,0,sizeof *t);
client = &t->c;
- memcpy(client,&client_template,sizeof(struct i2c_client));
- client->adapter = adap;
- client->addr = addr;
+ memcpy(client,&client_template,sizeof(struct i2c_client));
+ client->adapter = adap;
+ client->addr = addr;
i2c_set_clientdata(client, t);
do_tda7432_init(client);
@@ -472,7 +471,7 @@ static int tda7432_command(struct i2c_client *client,
}
}
- t->muted=(va->flags & VIDEO_AUDIO_MUTE);
+ t->muted=(va->flags & VIDEO_AUDIO_MUTE);
if (t->muted)
{
/* Mute & update balance*/
@@ -503,12 +502,12 @@ static int tda7432_command(struct i2c_client *client,
static struct i2c_driver driver = {
.owner = THIS_MODULE,
- .name = "i2c tda7432 driver",
+ .name = "i2c tda7432 driver",
.id = I2C_DRIVERID_TDA7432,
- .flags = I2C_DF_NOTIFY,
+ .flags = I2C_DF_NOTIFY,
.attach_adapter = tda7432_probe,
- .detach_client = tda7432_detach,
- .command = tda7432_command,
+ .detach_client = tda7432_detach,
+ .command = tda7432_command,
};
static struct i2c_client client_template =
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index c65f0c7680a..b2dfe07e9f9 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -1,172 +1,406 @@
/*
- *
- * i2c tv tuner chip device driver
- * controls the philips tda8290+75 tuner chip combo.
- */
+
+ i2c tv tuner chip device driver
+ controls the philips tda8290+75 tuner chip combo.
+
+ 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/i2c.h>
#include <linux/videodev.h>
#include <linux/delay.h>
#include <media/tuner.h>
-#define I2C_ADDR_TDA8290 0x4b
-#define I2C_ADDR_TDA8275 0x61
-
/* ---------------------------------------------------------------------- */
-struct freq_entry {
- u16 freq;
- u8 value;
+struct tda827x_data {
+ u32 lomax;
+ u8 spd;
+ u8 bs;
+ u8 bp;
+ u8 cp;
+ u8 gc3;
+ u8 div1p5;
};
-static struct freq_entry band_table[] = {
- { 0x2DF4, 0x1C },
- { 0x2574, 0x14 },
- { 0x22B4, 0x0C },
- { 0x20D4, 0x0B },
- { 0x1E74, 0x3B },
- { 0x1C34, 0x33 },
- { 0x16F4, 0x5B },
- { 0x1454, 0x53 },
- { 0x12D4, 0x52 },
- { 0x1034, 0x4A },
- { 0x0EE4, 0x7A },
- { 0x0D34, 0x72 },
- { 0x0B54, 0x9A },
- { 0x0914, 0x91 },
- { 0x07F4, 0x89 },
- { 0x0774, 0xB9 },
- { 0x067B, 0xB1 },
- { 0x0634, 0xD9 },
- { 0x05A4, 0xD8 }, // FM radio
- { 0x0494, 0xD0 },
- { 0x03BC, 0xC8 },
- { 0x0394, 0xF8 }, // 57250000 Hz
- { 0x0000, 0xF0 }, // 0
+ /* Note lomax entry is lo / 62500 */
+
+static struct tda827x_data tda827x_analog[] = {
+ { .lomax = 992, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /* 62 MHz */
+ { .lomax = 1056, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /* 66 MHz */
+ { .lomax = 1216, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /* 76 MHz */
+ { .lomax = 1344, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /* 84 MHz */
+ { .lomax = 1488, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 93 MHz */
+ { .lomax = 1568, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 98 MHz */
+ { .lomax = 1744, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 109 MHz */
+ { .lomax = 1968, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 123 MHz */
+ { .lomax = 2128, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 133 MHz */
+ { .lomax = 2416, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 151 MHz */
+ { .lomax = 2464, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 154 MHz */
+ { .lomax = 2896, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 181 MHz */
+ { .lomax = 2960, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 185 MHz */
+ { .lomax = 3472, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 217 MHz */
+ { .lomax = 3904, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 244 MHz */
+ { .lomax = 4240, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 265 MHz */
+ { .lomax = 4832, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 302 MHz */
+ { .lomax = 5184, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 324 MHz */
+ { .lomax = 5920, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 370 MHz */
+ { .lomax = 7264, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 454 MHz */
+ { .lomax = 7888, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 493 MHz */
+ { .lomax = 8480, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 530 MHz */
+ { .lomax = 8864, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 554 MHz */
+ { .lomax = 9664, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 604 MHz */
+ { .lomax = 11088, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 696 MHz */
+ { .lomax = 11840, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 740 MHz */
+ { .lomax = 13120, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 820 MHz */
+ { .lomax = 13840, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 865 MHz */
+ { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} /* End */
};
-static struct freq_entry div_table[] = {
- { 0x1C34, 3 },
- { 0x0D34, 2 },
- { 0x067B, 1 },
- { 0x0000, 0 },
-};
+static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
+{
+ unsigned char tuner_reg[8];
+ unsigned char reg2[2];
+ u32 N;
+ int i;
+ struct tuner *t = i2c_get_clientdata(c);
+ struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0};
-static struct freq_entry agc_table[] = {
- { 0x22B4, 0x8F },
- { 0x0B54, 0x9F },
- { 0x09A4, 0x8F },
- { 0x0554, 0x9F },
- { 0x0000, 0xBF },
-};
+ if (t->mode == V4L2_TUNER_RADIO)
+ freq = freq / 1000;
-static __u8 get_freq_entry( struct freq_entry* table, __u16 freq)
-{
- while(table->freq && table->freq > freq)
- table++;
- return table->value;
-}
+ N = freq + ifc;
+ i = 0;
+ while (tda827x_analog[i].lomax < N) {
+ if(tda827x_analog[i + 1].lomax == 0)
+ break;
+ i++;
+ }
+
+ N = N << tda827x_analog[i].spd;
+
+ tuner_reg[0] = 0;
+ tuner_reg[1] = (unsigned char)(N>>8);
+ tuner_reg[2] = (unsigned char) N;
+ tuner_reg[3] = 0x40;
+ tuner_reg[4] = 0x52 + (t->tda827x_lpsel << 5);
+ tuner_reg[5] = (tda827x_analog[i].spd << 6) + (tda827x_analog[i].div1p5 <<5) +
+ (tda827x_analog[i].bs <<3) + tda827x_analog[i].bp;
+ tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4);
+ tuner_reg[7] = 0x8f;
+
+ msg.buf = tuner_reg;
+ msg.len = 8;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ msg.buf= reg2;
+ msg.len = 2;
+ reg2[0] = 0x80;
+ reg2[1] = 0;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ reg2[0] = 0x60;
+ reg2[1] = 0xbf;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ reg2[0] = 0x30;
+ reg2[1] = tuner_reg[4] + 0x80;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ msleep(1);
+ reg2[0] = 0x30;
+ reg2[1] = tuner_reg[4] + 4;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ msleep(1);
+ reg2[0] = 0x30;
+ reg2[1] = tuner_reg[4];
+ i2c_transfer(c->adapter, &msg, 1);
-/* ---------------------------------------------------------------------- */
+ msleep(550);
+ reg2[0] = 0x30;
+ reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ;
+ i2c_transfer(c->adapter, &msg, 1);
-static unsigned char i2c_enable_bridge[2] = { 0x21, 0xC0 };
-static unsigned char i2c_disable_bridge[2] = { 0x21, 0x80 };
-static unsigned char i2c_init_tda8275[14] = { 0x00, 0x00, 0x00, 0x00,
- 0xfC, 0x04, 0xA3, 0x3F,
- 0x2A, 0x04, 0xFF, 0x00,
- 0x00, 0x40 };
-static unsigned char i2c_set_VS[2] = { 0x30, 0x6F };
-static unsigned char i2c_set_GP01_CF[2] = { 0x20, 0x0B };
-static unsigned char i2c_tda8290_reset[2] = { 0x00, 0x00 };
-static unsigned char i2c_tda8290_standby[2] = { 0x00, 0x02 };
-static unsigned char i2c_gainset_off[2] = { 0x28, 0x14 };
-static unsigned char i2c_gainset_on[2] = { 0x28, 0x54 };
-static unsigned char i2c_agc3_00[2] = { 0x80, 0x00 };
-static unsigned char i2c_agc2_BF[2] = { 0x60, 0xBF };
-static unsigned char i2c_cb1_D0[2] = { 0x30, 0xD0 };
-static unsigned char i2c_cb1_D2[2] = { 0x30, 0xD2 };
-static unsigned char i2c_cb1_56[2] = { 0x30, 0x56 };
-static unsigned char i2c_cb1_52[2] = { 0x30, 0x52 };
-static unsigned char i2c_cb1_50[2] = { 0x30, 0x50 };
-static unsigned char i2c_agc2_7F[2] = { 0x60, 0x7F };
-static unsigned char i2c_agc3_08[2] = { 0x80, 0x08 };
-
-static struct i2c_msg i2c_msg_init[] = {
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_init_tda8275), i2c_init_tda8275 },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_set_VS), i2c_set_VS },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_set_GP01_CF), i2c_set_GP01_CF },
-};
+ reg2[0] = 0x60;
+ reg2[1] = 0x3f;
+ i2c_transfer(c->adapter, &msg, 1);
-static struct i2c_msg i2c_msg_prolog[] = {
-// { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_easy_mode), i2c_easy_mode },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_gainset_off), i2c_gainset_off },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_tda8290_reset), i2c_tda8290_reset },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_enable_bridge), i2c_enable_bridge },
-};
+ reg2[0] = 0x80;
+ reg2[1] = 0x08; // Vsync en
+ i2c_transfer(c->adapter, &msg, 1);
+}
-static struct i2c_msg i2c_msg_config[] = {
-// { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_set_freq), i2c_set_freq },
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc3_00), i2c_agc3_00 },
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc2_BF), i2c_agc2_BF },
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_D2), i2c_cb1_D2 },
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_56), i2c_cb1_56 },
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_52), i2c_cb1_52 },
-};
+static void tda827x_agcf(struct i2c_client *c)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned char data[] = {0x80, 0x0c};
+ struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+ .flags = 0, .len = 2};
+ i2c_transfer(c->adapter, &msg, 1);
+}
-static struct i2c_msg i2c_msg_epilog[] = {
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_50), i2c_cb1_50 },
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc2_7F), i2c_agc2_7F },
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_agc3_08), i2c_agc3_08 },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_gainset_on), i2c_gainset_on },
+/* ---------------------------------------------------------------------- */
+
+struct tda827xa_data {
+ u32 lomax;
+ u8 svco;
+ u8 spd;
+ u8 scr;
+ u8 sbs;
+ u8 gc3;
};
-static struct i2c_msg i2c_msg_standby[] = {
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_enable_bridge), i2c_enable_bridge },
- { I2C_ADDR_TDA8275, 0, ARRAY_SIZE(i2c_cb1_D0), i2c_cb1_D0 },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_disable_bridge), i2c_disable_bridge },
- { I2C_ADDR_TDA8290, 0, ARRAY_SIZE(i2c_tda8290_standby), i2c_tda8290_standby },
+static struct tda827xa_data tda827xa_analog[] = {
+ { .lomax = 910, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3}, /* 56.875 MHz */
+ { .lomax = 1076, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 67.25 MHz */
+ { .lomax = 1300, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 81.25 MHz */
+ { .lomax = 1560, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 97.5 MHz */
+ { .lomax = 1820, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, /* 113.75 MHz */
+ { .lomax = 2152, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 134.5 MHz */
+ { .lomax = 2464, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 154 MHz */
+ { .lomax = 2600, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 162.5 MHz */
+ { .lomax = 2928, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 183 MHz */
+ { .lomax = 3120, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, /* 195 MHz */
+ { .lomax = 3640, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3}, /* 227.5 MHz */
+ { .lomax = 4304, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3}, /* 269 MHz */
+ { .lomax = 5200, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, /* 325 MHz */
+ { .lomax = 6240, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, /* 390 MHz */
+ { .lomax = 7280, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, /* 455 MHz */
+ { .lomax = 8320, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, /* 520 MHz */
+ { .lomax = 8608, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, /* 538 MHz */
+ { .lomax = 8864, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, /* 554 MHz */
+ { .lomax = 9920, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 620 MHz */
+ { .lomax = 10400, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 650 MHz */
+ { .lomax = 11200, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 700 MHz */
+ { .lomax = 12480, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 780 MHz */
+ { .lomax = 13120, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 820 MHz */
+ { .lomax = 13920, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 870 MHz */
+ { .lomax = 14576, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, /* 911 MHz */
+ { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */
};
-static int tda8290_tune(struct i2c_client *c)
+static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
{
+ unsigned char tuner_reg[14];
+ unsigned char reg2[2];
+ u32 N;
+ int i;
struct tuner *t = i2c_get_clientdata(c);
- struct i2c_msg easy_mode =
- { I2C_ADDR_TDA8290, 0, 2, t->i2c_easy_mode };
- struct i2c_msg set_freq =
- { I2C_ADDR_TDA8275, 0, 8, t->i2c_set_freq };
+ struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0};
- i2c_transfer(c->adapter, &easy_mode, 1);
- i2c_transfer(c->adapter, i2c_msg_prolog, ARRAY_SIZE(i2c_msg_prolog));
+ if (t->mode == V4L2_TUNER_RADIO)
+ freq = freq / 1000;
- i2c_transfer(c->adapter, &set_freq, 1);
- i2c_transfer(c->adapter, i2c_msg_config, ARRAY_SIZE(i2c_msg_config));
+ N = freq + ifc;
+ i = 0;
+ while (tda827xa_analog[i].lomax < N) {
+ if(tda827xa_analog[i + 1].lomax == 0)
+ break;
+ i++;
+ }
+
+ N = N << tda827xa_analog[i].spd;
+
+ tuner_reg[0] = 0;
+ tuner_reg[1] = (unsigned char)(N>>8);
+ tuner_reg[2] = (unsigned char) N;
+ tuner_reg[3] = 0;
+ tuner_reg[4] = 0x16;
+ tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) +
+ tda827xa_analog[i].sbs;
+ tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
+ tuner_reg[7] = 0x0c;
+ tuner_reg[8] = 4;
+ tuner_reg[9] = 0x20;
+ tuner_reg[10] = 0xff;
+ tuner_reg[11] = 0xe0;
+ tuner_reg[12] = 0;
+ tuner_reg[13] = 0x39 + (t->tda827x_lpsel << 1);
+
+ msg.buf = tuner_reg;
+ msg.len = 14;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ msg.buf= reg2;
+ msg.len = 2;
+ reg2[0] = 0x60;
+ reg2[1] = 0x3c;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ reg2[0] = 0xa0;
+ reg2[1] = 0xc0;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ msleep(2);
+ reg2[0] = 0x30;
+ reg2[1] = 0x10 + tda827xa_analog[i].scr;
+ i2c_transfer(c->adapter, &msg, 1);
msleep(550);
- i2c_transfer(c->adapter, i2c_msg_epilog, ARRAY_SIZE(i2c_msg_epilog));
- return 0;
+ reg2[0] = 0x50;
+ reg2[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
+ i2c_transfer(c->adapter, &msg, 1);
+
+ reg2[0] = 0x80;
+ reg2[1] = 0x28;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ reg2[0] = 0xb0;
+ reg2[1] = 0x01;
+ i2c_transfer(c->adapter, &msg, 1);
+
+ reg2[0] = 0xc0;
+ reg2[1] = 0x19 + (t->tda827x_lpsel << 1);
+ i2c_transfer(c->adapter, &msg, 1);
}
-static void set_frequency(struct tuner *t, u16 ifc, unsigned int freq)
+static void tda827xa_agcf(struct i2c_client *c)
{
- u32 N;
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned char data[] = {0x80, 0x2c};
+ struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+ .flags = 0, .len = 2};
+ i2c_transfer(c->adapter, &msg, 1);
+}
- if (t->mode == V4L2_TUNER_RADIO)
- freq = freq / 1000;
+/*---------------------------------------------------------------------*/
- N = (((freq<<3)+ifc)&0x3fffc);
-
- N = N >> get_freq_entry(div_table, freq);
- t->i2c_set_freq[0] = 0;
- t->i2c_set_freq[1] = (unsigned char)(N>>8);
- t->i2c_set_freq[2] = (unsigned char) N;
- t->i2c_set_freq[3] = 0x40;
- t->i2c_set_freq[4] = 0x52;
- t->i2c_set_freq[5] = get_freq_entry(band_table, freq);
- t->i2c_set_freq[6] = get_freq_entry(agc_table, freq);
- t->i2c_set_freq[7] = 0x8f;
+static void tda8290_i2c_bridge(struct i2c_client *c, int close)
+{
+ unsigned char enable[2] = { 0x21, 0xC0 };
+ unsigned char disable[2] = { 0x21, 0x80 };
+ unsigned char *msg;
+ if(close) {
+ msg = enable;
+ i2c_master_send(c, msg, 2);
+ /* let the bridge stabilize */
+ msleep(20);
+ } else {
+ msg = disable;
+ i2c_master_send(c, msg, 2);
+ }
}
+/*---------------------------------------------------------------------*/
+
+static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned char soft_reset[] = { 0x00, 0x00 };
+ unsigned char easy_mode[] = { 0x01, t->tda8290_easy_mode };
+ unsigned char expert_mode[] = { 0x01, 0x80 };
+ unsigned char gainset_off[] = { 0x28, 0x14 };
+ unsigned char if_agc_spd[] = { 0x0f, 0x88 };
+ unsigned char adc_head_6[] = { 0x05, 0x04 };
+ unsigned char adc_head_9[] = { 0x05, 0x02 };
+ unsigned char adc_head_12[] = { 0x05, 0x01 };
+ unsigned char pll_bw_nom[] = { 0x0d, 0x47 };
+ unsigned char pll_bw_low[] = { 0x0d, 0x27 };
+ unsigned char gainset_2[] = { 0x28, 0x64 };
+ unsigned char agc_rst_on[] = { 0x0e, 0x0b };
+ unsigned char agc_rst_off[] = { 0x0e, 0x09 };
+ unsigned char if_agc_set[] = { 0x0f, 0x81 };
+ unsigned char addr_adc_sat = 0x1a;
+ unsigned char addr_agc_stat = 0x1d;
+ unsigned char addr_pll_stat = 0x1b;
+ unsigned char adc_sat, agc_stat,
+ pll_stat;
+
+ i2c_master_send(c, easy_mode, 2);
+ i2c_master_send(c, soft_reset, 2);
+ msleep(1);
+
+ expert_mode[1] = t->tda8290_easy_mode + 0x80;
+ i2c_master_send(c, expert_mode, 2);
+ i2c_master_send(c, gainset_off, 2);
+ i2c_master_send(c, if_agc_spd, 2);
+ if (t->tda8290_easy_mode & 0x60)
+ i2c_master_send(c, adc_head_9, 2);
+ else
+ i2c_master_send(c, adc_head_6, 2);
+ i2c_master_send(c, pll_bw_nom, 2);
+
+ tda8290_i2c_bridge(c, 1);
+ if (t->tda827x_ver != 0)
+ tda827xa_tune(c, ifc, freq);
+ else
+ tda827x_tune(c, ifc, freq);
+ /* adjust headroom resp. gain */
+ i2c_master_send(c, &addr_adc_sat, 1);
+ i2c_master_recv(c, &adc_sat, 1);
+ i2c_master_send(c, &addr_agc_stat, 1);
+ i2c_master_recv(c, &agc_stat, 1);
+ i2c_master_send(c, &addr_pll_stat, 1);
+ i2c_master_recv(c, &pll_stat, 1);
+ if (pll_stat & 0x80)
+ tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat);
+ else
+ tuner_dbg("tda8290 not locked, no signal?\n");
+ if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) {
+ tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n",
+ agc_stat, adc_sat, pll_stat & 0x80);
+ i2c_master_send(c, gainset_2, 2);
+ msleep(100);
+ i2c_master_send(c, &addr_agc_stat, 1);
+ i2c_master_recv(c, &agc_stat, 1);
+ i2c_master_send(c, &addr_pll_stat, 1);
+ i2c_master_recv(c, &pll_stat, 1);
+ if ((agc_stat > 115) || !(pll_stat & 0x80)) {
+ tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
+ agc_stat, pll_stat & 0x80);
+ if (t->tda827x_ver != 0)
+ tda827xa_agcf(c);
+ else
+ tda827x_agcf(c);
+ msleep(100);
+ i2c_master_send(c, &addr_agc_stat, 1);
+ i2c_master_recv(c, &agc_stat, 1);
+ i2c_master_send(c, &addr_pll_stat, 1);
+ i2c_master_recv(c, &pll_stat, 1);
+ if((agc_stat > 115) || !(pll_stat & 0x80)) {
+ tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat);
+ i2c_master_send(c, adc_head_12, 2);
+ i2c_master_send(c, pll_bw_low, 2);
+ msleep(100);
+ }
+ }
+ }
+
+ /* l/ l' deadlock? */
+ if(t->tda8290_easy_mode & 0x60) {
+ i2c_master_send(c, &addr_adc_sat, 1);
+ i2c_master_recv(c, &adc_sat, 1);
+ i2c_master_send(c, &addr_pll_stat, 1);
+ i2c_master_recv(c, &pll_stat, 1);
+ if ((adc_sat > 20) || !(pll_stat & 0x80)) {
+ tuner_dbg("trying to resolve SECAM L deadlock\n");
+ i2c_master_send(c, agc_rst_on, 2);
+ msleep(40);
+ i2c_master_send(c, agc_rst_off, 2);
+ }
+ }
+
+ tda8290_i2c_bridge(c, 0);
+ i2c_master_send(c, if_agc_set, 2);
+ return 0;
+}
+
+
+/*---------------------------------------------------------------------*/
+
#define V4L2_STD_MN (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC)
#define V4L2_STD_B (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B)
#define V4L2_STD_GH (V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H)
@@ -174,20 +408,37 @@ static void set_frequency(struct tuner *t, u16 ifc, unsigned int freq)
static void set_audio(struct tuner *t)
{
- t->i2c_easy_mode[0] = 0x01;
-
- if (t->std & V4L2_STD_MN)
- t->i2c_easy_mode[1] = 0x01;
- else if (t->std & V4L2_STD_B)
- t->i2c_easy_mode[1] = 0x02;
- else if (t->std & V4L2_STD_GH)
- t->i2c_easy_mode[1] = 0x04;
- else if (t->std & V4L2_STD_PAL_I)
- t->i2c_easy_mode[1] = 0x08;
- else if (t->std & V4L2_STD_DK)
- t->i2c_easy_mode[1] = 0x10;
- else if (t->std & V4L2_STD_SECAM_L)
- t->i2c_easy_mode[1] = 0x20;
+ char* mode;
+
+ t->tda827x_lpsel = 0;
+ mode = "xx";
+ if (t->std & V4L2_STD_MN) {
+ t->sgIF = 92;
+ t->tda8290_easy_mode = 0x01;
+ t->tda827x_lpsel = 1;
+ mode = "MN";
+ } else if (t->std & V4L2_STD_B) {
+ t->sgIF = 108;
+ t->tda8290_easy_mode = 0x02;
+ mode = "B";
+ } else if (t->std & V4L2_STD_GH) {
+ t->sgIF = 124;
+ t->tda8290_easy_mode = 0x04;
+ mode = "GH";
+ } else if (t->std & V4L2_STD_PAL_I) {
+ t->sgIF = 124;
+ t->tda8290_easy_mode = 0x08;
+ mode = "I";
+ } else if (t->std & V4L2_STD_DK) {
+ t->sgIF = 124;
+ t->tda8290_easy_mode = 0x10;
+ mode = "DK";
+ } else if (t->std & V4L2_STD_SECAM_L) {
+ t->sgIF = 124;
+ t->tda8290_easy_mode = 0x20;
+ mode = "L";
+ }
+ tuner_dbg("setting tda8290 to system %s\n", mode);
}
static void set_tv_freq(struct i2c_client *c, unsigned int freq)
@@ -195,15 +446,13 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
struct tuner *t = i2c_get_clientdata(c);
set_audio(t);
- set_frequency(t, 864, freq);
- tda8290_tune(c);
+ tda8290_tune(c, t->sgIF, freq);
}
static void set_radio_freq(struct i2c_client *c, unsigned int freq)
{
- struct tuner *t = i2c_get_clientdata(c);
- set_frequency(t, 704, freq);
- tda8290_tune(c);
+ /* if frequency is 5.5 MHz */
+ tda8290_tune(c, 88, freq);
}
static int has_signal(struct i2c_client *c)
@@ -216,27 +465,145 @@ static int has_signal(struct i2c_client *c)
return (afc & 0x80)? 65535:0;
}
+/*---------------------------------------------------------------------*/
+
static void standby(struct i2c_client *c)
{
- i2c_transfer(c->adapter, i2c_msg_standby, ARRAY_SIZE(i2c_msg_standby));
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned char cb1[] = { 0x30, 0xD0 };
+ unsigned char tda8290_standby[] = { 0x00, 0x02 };
+ struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
+
+ tda8290_i2c_bridge(c, 1);
+ if (t->tda827x_ver != 0)
+ cb1[1] = 0x90;
+ i2c_transfer(c->adapter, &msg, 1);
+ tda8290_i2c_bridge(c, 0);
+ i2c_master_send(c, tda8290_standby, 2);
}
-int tda8290_init(struct i2c_client *c)
+
+static void tda8290_init_if(struct i2c_client *c)
+{
+ unsigned char set_VS[] = { 0x30, 0x6F };
+ unsigned char set_GP01_CF[] = { 0x20, 0x0B };
+
+ i2c_master_send(c, set_VS, 2);
+ i2c_master_send(c, set_GP01_CF, 2);
+}
+
+static void tda8290_init_tuner(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
+ unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
+ 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
+ unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
+ 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
+ struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0,
+ .buf=tda8275_init, .len = 14};
+ if (t->tda827x_ver != 0)
+ msg.buf = tda8275a_init;
+
+ tda8290_i2c_bridge(c, 1);
+ i2c_transfer(c->adapter, &msg, 1);
+ tda8290_i2c_bridge(c, 0);
+}
- strlcpy(c->name, "tda8290+75", sizeof(c->name));
+/*---------------------------------------------------------------------*/
+
+int tda8290_init(struct i2c_client *c)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ u8 data;
+ int i, ret, tuners_found;
+ u32 tuner_addrs;
+ struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1};
+
+ tda8290_i2c_bridge(c, 1);
+ /* probe for tuner chip */
+ tuners_found = 0;
+ tuner_addrs = 0;
+ for (i=0x60; i<= 0x63; i++) {
+ msg.addr = i;
+ ret = i2c_transfer(c->adapter, &msg, 1);
+ if (ret == 1) {
+ tuners_found++;
+ tuner_addrs = (tuner_addrs << 8) + i;
+ }
+ }
+ /* if there is more than one tuner, we expect the right one is
+ behind the bridge and we choose the highest address that doesn't
+ give a response now
+ */
+ tda8290_i2c_bridge(c, 0);
+ if(tuners_found > 1)
+ for (i = 0; i < tuners_found; i++) {
+ msg.addr = tuner_addrs & 0xff;
+ ret = i2c_transfer(c->adapter, &msg, 1);
+ if(ret == 1)
+ tuner_addrs = tuner_addrs >> 8;
+ else
+ break;
+ }
+ if (tuner_addrs == 0) {
+ tuner_addrs = 0x61;
+ tuner_info ("could not clearly identify tuner address, defaulting to %x\n",
+ tuner_addrs);
+ } else {
+ tuner_addrs = tuner_addrs & 0xff;
+ tuner_info ("setting tuner address to %x\n", tuner_addrs);
+ }
+ t->tda827x_addr = tuner_addrs;
+ msg.addr = tuner_addrs;
+
+ tda8290_i2c_bridge(c, 1);
+ ret = i2c_transfer(c->adapter, &msg, 1);
+ if( ret != 1)
+ tuner_warn ("TDA827x access failed!\n");
+ if ((data & 0x3c) == 0) {
+ strlcpy(c->name, "tda8290+75", sizeof(c->name));
+ t->tda827x_ver = 0;
+ } else {
+ strlcpy(c->name, "tda8290+75a", sizeof(c->name));
+ t->tda827x_ver = 2;
+ }
tuner_info("tuner: type set to %s\n", c->name);
+
t->tv_freq = set_tv_freq;
t->radio_freq = set_radio_freq;
t->has_signal = has_signal;
t->standby = standby;
+ t->tda827x_lpsel = 0;
- i2c_master_send(c, i2c_enable_bridge, ARRAY_SIZE(i2c_enable_bridge));
- i2c_transfer(c->adapter, i2c_msg_init, ARRAY_SIZE(i2c_msg_init));
+ tda8290_init_tuner(c);
+ tda8290_init_if(c);
return 0;
}
+int tda8290_probe(struct i2c_client *c)
+{
+ unsigned char soft_reset[] = { 0x00, 0x00 };
+ unsigned char easy_mode_b[] = { 0x01, 0x02 };
+ unsigned char easy_mode_g[] = { 0x01, 0x04 };
+ unsigned char addr_dto_lsb = 0x07;
+ unsigned char data;
+
+ i2c_master_send(c, easy_mode_b, 2);
+ i2c_master_send(c, soft_reset, 2);
+ i2c_master_send(c, &addr_dto_lsb, 1);
+ i2c_master_recv(c, &data, 1);
+ if (data == 0) {
+ i2c_master_send(c, easy_mode_g, 2);
+ i2c_master_send(c, soft_reset, 2);
+ i2c_master_send(c, &addr_dto_lsb, 1);
+ i2c_master_recv(c, &data, 1);
+ if (data == 0x7b) {
+ return 0;
+ }
+ }
+ return -1;
+}
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
index 7e3dcdb262b..a5e37dc91f3 100644
--- a/drivers/media/video/tda9875.c
+++ b/drivers/media/video/tda9875.c
@@ -32,7 +32,6 @@
#include "bttv.h"
#include <media/audiochip.h>
-#include <media/id.h>
static int debug; /* insmod parameter */
module_param(debug, int, S_IRUGO | S_IWUSR);
@@ -126,20 +125,20 @@ static int tda9875_write(struct i2c_client *client, int subaddr, unsigned char v
static int i2c_read_register(struct i2c_adapter *adap, int addr, int reg)
{
- unsigned char write[1];
- unsigned char read[1];
- struct i2c_msg msgs[2] = {
- { addr, 0, 1, write },
- { addr, I2C_M_RD, 1, read }
- };
- write[0] = reg;
-
- if (2 != i2c_transfer(adap,msgs,2)) {
- printk(KERN_WARNING "tda9875: I/O error (read2)\n");
- return -1;
- }
- dprintk("tda9875: chip_read2: reg%d=0x%x\n",reg,read[0]);
- return read[0];
+ unsigned char write[1];
+ unsigned char read[1];
+ struct i2c_msg msgs[2] = {
+ { addr, 0, 1, write },
+ { addr, I2C_M_RD, 1, read }
+ };
+ write[0] = reg;
+
+ if (2 != i2c_transfer(adap,msgs,2)) {
+ printk(KERN_WARNING "tda9875: I/O error (read2)\n");
+ return -1;
+ }
+ dprintk("tda9875: chip_read2: reg%d=0x%x\n",reg,read[0]);
+ return read[0];
}
static void tda9875_set(struct i2c_client *client)
@@ -184,7 +183,7 @@ static void do_tda9875_init(struct i2c_client *client)
tda9875_write(client, TDA9875_DACOS, 0x02 ); /* sig DAC i/o(in:nicam)*/
tda9875_write(client, TDA9875_ADCIS, 0x6f ); /* sig ADC input(in:mono)*/
tda9875_write(client, TDA9875_LOSR, 0x00 ); /* line out (in:mono)*/
- tda9875_write(client, TDA9875_AER, 0x00 ); /*06 Effect (AVL+PSEUDO) */
+ tda9875_write(client, TDA9875_AER, 0x00 ); /*06 Effect (AVL+PSEUDO) */
tda9875_write(client, TDA9875_MCS, 0x44 ); /* Main ch select (DAC) */
tda9875_write(client, TDA9875_MVL, 0x03 ); /* Vol Main left 10dB */
tda9875_write(client, TDA9875_MVR, 0x03 ); /* Vol Main right 10dB*/
@@ -200,7 +199,7 @@ static void do_tda9875_init(struct i2c_client *client)
t->mode=AUDIO_UNMUTE;
t->lvol=t->rvol =0; /* 0dB */
- t->bass=0; /* 0dB */
+ t->bass=0; /* 0dB */
t->treble=0; /* 0dB */
tda9875_set(client);
@@ -239,9 +238,9 @@ static int tda9875_attach(struct i2c_adapter *adap, int addr, int kind)
memset(t,0,sizeof *t);
client = &t->c;
- memcpy(client,&client_template,sizeof(struct i2c_client));
- client->adapter = adap;
- client->addr = addr;
+ memcpy(client,&client_template,sizeof(struct i2c_client));
+ client->adapter = adap;
+ client->addr = addr;
i2c_set_clientdata(client, t);
if(!tda9875_checkit(adap,addr)) {
@@ -287,7 +286,7 @@ static int tda9875_command(struct i2c_client *client,
dprintk("In tda9875_command...\n");
switch (cmd) {
- /* --- v4l ioctls --- */
+ /* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a
kernel pointer here... */
case VIDIOCGAUDIO:
@@ -355,7 +354,7 @@ static int tda9875_command(struct i2c_client *client,
//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble);
- tda9875_set(client);
+ tda9875_set(client);
break;
@@ -374,18 +373,18 @@ static int tda9875_command(struct i2c_client *client,
static struct i2c_driver driver = {
.owner = THIS_MODULE,
- .name = "i2c tda9875 driver",
- .id = I2C_DRIVERID_TDA9875,
- .flags = I2C_DF_NOTIFY,
+ .name = "i2c tda9875 driver",
+ .id = I2C_DRIVERID_TDA9875,
+ .flags = I2C_DF_NOTIFY,
.attach_adapter = tda9875_probe,
- .detach_client = tda9875_detach,
- .command = tda9875_command,
+ .detach_client = tda9875_detach,
+ .command = tda9875_command,
};
static struct i2c_client client_template =
{
- .name = "tda9875",
- .driver = &driver,
+ .name = "tda9875",
+ .driver = &driver,
};
static int __init tda9875_init(void)
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index 94053f149dd..4249127c0a1 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -11,7 +11,6 @@
#include <media/audiochip.h>
#include <media/tuner.h>
-#include <media/id.h>
/* Chips:
TDA9885 (PAL, NTSC)
@@ -44,8 +43,13 @@ MODULE_LICENSE("GPL");
/* ---------------------------------------------------------------------- */
#define UNSET (-1U)
-#define PREFIX "tda9885/6/7: "
-#define dprintk if (debug) printk
+#define tda9887_info(fmt, arg...) do {\
+ printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \
+ i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0)
+#define tda9887_dbg(fmt, arg...) do {\
+ if (debug) \
+ printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \
+ i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0)
struct tda9887 {
struct i2c_client client;
@@ -55,6 +59,7 @@ struct tda9887 {
unsigned int pinnacle_id;
unsigned int using_v4l2;
unsigned int radio_mode;
+ unsigned char data[4];
};
struct tvnorm {
@@ -180,7 +185,8 @@ static struct tvnorm tvnorms[] = {
.name = "SECAM-L",
.b = ( cPositiveAmTV |
cQSS ),
- .e = ( cAudioIF_6_5 |
+ .e = ( cGating_36 |
+ cAudioIF_6_5 |
cVideoIF_38_90 ),
},{
.std = V4L2_STD_SECAM_DK,
@@ -236,7 +242,7 @@ static struct tvnorm radio_mono = {
/* ---------------------------------------------------------------------- */
-static void dump_read_message(unsigned char *buf)
+static void dump_read_message(struct tda9887 *t, unsigned char *buf)
{
static char *afc[16] = {
"- 12.5 kHz",
@@ -256,15 +262,15 @@ static void dump_read_message(unsigned char *buf)
"+ 37.5 kHz",
"+ 12.5 kHz",
};
- printk(PREFIX "read: 0x%2x\n", buf[0]);
- printk(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
- printk(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]);
- printk(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low");
- printk(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out");
- printk(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");
+ tda9887_info("read: 0x%2x\n", buf[0]);
+ tda9887_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
+ tda9887_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]);
+ tda9887_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low");
+ tda9887_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out");
+ tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");
}
-static void dump_write_message(unsigned char *buf)
+static void dump_write_message(struct tda9887 *t, unsigned char *buf)
{
static char *sound[4] = {
"AM/TV",
@@ -304,58 +310,58 @@ static void dump_write_message(unsigned char *buf)
"44 MHz",
};
- printk(PREFIX "write: byte B 0x%02x\n",buf[1]);
- printk(" B0 video mode : %s\n",
+ tda9887_info("write: byte B 0x%02x\n",buf[1]);
+ tda9887_info(" B0 video mode : %s\n",
(buf[1] & 0x01) ? "video trap" : "sound trap");
- printk(" B1 auto mute fm : %s\n",
+ tda9887_info(" B1 auto mute fm : %s\n",
(buf[1] & 0x02) ? "yes" : "no");
- printk(" B2 carrier mode : %s\n",
+ tda9887_info(" B2 carrier mode : %s\n",
(buf[1] & 0x04) ? "QSS" : "Intercarrier");
- printk(" B3-4 tv sound/radio : %s\n",
+ tda9887_info(" B3-4 tv sound/radio : %s\n",
sound[(buf[1] & 0x18) >> 3]);
- printk(" B5 force mute audio: %s\n",
+ tda9887_info(" B5 force mute audio: %s\n",
(buf[1] & 0x20) ? "yes" : "no");
- printk(" B6 output port 1 : %s\n",
+ tda9887_info(" B6 output port 1 : %s\n",
(buf[1] & 0x40) ? "high (inactive)" : "low (active)");
- printk(" B7 output port 2 : %s\n",
+ tda9887_info(" B7 output port 2 : %s\n",
(buf[1] & 0x80) ? "high (inactive)" : "low (active)");
- printk(PREFIX "write: byte C 0x%02x\n",buf[2]);
- printk(" C0-4 top adjustment : %s dB\n", adjust[buf[2] & 0x1f]);
- printk(" C5-6 de-emphasis : %s\n", deemph[(buf[2] & 0x60) >> 5]);
- printk(" C7 audio gain : %s\n",
+ tda9887_info("write: byte C 0x%02x\n",buf[2]);
+ tda9887_info(" C0-4 top adjustment : %s dB\n", adjust[buf[2] & 0x1f]);
+ tda9887_info(" C5-6 de-emphasis : %s\n", deemph[(buf[2] & 0x60) >> 5]);
+ tda9887_info(" C7 audio gain : %s\n",
(buf[2] & 0x80) ? "-6" : "0");
- printk(PREFIX "write: byte E 0x%02x\n",buf[3]);
- printk(" E0-1 sound carrier : %s\n",
+ tda9887_info("write: byte E 0x%02x\n",buf[3]);
+ tda9887_info(" E0-1 sound carrier : %s\n",
carrier[(buf[3] & 0x03)]);
- printk(" E6 l pll ganting : %s\n",
+ tda9887_info(" E6 l pll gating : %s\n",
(buf[3] & 0x40) ? "36" : "13");
if (buf[1] & 0x08) {
/* radio */
- printk(" E2-4 video if : %s\n",
+ tda9887_info(" E2-4 video if : %s\n",
rif[(buf[3] & 0x0c) >> 2]);
- printk(" E7 vif agc output : %s\n",
+ tda9887_info(" E7 vif agc output : %s\n",
(buf[3] & 0x80)
? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio")
: "fm radio carrier afc");
} else {
/* video */
- printk(" E2-4 video if : %s\n",
+ tda9887_info(" E2-4 video if : %s\n",
vif[(buf[3] & 0x1c) >> 2]);
- printk(" E5 tuner gain : %s\n",
+ tda9887_info(" E5 tuner gain : %s\n",
(buf[3] & 0x80)
? ((buf[3] & 0x20) ? "external" : "normal")
: ((buf[3] & 0x20) ? "minimum" : "normal"));
- printk(" E7 vif agc output : %s\n",
+ tda9887_info(" E7 vif agc output : %s\n",
(buf[3] & 0x80)
? ((buf[3] & 0x20)
? "pin3 port, pin22 vif agc out"
: "pin22 port, pin3 vif acg ext in")
: "pin3+pin22 port");
}
- printk("--\n");
+ tda9887_info("--\n");
}
/* ---------------------------------------------------------------------- */
@@ -379,11 +385,11 @@ static int tda9887_set_tvnorm(struct tda9887 *t, char *buf)
}
}
if (NULL == norm) {
- dprintk(PREFIX "Unsupported tvnorm entry - audio muted\n");
+ tda9887_dbg("Unsupported tvnorm entry - audio muted\n");
return -1;
}
- dprintk(PREFIX "configure for: %s\n",norm->name);
+ tda9887_dbg("configure for: %s\n",norm->name);
buf[1] = norm->b;
buf[2] = norm->c;
buf[3] = norm->e;
@@ -458,6 +464,8 @@ static int tda9887_set_config(struct tda9887 *t, char *buf)
break;
}
}
+ if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
+ buf[1] &= ~cQSS;
return 0;
}
@@ -475,11 +483,11 @@ static int tda9887_set_pinnacle(struct tda9887 *t, char *buf)
}
}
if (t->std & V4L2_STD_525_60) {
- if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) {
+ if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) {
bCarrierMode = cIntercarrier;
} else {
bCarrierMode = cQSS;
- }
+ }
}
if (bCarrierMode != UNSET) {
@@ -505,26 +513,26 @@ static int tda9887_fixup_std(struct tda9887 *t)
case 'B':
case 'g':
case 'G':
- dprintk(PREFIX "insmod fixup: PAL => PAL-BG\n");
+ tda9887_dbg("insmod fixup: PAL => PAL-BG\n");
t->std = V4L2_STD_PAL_BG;
break;
case 'i':
case 'I':
- dprintk(PREFIX "insmod fixup: PAL => PAL-I\n");
+ tda9887_dbg("insmod fixup: PAL => PAL-I\n");
t->std = V4L2_STD_PAL_I;
break;
case 'd':
case 'D':
case 'k':
case 'K':
- dprintk(PREFIX "insmod fixup: PAL => PAL-DK\n");
+ tda9887_dbg("insmod fixup: PAL => PAL-DK\n");
t->std = V4L2_STD_PAL_DK;
break;
case '-':
/* default parameter, do nothing */
break;
default:
- printk(PREFIX "pal= argument not recognised\n");
+ tda9887_info("pal= argument not recognised\n");
break;
}
}
@@ -534,19 +542,19 @@ static int tda9887_fixup_std(struct tda9887 *t)
case 'D':
case 'k':
case 'K':
- dprintk(PREFIX "insmod fixup: SECAM => SECAM-DK\n");
+ tda9887_dbg("insmod fixup: SECAM => SECAM-DK\n");
t->std = V4L2_STD_SECAM_DK;
break;
case 'l':
case 'L':
- dprintk(PREFIX "insmod fixup: SECAM => SECAM-L\n");
+ tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
t->std = V4L2_STD_SECAM_L;
break;
case '-':
/* default parameter, do nothing */
break;
default:
- printk(PREFIX "secam= argument not recognised\n");
+ tda9887_info("secam= argument not recognised\n");
break;
}
}
@@ -559,41 +567,40 @@ static int tda9887_status(struct tda9887 *t)
int rc;
memset(buf,0,sizeof(buf));
- if (1 != (rc = i2c_master_recv(&t->client,buf,1)))
- printk(PREFIX "i2c i/o error: rc == %d (should be 1)\n",rc);
- dump_read_message(buf);
+ if (1 != (rc = i2c_master_recv(&t->client,buf,1)))
+ tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
+ dump_read_message(t, buf);
return 0;
}
static int tda9887_configure(struct tda9887 *t)
{
- unsigned char buf[4];
int rc;
- memset(buf,0,sizeof(buf));
- tda9887_set_tvnorm(t,buf);
+ memset(t->data,0,sizeof(t->data));
+ tda9887_set_tvnorm(t,t->data);
- buf[1] |= cOutputPort1Inactive;
- buf[1] |= cOutputPort2Inactive;
+ t->data[1] |= cOutputPort1Inactive;
+ t->data[1] |= cOutputPort2Inactive;
if (UNSET != t->pinnacle_id) {
- tda9887_set_pinnacle(t,buf);
+ tda9887_set_pinnacle(t,t->data);
}
- tda9887_set_config(t,buf);
- tda9887_set_insmod(t,buf);
+ tda9887_set_config(t,t->data);
+ tda9887_set_insmod(t,t->data);
if (t->mode == T_STANDBY) {
- buf[1] |= cForcedMuteAudioON;
+ t->data[1] |= cForcedMuteAudioON;
}
- dprintk(PREFIX "writing: b=0x%02x c=0x%02x e=0x%02x\n",
- buf[1],buf[2],buf[3]);
+ tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
+ t->data[1],t->data[2],t->data[3]);
if (debug > 1)
- dump_write_message(buf);
+ dump_write_message(t, t->data);
- if (4 != (rc = i2c_master_send(&t->client,buf,4)))
- printk(PREFIX "i2c i/o error: rc == %d (should be 4)\n",rc);
+ if (4 != (rc = i2c_master_send(&t->client,t->data,4)))
+ tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
if (debug > 2) {
msleep_interruptible(1000);
@@ -608,13 +615,11 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct tda9887 *t;
- client_template.adapter = adap;
- client_template.addr = addr;
-
- printk(PREFIX "chip found @ 0x%x\n", addr<<1);
+ client_template.adapter = adap;
+ client_template.addr = addr;
- if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
- return -ENOMEM;
+ if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
+ return -ENOMEM;
memset(t,0,sizeof(*t));
t->client = client_template;
@@ -622,6 +627,8 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
t->pinnacle_id = UNSET;
t->radio_mode = V4L2_TUNER_MODE_STEREO;
+ tda9887_info("chip found @ 0x%x (%s)\n", addr<<1, adap->name);
+
i2c_set_clientdata(&t->client, t);
i2c_attach_client(&t->client);
@@ -655,18 +662,18 @@ static int tda9887_detach(struct i2c_client *client)
}
#define SWITCH_V4L2 if (!t->using_v4l2 && debug) \
- printk(PREFIX "switching to v4l2\n"); \
- t->using_v4l2 = 1;
+ tda9887_info("switching to v4l2\n"); \
+ t->using_v4l2 = 1;
#define CHECK_V4L2 if (t->using_v4l2) { if (debug) \
- printk(PREFIX "ignore v4l1 call\n"); \
- return 0; }
+ tda9887_info("ignore v4l1 call\n"); \
+ return 0; }
static int
tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct tda9887 *t = i2c_get_clientdata(client);
- switch (cmd) {
+ switch (cmd) {
/* --- configuration --- */
case AUDC_SET_RADIO:
@@ -777,6 +784,11 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
}
break;
}
+ case VIDIOC_LOG_STATUS:
+ {
+ tda9887_info("Data bytes: b=%02x c=%02x e=%02x\n", t->data[1], t->data[2], t->data[3]);
+ break;
+ }
default:
/* nothing */
break;
@@ -786,7 +798,10 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
static int tda9887_suspend(struct device * dev, pm_message_t state)
{
- dprintk("tda9887: suspend\n");
+ struct i2c_client *c = container_of(dev, struct i2c_client, dev);
+ struct tda9887 *t = i2c_get_clientdata(c);
+
+ tda9887_dbg("suspend\n");
return 0;
}
@@ -795,7 +810,7 @@ static int tda9887_resume(struct device * dev)
struct i2c_client *c = container_of(dev, struct i2c_client, dev);
struct tda9887 *t = i2c_get_clientdata(c);
- dprintk("tda9887: resume\n");
+ tda9887_dbg("resume\n");
tda9887_configure(t);
return 0;
}
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index 38bf5094379..a9375ef05de 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/video/tea5767.c
@@ -117,10 +117,10 @@
#define TEA5767_RESERVED_MASK 0xff
enum tea5767_xtal_freq {
- TEA5767_LOW_LO_32768 = 0,
- TEA5767_HIGH_LO_32768 = 1,
- TEA5767_LOW_LO_13MHz = 2,
- TEA5767_HIGH_LO_13MHz = 3,
+ TEA5767_LOW_LO_32768 = 0,
+ TEA5767_HIGH_LO_32768 = 1,
+ TEA5767_LOW_LO_13MHz = 2,
+ TEA5767_HIGH_LO_13MHz = 3,
};
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index ad85bef1c3d..73c4041c35d 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -28,7 +28,7 @@
/* standard i2c insmod options */
static unsigned short normal_i2c[] = {
- 0x4b, /* tda8290 */
+ 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
I2C_CLIENT_END
@@ -189,6 +189,13 @@ static void set_type(struct i2c_client *c, unsigned int type,
i2c_master_send(c, buffer, 4);
default_tuner_init(c);
break;
+ case TUNER_PHILIPS_TD1316:
+ buffer[0] = 0x0b;
+ buffer[1] = 0xdc;
+ buffer[2] = 0x86;
+ buffer[3] = 0xa4;
+ i2c_master_send(c,buffer,4);
+ default_tuner_init(c);
default:
default_tuner_init(c);
break;
@@ -215,9 +222,9 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
{
struct tuner *t = i2c_get_clientdata(c);
- if ((tun_setup->addr == ADDR_UNSET &&
+ if ( t->type == UNSET && ((tun_setup->addr == ADDR_UNSET &&
(t->mode_mask & tun_setup->mode_mask)) ||
- tun_setup->addr == c->addr) {
+ tun_setup->addr == c->addr)) {
set_type(c, tun_setup->type, tun_setup->mode_mask);
}
}
@@ -341,23 +348,33 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
t->audmode = V4L2_TUNER_MODE_STEREO;
t->mode_mask = T_UNINITIALIZED;
-
- tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
-
if (show_i2c) {
unsigned char buffer[16];
int i,rc;
memset(buffer, 0, sizeof(buffer));
rc = i2c_master_recv(&t->i2c, buffer, sizeof(buffer));
- printk("tuner-%04x I2C RECV = ",addr);
+ tuner_info("I2C RECV = ");
for (i=0;i<rc;i++)
printk("%02x ",buffer[i]);
printk("\n");
}
/* TEA5767 autodetection code - only for addr = 0xc0 */
if (!no_autodetect) {
- if (addr == 0x60) {
+ switch (addr) {
+ case 0x42:
+ case 0x43:
+ case 0x4a:
+ case 0x4b:
+ /* If chip is not tda8290, don't register.
+ since it can be tda9887*/
+ if (tda8290_probe(&t->i2c) != 0) {
+ tuner_dbg("chip at addr %x is not a tda8290\n", addr);
+ kfree(t);
+ return 0;
+ }
+ break;
+ case 0x60:
if (tea5767_autodetection(&t->i2c) != EINVAL) {
t->type = TUNER_TEA5767;
t->mode_mask = T_RADIO;
@@ -365,10 +382,9 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
t->freq = 87.5 * 16; /* Sets freq to FM range */
default_mode_mask &= ~T_RADIO;
- i2c_attach_client (&t->i2c);
- set_type(&t->i2c,t->type, t->mode_mask);
- return 0;
+ goto register_client;
}
+ break;
}
}
@@ -381,6 +397,8 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
}
/* Should be just before return */
+register_client:
+ tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
i2c_attach_client (&t->i2c);
set_type (&t->i2c,t->type, t->mode_mask);
return 0;
@@ -425,23 +443,23 @@ static int tuner_detach(struct i2c_client *client)
static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
{
- if (mode == t->mode)
- return 0;
-
- t->mode = mode;
-
- if (check_mode(t, cmd) == EINVAL) {
- t->mode = T_STANDBY;
- if (t->standby)
- t->standby (client);
- return EINVAL;
- }
- return 0;
+ if (mode == t->mode)
+ return 0;
+
+ t->mode = mode;
+
+ if (check_mode(t, cmd) == EINVAL) {
+ t->mode = T_STANDBY;
+ if (t->standby)
+ t->standby (client);
+ return EINVAL;
+ }
+ return 0;
}
#define switch_v4l2() if (!t->using_v4l2) \
- tuner_dbg("switching to v4l2\n"); \
- t->using_v4l2 = 1;
+ tuner_dbg("switching to v4l2\n"); \
+ t->using_v4l2 = 1;
static inline int check_v4l2(struct tuner *t)
{
@@ -479,8 +497,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
}
case AUDC_CONFIG_PINNACLE:
- if (check_mode(t, "AUDC_CONFIG_PINNACLE") == EINVAL)
- return 0;
switch (*iarg) {
case 2:
tuner_dbg("pinnacle pal\n");
@@ -616,7 +632,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
switch_v4l2();
if (V4L2_TUNER_RADIO == f->type &&
V4L2_TUNER_RADIO != t->mode) {
- if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
+ if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
== EINVAL)
return 0;
}
@@ -688,7 +704,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
}
default:
- tuner_dbg("Unimplemented IOCTL 0x%08x(dir=%d,tp=0x%02x,nr=%d,sz=%d)\n",
+ tuner_dbg("Unimplemented IOCTL 0x%08x(dir=%d,tp='%c',nr=%d,sz=%d)\n",
cmd, _IOC_DIR(cmd), _IOC_TYPE(cmd),
_IOC_NR(cmd), _IOC_SIZE(cmd));
break;
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index 8edd73abe1d..d832205818f 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -102,7 +102,7 @@ struct tunertype
*/
static struct tunertype tuners[] = {
/* 0-9 */
- { "Temic PAL (4002 FH5)", TEMIC, PAL,
+ { "Temic PAL (4002 FH5)", TEMIC, PAL,
16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623},
{ "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I,
16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
@@ -118,41 +118,41 @@ static struct tunertype tuners[] = {
16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732},
{ "Temic PAL_I (4062 FY5)", TEMIC, PAL_I,
16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623},
- { "Temic NTSC (4036 FY5)", TEMIC, NTSC,
+ { "Temic NTSC (4036 FY5)", TEMIC, NTSC,
16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732},
- { "Alps HSBH1", TEMIC, NTSC,
+ { "Alps HSBH1", TEMIC, NTSC,
16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
/* 10-19 */
- { "Alps TSBE1", TEMIC, PAL,
+ { "Alps TSBE1", TEMIC, PAL,
16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732},
- { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */
+ { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modulartech MM205 */
16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632},
- { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
+ { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622},
- { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
+ { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */
16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608},
{ "Temic PAL_BG (4006FH5)", TEMIC, PAL,
16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
- { "Alps TSCH6", Alps, NTSC,
- 16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
- { "Temic PAL_DK (4016 FY5)", TEMIC, PAL,
- 16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623},
- { "Philips NTSC_M (MK2)", Philips, NTSC,
- 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
- { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I,
- 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
- { "Temic PAL* auto (4006 FN5)", TEMIC, PAL,
- 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+ { "Alps TSCH6", Alps, NTSC,
+ 16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
+ { "Temic PAL_DK (4016 FY5)", TEMIC, PAL,
+ 16*168.25,16*456.25,0xa0,0x90,0x30,0x8e,623},
+ { "Philips NTSC_M (MK2)", Philips, NTSC,
+ 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
+ { "Temic PAL_I (4066 FY5)", TEMIC, PAL_I,
+ 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+ { "Temic PAL* auto (4006 FN5)", TEMIC, PAL,
+ 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
/* 20-29 */
- { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL,
- 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
- { "Temic NTSC (4039 FR5)", TEMIC, NTSC,
- 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
- { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL,
- 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
- { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL,
+ { "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", TEMIC, PAL,
+ 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
+ { "Temic NTSC (4039 FR5)", TEMIC, NTSC,
+ 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
+ { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL,
+ 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623},
+ { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL,
16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
{ "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL,
16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
@@ -173,21 +173,21 @@ static struct tunertype tuners[] = {
{ "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */
16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940 },
{ "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */
- 16*169,16*464,0xA0,0x90,0x30,0x8e,623},
+ 16*169,16*464,0xA0,0x90,0x30,0x8e,623},
{ "MT20xx universal", Microtune, PAL|NTSC,
/* see mt20xx.c for details */ },
{ "Temic PAL_BG (4106 FH5)", TEMIC, PAL,
- 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
+ 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623},
{ "Temic PAL_DK/SECAM_L (4012 FY5)", TEMIC, PAL,
- 16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623},
+ 16*140.25, 16*463.25, 0x02,0x04,0x01,0x8e,623},
{ "Temic NTSC (4136 FY5)", TEMIC, NTSC,
- 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
- { "LG PAL (newer TAPC series)", LGINNOTEK, PAL,
- 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623},
+ 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732},
+ { "LG PAL (newer TAPC series)", LGINNOTEK, PAL,
+ 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623},
{ "Philips PAL/SECAM multi (FM1216ME MK3)", Philips, PAL,
- 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
+ 16*158.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
{ "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC,
- 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732},
+ 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732},
/* 40-49 */
{ "HITACHI V7-J180AT", HITACHI, NTSC,
@@ -196,24 +196,24 @@ static struct tunertype tuners[] = {
16*140.25,16*463.25,0x01,0xc2,0xcf,0x8e,623},
{ "Philips 1236D ATSC/NTSC daul in", Philips, ATSC,
16*157.25,16*454.00,0xa0,0x90,0x30,0x8e,732},
- { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC,
- 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
- { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC,
- 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
+ { "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", Philips, NTSC,
+ 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
+ { "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", Philips, NTSC,
+ 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732},
{ "Microtune 4049 FM5", Microtune, PAL,
16*141.00,16*464.00,0xa0,0x90,0x30,0x8e,623},
{ "Panasonic VP27s/ENGE4324D", Panasonic, NTSC,
16*160.00,16*454.00,0x01,0x02,0x08,0xce,940},
- { "LG NTSC (TAPE series)", LGINNOTEK, NTSC,
- 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
- { "Tenna TNF 8831 BGFF)", Philips, PAL,
- 16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
+ { "LG NTSC (TAPE series)", LGINNOTEK, NTSC,
+ 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
+ { "Tenna TNF 8831 BGFF)", Philips, PAL,
+ 16*161.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
{ "Microtune 4042 FI5 ATSC/NTSC dual in", Microtune, NTSC,
16*162.00,16*457.00,0xa2,0x94,0x31,0x8e,732},
/* 50-59 */
- { "TCL 2002N", TCL, NTSC,
- 16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732},
+ { "TCL 2002N", TCL, NTSC,
+ 16*172.00,16*448.00,0x01,0x02,0x08,0x8e,732},
{ "Philips PAL/SECAM_D (FM 1256 I-H3)", Philips, PAL,
16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
{ "Thomson DDT 7610 (ATSC/NTSC)", THOMSON, ATSC,
@@ -222,8 +222,8 @@ static struct tunertype tuners[] = {
16*160.00,16*454.00,0x41,0x42,0x04,0x8e,940}, /* UHF band untested */
{ "tda8290+75", Philips, PAL|NTSC,
/* see tda8290.c for details */ },
- { "LG PAL (TAPE series)", LGINNOTEK, PAL,
- 16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623},
+ { "TCL 2002MB", TCL, PAL,
+ 16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623},
{ "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL,
16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 },
{ "Philips FQ1236A MK4", Philips, NTSC,
@@ -233,21 +233,25 @@ static struct tunertype tuners[] = {
{ "Ymec TVision TVF-5533MF", Philips, NTSC,
16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732},
- /* 60-66 */
+ /* 60-68 */
{ "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC,
16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732},
{ "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL,
- 16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623},
+ 16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623},
{ "Philips TEA5767HN FM Radio", Philips, RADIO,
- /* see tea5767.c for details */},
+ /* see tea5767.c for details */},
{ "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL,
16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 },
{ "LG TDVS-H062F/TUA6034", LGINNOTEK, ATSC,
16*160.00,16*455.00,0x01,0x02,0x04,0x8e,732},
{ "Ymec TVF66T5-B/DFF", Philips, PAL,
- 16*160.25,16*464.25,0x01,0x02,0x08,0x8e,623},
- { "LG NTSC (TALN mini series)", LGINNOTEK, NTSC,
+ 16*160.25,16*464.25,0x01,0x02,0x08,0x8e,623},
+ { "LG NTSC (TALN mini series)", LGINNOTEK, NTSC,
16*137.25,16*373.25,0x01,0x02,0x08,0x8e,732 },
+ { "Philips TD1316 Hybrid Tuner", Philips, PAL,
+ 16*160.00,16*442.00,0xa1,0xa2,0xa4,0xc8,623 },
+ { "Philips TUV1236D ATSC/NTSC dual in", Philips, ATSC,
+ 16*157.25,16*454.00,0x01,0x02,0x04,0xce,732 },
};
unsigned const int tuner_count = ARRAY_SIZE(tuners);
@@ -277,7 +281,7 @@ static int tuner_stereo(struct i2c_client *c)
status = tuner_getstatus (c);
switch (t->type) {
- case TUNER_PHILIPS_FM1216ME_MK3:
+ case TUNER_PHILIPS_FM1216ME_MK3:
case TUNER_PHILIPS_FM1236_MK3:
case TUNER_PHILIPS_FM1256_IH3:
stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
@@ -295,10 +299,10 @@ static int tuner_stereo(struct i2c_client *c)
static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
{
struct tuner *t = i2c_get_clientdata(c);
- u8 config;
+ u8 config, tuneraddr;
u16 div;
struct tunertype *tun;
- unsigned char buffer[4];
+ unsigned char buffer[4];
int rc;
tun = &tuners[t->type];
@@ -373,6 +377,31 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
/* Set the charge pump for fast tuning */
tun->config |= TUNER_CHARGE_PUMP;
break;
+
+ case TUNER_PHILIPS_TUV1236D:
+ /* 0x40 -> ATSC antenna input 1 */
+ /* 0x48 -> ATSC antenna input 2 */
+ /* 0x00 -> NTSC antenna input 1 */
+ /* 0x08 -> NTSC antenna input 2 */
+ buffer[0] = 0x14;
+ buffer[1] = 0x00;
+ buffer[2] = 0x17;
+ buffer[3] = 0x00;
+ config &= ~0x40;
+ if (t->std & V4L2_STD_ATSC) {
+ config |= 0x40;
+ buffer[1] = 0x04;
+ }
+ /* set to the correct mode (analog or digital) */
+ tuneraddr = c->addr;
+ c->addr = 0x0a;
+ if (2 != (rc = i2c_master_send(c,&buffer[0],2)))
+ tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
+ if (2 != (rc = i2c_master_send(c,&buffer[2],2)))
+ tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
+ c->addr = tuneraddr;
+ /* FIXME: input */
+ break;
}
/*
@@ -404,7 +433,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
buffer[0],buffer[1],buffer[2],buffer[3]);
- if (4 != (rc = i2c_master_send(c,buffer,4)))
+ if (4 != (rc = i2c_master_send(c,buffer,4)))
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
if (t->type == TUNER_MICROTUNE_4042FI5) {
@@ -443,7 +472,7 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
{
struct tunertype *tun;
struct tuner *t = i2c_get_clientdata(c);
- unsigned char buffer[4];
+ unsigned char buffer[4];
unsigned div;
int rc;
@@ -476,13 +505,13 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
buffer[3] = 0xa4;
break;
}
- buffer[0] = (div>>8) & 0x7f;
- buffer[1] = div & 0xff;
+ buffer[0] = (div>>8) & 0x7f;
+ buffer[1] = div & 0xff;
tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
buffer[0],buffer[1],buffer[2],buffer[3]);
- if (4 != (rc = i2c_master_send(c,buffer,4)))
+ if (4 != (rc = i2c_master_send(c,buffer,4)))
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
}
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 1c31ef52f86..c31bf28b73f 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -31,7 +31,6 @@
#include <linux/smp_lock.h>
#include <media/audiochip.h>
-#include <media/id.h>
#include "tvaudio.h"
@@ -458,8 +457,8 @@ static void tda9840_setmode(struct CHIPSTATE *chip, int mode)
#define TDA9855_LOUD 1<<5 /* Loudness, 1==off */
#define TDA9855_SUR 1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */
/* Bits 0 to 3 select various combinations
- * of line in and line out, only the
- * interesting ones are defined */
+ * of line in and line out, only the
+ * interesting ones are defined */
#define TDA9855_EXT 1<<2 /* Selects inputs LIR and LIL. Pins 41 & 12 */
#define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */
@@ -1028,7 +1027,7 @@ static int tda9874a_initialize(struct CHIPSTATE *chip)
#define TEA6300_TR 0x03 /* treble */
#define TEA6300_FA 0x04 /* fader control */
#define TEA6300_S 0x05 /* switch register */
- /* values for those registers: */
+ /* values for those registers: */
#define TEA6300_S_SA 0x01 /* stereo A input */
#define TEA6300_S_SB 0x02 /* stereo B */
#define TEA6300_S_SC 0x04 /* stereo C */
@@ -1042,7 +1041,7 @@ static int tda9874a_initialize(struct CHIPSTATE *chip)
#define TEA6320_BA 0x05 /* bass (0-4) */
#define TEA6320_TR 0x06 /* treble (0-4) */
#define TEA6320_S 0x07 /* switch register */
- /* values for those registers: */
+ /* values for those registers: */
#define TEA6320_S_SA 0x07 /* stereo A input */
#define TEA6320_S_SB 0x06 /* stereo B */
#define TEA6320_S_SC 0x05 /* stereo C */
@@ -1082,7 +1081,7 @@ static int tea6320_initialize(struct CHIPSTATE * chip)
#define TDA8425_BA 0x02 /* bass */
#define TDA8425_TR 0x03 /* treble */
#define TDA8425_S1 0x08 /* switch functions */
- /* values for those registers: */
+ /* values for those registers: */
#define TDA8425_S1_OFF 0xEE /* audio off (mute on) */
#define TDA8425_S1_CH1 0xCE /* audio channel 1 (mute off) - "linear stereo" mode */
#define TDA8425_S1_CH2 0xCF /* audio channel 2 (mute off) - "linear stereo" mode */
@@ -1148,7 +1147,7 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
/* bit definition of the RESET register, I2C data. */
#define PIC16C54_MISC_RESET_REMOTE_CTL 0x01 /* bit 0, Reset to receive the key */
- /* code of remote controller */
+ /* code of remote controller */
#define PIC16C54_MISC_MTS_MAIN 0x02 /* bit 1 */
#define PIC16C54_MISC_MTS_SAP 0x04 /* bit 2 */
#define PIC16C54_MISC_MTS_BOTH 0x08 /* bit 3 */
@@ -1281,7 +1280,7 @@ static struct CHIPDESC chiplist[] = {
.setmode = tda9840_setmode,
.checkmode = generic_checkmode,
- .init = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
+ .init = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
/* ,TDA9840_SW, TDA9840_MONO */} }
},
{
@@ -1438,7 +1437,7 @@ static struct CHIPDESC chiplist[] = {
},
{
.name = "pic16c54 (PV951)",
- .id = I2C_DRIVERID_PIC16C54_PV951,
+ .id = I2C_DRIVERID_PIC16C54_PV9,
.insmodopt = &pic16c54,
.addr_lo = I2C_PIC16C54 >> 1,
.addr_hi = I2C_PIC16C54>> 1,
@@ -1467,7 +1466,7 @@ static struct CHIPDESC chiplist[] = {
.setmode = ta8874z_setmode,
.checkmode = generic_checkmode,
- .init = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}},
+ .init = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}},
},
{ .name = NULL } /* EOF */
};
@@ -1486,8 +1485,8 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
return -ENOMEM;
memset(chip,0,sizeof(*chip));
memcpy(&chip->c,&client_template,sizeof(struct i2c_client));
- chip->c.adapter = adap;
- chip->c.addr = addr;
+ chip->c.adapter = adap;
+ chip->c.addr = addr;
i2c_set_clientdata(&chip->c, chip);
/* find description for the chip */
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 5344d559219..72e8741e8b5 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -6,12 +6,12 @@
* which are:
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
- & Marcus Metzler (mocm@thp.uni-koeln.de)
+ & Marcus Metzler (mocm@thp.uni-koeln.de)
(c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
* Adjustments to fit a more general model and all bugs:
- Copyright (C) 2003 John Klar <linpvr at projectplasma.com>
+ Copyright (C) 2003 John Klar <linpvr at projectplasma.com>
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -40,6 +40,7 @@
#include <media/tuner.h>
#include <media/tveeprom.h>
+#include <media/audiochip.h>
MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver");
MODULE_AUTHOR("John Klar");
@@ -53,14 +54,14 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
#define tveeprom_info(fmt, arg...) do {\
printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
- c->adapter->nr, c->addr , ##arg); } while (0)
+ c->adapter->nr, c->addr , ##arg); } while (0)
#define tveeprom_warn(fmt, arg...) do {\
printk(KERN_WARNING "tveeprom %d-%04x: " fmt, \
- c->adapter->nr, c->addr , ##arg); } while (0)
+ c->adapter->nr, c->addr , ##arg); } while (0)
#define tveeprom_dbg(fmt, arg...) do {\
if (debug) \
- printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
- c->adapter->nr, c->addr , ##arg); } while (0)
+ printk(KERN_INFO "tveeprom %d-%04x: " fmt, \
+ c->adapter->nr, c->addr , ##arg); } while (0)
/* ----------------------------------------------------------------------- */
@@ -134,8 +135,8 @@ hauppauge_tuner[] =
{ TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
{ TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" },
{ TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
- { TUNER_PHILIPS_NTSC, "Philips TD1536" },
- { TUNER_PHILIPS_NTSC, "Philips TD1536D" },
+ { TUNER_PHILIPS_NTSC, "Philips TD1536" },
+ { TUNER_PHILIPS_NTSC, "Philips TD1536D" },
{ TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */
{ TUNER_ABSENT, "Philips FI1256MP" },
/* 40-49 */
@@ -189,7 +190,7 @@ hauppauge_tuner[] =
{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"},
{ TUNER_TCL_2002N, "TCL 2002N 6A"},
- { TUNER_ABSENT, "Philips FQ1236 MK3"},
+ { TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"},
{ TUNER_ABSENT, "Samsung TCPN 2121P30A"},
{ TUNER_ABSENT, "Samsung TCPE 4121P30A"},
{ TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"},
@@ -200,95 +201,137 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "Philips FQ1286A MK4"},
{ TUNER_ABSENT, "Philips FQ1216ME MK5"},
{ TUNER_ABSENT, "Philips FQ1236 MK5"},
- { TUNER_ABSENT, "Unspecified"},
- { TUNER_LG_PAL_TAPE, "LG PAL (TAPE Series)"},
- { TUNER_ABSENT, "Unspecified"},
- { TUNER_TCL_2002N, "TCL 2002N 5H"},
- /* 100-103 */
- { TUNER_ABSENT, "Unspecified"},
- { TUNER_TEA5767, "Philips TEA5767HN FM Radio"},
- { TUNER_ABSENT, "Unspecified"},
- { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05 4"},
+ { TUNER_ABSENT, "Samsung TCPG_6121P30A"},
+ { TUNER_TCL_2002MB, "TCL 2002MB_3H"},
+ { TUNER_ABSENT, "TCL 2002MI_3H"},
+ { TUNER_TCL_2002N, "TCL 2002N 5H"},
+ /* 100-109 */
+ { TUNER_ABSENT, "Philips FMD1216ME"},
+ { TUNER_TEA5767, "Philips TEA5768HL FM Radio"},
+ { TUNER_ABSENT, "Panasonic ENV57H12D5"},
+ { TUNER_ABSENT, "TCL MFNM05-4"},
+ { TUNER_ABSENT, "TCL MNM05-4"},
+ { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"},
+ { TUNER_ABSENT, "TCL MQNM05-4"},
+ { TUNER_ABSENT, "LG TAPC-W701D"},
+ { TUNER_ABSENT, "TCL 9886P-WM"},
+ { TUNER_ABSENT, "TCL 1676NM-WM"},
};
-/* This list is supplied by Hauppauge. Thanks! */
-static const char *audioIC[] = {
- /* 0-4 */
- "None", "TEA6300", "TEA6320", "TDA9850", "MSP3400C",
- /* 5-9 */
- "MSP3410D", "MSP3415", "MSP3430", "MSP3438", "CS5331",
- /* 10-14 */
- "MSP3435", "MSP3440", "MSP3445", "MSP3411", "MSP3416",
- /* 15-19 */
- "MSP3425", "MSP3451", "MSP3418", "Type 0x12", "OKI7716",
- /* 20-24 */
- "MSP4410", "MSP4420", "MSP4440", "MSP4450", "MSP4408",
- /* 25-29 */
- "MSP4418", "MSP4428", "MSP4448", "MSP4458", "Type 0x1d",
- /* 30-34 */
- "CX880", "CX881", "CX883", "CX882", "CX25840",
- /* 35-38 */
- "CX25841", "CX25842", "CX25843", "CX23418",
+static struct HAUPPAUGE_AUDIOIC
+{
+ enum audiochip id;
+ char *name;
+}
+audioIC[] =
+{
+ /* 0-4 */
+ {AUDIO_CHIP_NONE, "None"},
+ {AUDIO_CHIP_TEA6300, "TEA6300"},
+ {AUDIO_CHIP_TEA6300, "TEA6320"},
+ {AUDIO_CHIP_TDA985X, "TDA9850"},
+ {AUDIO_CHIP_MSP34XX, "MSP3400C"},
+ /* 5-9 */
+ {AUDIO_CHIP_MSP34XX, "MSP3410D"},
+ {AUDIO_CHIP_MSP34XX, "MSP3415"},
+ {AUDIO_CHIP_MSP34XX, "MSP3430"},
+ {AUDIO_CHIP_UNKNOWN, "MSP3438"},
+ {AUDIO_CHIP_UNKNOWN, "CS5331"},
+ /* 10-14 */
+ {AUDIO_CHIP_MSP34XX, "MSP3435"},
+ {AUDIO_CHIP_MSP34XX, "MSP3440"},
+ {AUDIO_CHIP_MSP34XX, "MSP3445"},
+ {AUDIO_CHIP_UNKNOWN, "MSP3411"},
+ {AUDIO_CHIP_UNKNOWN, "MSP3416"},
+ /* 15-19 */
+ {AUDIO_CHIP_MSP34XX, "MSP3425"},
+ {AUDIO_CHIP_UNKNOWN, "MSP3451"},
+ {AUDIO_CHIP_UNKNOWN, "MSP3418"},
+ {AUDIO_CHIP_UNKNOWN, "Type 0x12"},
+ {AUDIO_CHIP_UNKNOWN, "OKI7716"},
+ /* 20-24 */
+ {AUDIO_CHIP_UNKNOWN, "MSP4410"},
+ {AUDIO_CHIP_UNKNOWN, "MSP4420"},
+ {AUDIO_CHIP_UNKNOWN, "MSP4440"},
+ {AUDIO_CHIP_UNKNOWN, "MSP4450"},
+ {AUDIO_CHIP_UNKNOWN, "MSP4408"},
+ /* 25-29 */
+ {AUDIO_CHIP_UNKNOWN, "MSP4418"},
+ {AUDIO_CHIP_UNKNOWN, "MSP4428"},
+ {AUDIO_CHIP_UNKNOWN, "MSP4448"},
+ {AUDIO_CHIP_UNKNOWN, "MSP4458"},
+ {AUDIO_CHIP_UNKNOWN, "Type 0x1d"},
+ /* 30-34 */
+ {AUDIO_CHIP_INTERNAL, "CX880"},
+ {AUDIO_CHIP_INTERNAL, "CX881"},
+ {AUDIO_CHIP_INTERNAL, "CX883"},
+ {AUDIO_CHIP_INTERNAL, "CX882"},
+ {AUDIO_CHIP_INTERNAL, "CX25840"},
+ /* 35-38 */
+ {AUDIO_CHIP_INTERNAL, "CX25841"},
+ {AUDIO_CHIP_INTERNAL, "CX25842"},
+ {AUDIO_CHIP_INTERNAL, "CX25843"},
+ {AUDIO_CHIP_INTERNAL, "CX23418"},
};
/* This list is supplied by Hauppauge. Thanks! */
static const char *decoderIC[] = {
- /* 0-4 */
- "None", "BT815", "BT817", "BT819", "BT815A",
- /* 5-9 */
- "BT817A", "BT819A", "BT827", "BT829", "BT848",
- /* 10-14 */
- "BT848A", "BT849A", "BT829A", "BT827A", "BT878",
- /* 15-19 */
- "BT879", "BT880", "VPX3226E", "SAA7114", "SAA7115",
- /* 20-24 */
- "CX880", "CX881", "CX883", "SAA7111", "SAA7113",
- /* 25-29 */
- "CX882", "TVP5150A", "CX25840", "CX25841", "CX25842",
- /* 30-31 */
- "CX25843", "CX23418",
+ /* 0-4 */
+ "None", "BT815", "BT817", "BT819", "BT815A",
+ /* 5-9 */
+ "BT817A", "BT819A", "BT827", "BT829", "BT848",
+ /* 10-14 */
+ "BT848A", "BT849A", "BT829A", "BT827A", "BT878",
+ /* 15-19 */
+ "BT879", "BT880", "VPX3226E", "SAA7114", "SAA7115",
+ /* 20-24 */
+ "CX880", "CX881", "CX883", "SAA7111", "SAA7113",
+ /* 25-29 */
+ "CX882", "TVP5150A", "CX25840", "CX25841", "CX25842",
+ /* 30-31 */
+ "CX25843", "CX23418",
};
static int hasRadioTuner(int tunerType)
{
- switch (tunerType) {
- case 18: //PNPEnv_TUNER_FR1236_MK2:
- case 23: //PNPEnv_TUNER_FM1236:
- case 38: //PNPEnv_TUNER_FMR1236:
- case 16: //PNPEnv_TUNER_FR1216_MK2:
- case 19: //PNPEnv_TUNER_FR1246_MK2:
- case 21: //PNPEnv_TUNER_FM1216:
- case 24: //PNPEnv_TUNER_FM1246:
- case 17: //PNPEnv_TUNER_FR1216MF_MK2:
- case 22: //PNPEnv_TUNER_FM1216MF:
- case 20: //PNPEnv_TUNER_FR1256_MK2:
- case 25: //PNPEnv_TUNER_FM1256:
- case 33: //PNPEnv_TUNER_4039FR5:
- case 42: //PNPEnv_TUNER_4009FR5:
- case 52: //PNPEnv_TUNER_4049FM5:
- case 54: //PNPEnv_TUNER_4049FM5_AltI2C:
- case 44: //PNPEnv_TUNER_4009FN5:
- case 31: //PNPEnv_TUNER_TCPB9085P:
- case 30: //PNPEnv_TUNER_TCPN9085D:
- case 46: //PNPEnv_TUNER_TP18NSR01F:
- case 47: //PNPEnv_TUNER_TP18PSB01D:
- case 49: //PNPEnv_TUNER_TAPC_I001D:
- case 60: //PNPEnv_TUNER_TAPE_S001D_MK3:
- case 57: //PNPEnv_TUNER_FM1216ME_MK3:
- case 59: //PNPEnv_TUNER_FM1216MP_MK3:
- case 58: //PNPEnv_TUNER_FM1236_MK3:
- case 68: //PNPEnv_TUNER_TAPE_H001F_MK3:
- case 61: //PNPEnv_TUNER_TAPE_M001D_MK3:
- case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM:
- case 89: //PNPEnv_TUNER_TCL_MFPE05_2:
- case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4:
- return 1;
- }
- return 0;
+ switch (tunerType) {
+ case 18: //PNPEnv_TUNER_FR1236_MK2:
+ case 23: //PNPEnv_TUNER_FM1236:
+ case 38: //PNPEnv_TUNER_FMR1236:
+ case 16: //PNPEnv_TUNER_FR1216_MK2:
+ case 19: //PNPEnv_TUNER_FR1246_MK2:
+ case 21: //PNPEnv_TUNER_FM1216:
+ case 24: //PNPEnv_TUNER_FM1246:
+ case 17: //PNPEnv_TUNER_FR1216MF_MK2:
+ case 22: //PNPEnv_TUNER_FM1216MF:
+ case 20: //PNPEnv_TUNER_FR1256_MK2:
+ case 25: //PNPEnv_TUNER_FM1256:
+ case 33: //PNPEnv_TUNER_4039FR5:
+ case 42: //PNPEnv_TUNER_4009FR5:
+ case 52: //PNPEnv_TUNER_4049FM5:
+ case 54: //PNPEnv_TUNER_4049FM5_AltI2C:
+ case 44: //PNPEnv_TUNER_4009FN5:
+ case 31: //PNPEnv_TUNER_TCPB9085P:
+ case 30: //PNPEnv_TUNER_TCPN9085D:
+ case 46: //PNPEnv_TUNER_TP18NSR01F:
+ case 47: //PNPEnv_TUNER_TP18PSB01D:
+ case 49: //PNPEnv_TUNER_TAPC_I001D:
+ case 60: //PNPEnv_TUNER_TAPE_S001D_MK3:
+ case 57: //PNPEnv_TUNER_FM1216ME_MK3:
+ case 59: //PNPEnv_TUNER_FM1216MP_MK3:
+ case 58: //PNPEnv_TUNER_FM1236_MK3:
+ case 68: //PNPEnv_TUNER_TAPE_H001F_MK3:
+ case 61: //PNPEnv_TUNER_TAPE_M001D_MK3:
+ case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM:
+ case 89: //PNPEnv_TUNER_TCL_MFPE05_2:
+ case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4:
+ return 1;
+ }
+ return 0;
}
void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
- unsigned char *eeprom_data)
+ unsigned char *eeprom_data)
{
/* ----------------------------------------------
** The hauppauge eeprom format is tagged
@@ -312,19 +355,27 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
** # of inputs/outputs ???
*/
- int i, j, len, done, beenhere, tag;
+ int i, j, len, done, beenhere, tag,start;
- int tuner1 = 0, t_format1 = 0;
+ int tuner1 = 0, t_format1 = 0, audioic=-1;
char *t_name1 = NULL;
- const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" };
+ const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" };
- int tuner2 = 0, t_format2 = 0;
+ int tuner2 = 0, t_format2 = 0;
char *t_name2 = NULL;
- const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" };
+ const char *t_fmt_name2[8] = { " none", "", "", "", "", "", "", "" };
- memset(tvee, 0, sizeof(*tvee));
+ memset(tvee, 0, sizeof(*tvee));
done = len = beenhere = 0;
- for (i = 0; !done && i < 256; i += len) {
+
+ /* Hack for processing eeprom for em28xx */
+ if ((eeprom_data[0]==0x1a)&&(eeprom_data[1]==0xeb)&&
+ (eeprom_data[2]==0x67)&&(eeprom_data[3]==0x95))
+ start=0xa0;
+ else
+ start=0;
+
+ for (i = start; !done && i < 256; i += len) {
if (eeprom_data[i] == 0x84) {
len = eeprom_data[i + 1] + (eeprom_data[i + 2] << 8);
i += 3;
@@ -338,28 +389,28 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
++i;
} else {
tveeprom_warn("Encountered bad packet header [%02x]. "
- "Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]);
+ "Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]);
return;
}
- if (debug) {
- tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1);
- for(j = 1; j < len; j++) {
- printk(" %02x", eeprom_data[i + j]);
- }
- printk("\n");
- }
+ if (debug) {
+ tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1);
+ for(j = 1; j < len; j++) {
+ printk(" %02x", eeprom_data[i + j]);
+ }
+ printk("\n");
+ }
/* process by tag */
tag = eeprom_data[i];
switch (tag) {
case 0x00:
- /* tag: 'Comprehensive' */
+ /* tag: 'Comprehensive' */
tuner1 = eeprom_data[i+6];
t_format1 = eeprom_data[i+5];
tvee->has_radio = eeprom_data[i+len-1];
- /* old style tag, don't know how to detect
- IR presence, mark as unknown. */
+ /* old style tag, don't know how to detect
+ IR presence, mark as unknown. */
tvee->has_ir = 2;
tvee->model =
eeprom_data[i+8] +
@@ -370,7 +421,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
break;
case 0x01:
- /* tag: 'SerialID' */
+ /* tag: 'SerialID' */
tvee->serial_number =
eeprom_data[i+6] +
(eeprom_data[i+7] << 8) +
@@ -378,17 +429,21 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
break;
case 0x02:
- /* tag 'AudioInfo'
- Note mask with 0x7F, high bit used on some older models
- to indicate 4052 mux was removed in favor of using MSP
- inputs directly. */
- tvee->audio_processor = eeprom_data[i+2] & 0x7f;
+ /* tag 'AudioInfo'
+ Note mask with 0x7F, high bit used on some older models
+ to indicate 4052 mux was removed in favor of using MSP
+ inputs directly. */
+ audioic = eeprom_data[i+2] & 0x7f;
+ if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+ tvee->audio_processor = audioIC[audioic].id;
+ else
+ tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
break;
- /* case 0x03: tag 'EEInfo' */
+ /* case 0x03: tag 'EEInfo' */
case 0x04:
- /* tag 'SerialID2' */
+ /* tag 'SerialID2' */
tvee->serial_number =
eeprom_data[i+5] +
(eeprom_data[i+6] << 8) +
@@ -396,15 +451,20 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
break;
case 0x05:
- /* tag 'Audio2'
- Note mask with 0x7F, high bit used on some older models
- to indicate 4052 mux was removed in favor of using MSP
- inputs directly. */
- tvee->audio_processor = eeprom_data[i+1] & 0x7f;
+ /* tag 'Audio2'
+ Note mask with 0x7F, high bit used on some older models
+ to indicate 4052 mux was removed in favor of using MSP
+ inputs directly. */
+ audioic = eeprom_data[i+1] & 0x7f;
+ if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+ tvee->audio_processor = audioIC[audioic].id;
+ else
+ tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
+
break;
case 0x06:
- /* tag 'ModelRev' */
+ /* tag 'ModelRev' */
tvee->model =
eeprom_data[i+1] +
(eeprom_data[i+2] << 8);
@@ -414,55 +474,55 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
break;
case 0x07:
- /* tag 'Details': according to Hauppauge not interesting
- on any PCI-era or later boards. */
+ /* tag 'Details': according to Hauppauge not interesting
+ on any PCI-era or later boards. */
break;
- /* there is no tag 0x08 defined */
+ /* there is no tag 0x08 defined */
case 0x09:
- /* tag 'Video' */
+ /* tag 'Video' */
tvee->decoder_processor = eeprom_data[i + 1];
break;
case 0x0a:
- /* tag 'Tuner' */
+ /* tag 'Tuner' */
if (beenhere == 0) {
tuner1 = eeprom_data[i+2];
t_format1 = eeprom_data[i+1];
beenhere = 1;
} else {
- /* a second (radio) tuner may be present */
+ /* a second (radio) tuner may be present */
tuner2 = eeprom_data[i+2];
t_format2 = eeprom_data[i+1];
- if (t_format2 == 0) { /* not a TV tuner? */
- tvee->has_radio = 1; /* must be radio */
- }
- }
+ if (t_format2 == 0) { /* not a TV tuner? */
+ tvee->has_radio = 1; /* must be radio */
+ }
+ }
break;
- case 0x0b:
- /* tag 'Inputs': according to Hauppauge this is specific
- to each driver family, so no good assumptions can be
- made. */
- break;
+ case 0x0b:
+ /* tag 'Inputs': according to Hauppauge this is specific
+ to each driver family, so no good assumptions can be
+ made. */
+ break;
- /* case 0x0c: tag 'Balun' */
- /* case 0x0d: tag 'Teletext' */
+ /* case 0x0c: tag 'Balun' */
+ /* case 0x0d: tag 'Teletext' */
case 0x0e:
- /* tag: 'Radio' */
+ /* tag: 'Radio' */
tvee->has_radio = eeprom_data[i+1];
break;
- case 0x0f:
- /* tag 'IRInfo' */
- tvee->has_ir = eeprom_data[i+1];
- break;
+ case 0x0f:
+ /* tag 'IRInfo' */
+ tvee->has_ir = eeprom_data[i+1];
+ break;
- /* case 0x10: tag 'VBIInfo' */
- /* case 0x11: tag 'QCInfo' */
- /* case 0x12: tag 'InfoBits' */
+ /* case 0x10: tag 'VBIInfo' */
+ /* case 0x11: tag 'QCInfo' */
+ /* case 0x12: tag 'InfoBits' */
default:
tveeprom_dbg("Not sure what to do with tag [%02x]\n", tag);
@@ -483,11 +543,11 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
tvee->rev_str[4] = 0;
}
- if (hasRadioTuner(tuner1) && !tvee->has_radio) {
- tveeprom_info("The eeprom says no radio is present, but the tuner type\n");
- tveeprom_info("indicates otherwise. I will assume that radio is present.\n");
- tvee->has_radio = 1;
- }
+ if (hasRadioTuner(tuner1) && !tvee->has_radio) {
+ tveeprom_info("The eeprom says no radio is present, but the tuner type\n");
+ tveeprom_info("indicates otherwise. I will assume that radio is present.\n");
+ tvee->has_radio = 1;
+ }
if (tuner1 < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) {
tvee->tuner_type = hauppauge_tuner[tuner1].id;
@@ -510,45 +570,53 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
tvee->tuner_formats |= hauppauge_tuner_fmt[i].id;
t_fmt_name1[j++] = hauppauge_tuner_fmt[i].name;
}
- if (t_format2 & (1 << i)) {
- tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id;
- t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name;
- }
+ if (t_format2 & (1 << i)) {
+ tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id;
+ t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name;
+ }
}
tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n",
- tvee->model, tvee->rev_str, tvee->serial_number);
+ tvee->model, tvee->rev_str, tvee->serial_number);
tveeprom_info("tuner model is %s (idx %d, type %d)\n",
- t_name1, tuner1, tvee->tuner_type);
+ t_name1, tuner1, tvee->tuner_type);
tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
- t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3],
- t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7],
- t_format1);
- if (tuner2) {
- tveeprom_info("second tuner model is %s (idx %d, type %d)\n",
- t_name2, tuner2, tvee->tuner2_type);
- }
- if (t_format2) {
- tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
- t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3],
- t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7],
- t_format2);
- }
- tveeprom_info("audio processor is %s (idx %d)\n",
- STRM(audioIC, tvee->audio_processor),
- tvee->audio_processor);
- if (tvee->decoder_processor) {
- tveeprom_info("decoder processor is %s (idx %d)\n",
- STRM(decoderIC, tvee->decoder_processor),
- tvee->decoder_processor);
- }
- if (tvee->has_ir == 2)
- tveeprom_info("has %sradio\n",
- tvee->has_radio ? "" : "no ");
- else
- tveeprom_info("has %sradio, has %sIR remote\n",
- tvee->has_radio ? "" : "no ",
- tvee->has_ir ? "" : "no ");
+ t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3],
+ t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7],
+ t_format1);
+ if (tuner2) {
+ tveeprom_info("second tuner model is %s (idx %d, type %d)\n",
+ t_name2, tuner2, tvee->tuner2_type);
+ }
+ if (t_format2) {
+ tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
+ t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3],
+ t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7],
+ t_format2);
+ }
+ if (audioic<0) {
+ tveeprom_info("audio processor is unknown (no idx)\n");
+ tvee->audio_processor=AUDIO_CHIP_UNKNOWN;
+ } else {
+ if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+ tveeprom_info("audio processor is %s (idx %d)\n",
+ audioIC[audioic].name,audioic);
+ else
+ tveeprom_info("audio processor is unknown (idx %d)\n",
+ audioic);
+ }
+ if (tvee->decoder_processor) {
+ tveeprom_info("decoder processor is %s (idx %d)\n",
+ STRM(decoderIC, tvee->decoder_processor),
+ tvee->decoder_processor);
+ }
+ if (tvee->has_ir == 2)
+ tveeprom_info("has %sradio\n",
+ tvee->has_radio ? "" : "no ");
+ else
+ tveeprom_info("has %sradio, has %sIR remote\n",
+ tvee->has_radio ? "" : "no ",
+ tvee->has_ir ? "" : "no ");
}
EXPORT_SYMBOL(tveeprom_hauppauge_analog);
@@ -569,18 +637,18 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len)
tveeprom_warn("i2c eeprom read error (err=%d)\n", err);
return -1;
}
- if (debug) {
- int i;
-
- tveeprom_info("full 256-byte eeprom dump:\n");
- for (i = 0; i < len; i++) {
- if (0 == (i % 16))
- tveeprom_info("%02x:", i);
- printk(" %02x", eedata[i]);
- if (15 == (i % 16))
- printk("\n");
- }
- }
+ if (debug) {
+ int i;
+
+ tveeprom_info("full 256-byte eeprom dump:\n");
+ for (i = 0; i < len; i++) {
+ if (0 == (i % 16))
+ tveeprom_info("%02x:", i);
+ printk(" %02x", eedata[i]);
+ if (15 == (i % 16))
+ printk("\n");
+ }
+ }
return 0;
}
EXPORT_SYMBOL(tveeprom_read);
@@ -590,10 +658,6 @@ EXPORT_SYMBOL(tveeprom_read);
/* run, just call the exported tveeprom_* directly, there is no point in */
/* using the indirect way via i2c_driver->command() */
-#ifndef I2C_DRIVERID_TVEEPROM
-# define I2C_DRIVERID_TVEEPROM I2C_DRIVERID_EXP2
-#endif
-
static unsigned short normal_i2c[] = {
0xa0 >> 1,
I2C_CLIENT_END,
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
index d86e08ebddf..8318bd1aad0 100644
--- a/drivers/media/video/tvmixer.c
+++ b/drivers/media/video/tvmixer.c
@@ -79,7 +79,7 @@ static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cm
{
struct video_audio va;
int left,right,ret,val = 0;
- struct TVMIXER *mix = file->private_data;
+ struct TVMIXER *mix = file->private_data;
struct i2c_client *client = mix->dev;
void __user *argp = (void __user *)arg;
int __user *p = argp;
@@ -87,25 +87,25 @@ static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cm
if (NULL == client)
return -ENODEV;
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- strlcpy(info.id, "tv card", sizeof(info.id));
- strlcpy(info.name, client->name, sizeof(info.name));
- info.modify_counter = 42 /* FIXME */;
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == SOUND_OLD_MIXER_INFO) {
- _old_mixer_info info;
- strlcpy(info.id, "tv card", sizeof(info.id));
- strlcpy(info.name, client->name, sizeof(info.name));
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, p);
+ if (cmd == SOUND_MIXER_INFO) {
+ mixer_info info;
+ strlcpy(info.id, "tv card", sizeof(info.id));
+ strlcpy(info.name, client->name, sizeof(info.name));
+ info.modify_counter = 42 /* FIXME */;
+ if (copy_to_user(argp, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == SOUND_OLD_MIXER_INFO) {
+ _old_mixer_info info;
+ strlcpy(info.id, "tv card", sizeof(info.id));
+ strlcpy(info.name, client->name, sizeof(info.name));
+ if (copy_to_user(argp, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == OSS_GETVERSION)
+ return put_user(SOUND_VERSION, p);
if (_SIOC_DIR(cmd) & _SIOC_WRITE)
if (get_user(val, p))
@@ -181,8 +181,8 @@ static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cm
static int tvmixer_open(struct inode *inode, struct file *file)
{
- int i, minor = iminor(inode);
- struct TVMIXER *mix = NULL;
+ int i, minor = iminor(inode);
+ struct TVMIXER *mix = NULL;
struct i2c_client *client = NULL;
for (i = 0; i < DEV_MAX; i++) {
@@ -204,7 +204,7 @@ static int tvmixer_open(struct inode *inode, struct file *file)
#endif
if (client->adapter->owner)
try_module_get(client->adapter->owner);
- return 0;
+ return 0;
}
static int tvmixer_release(struct inode *inode, struct file *file)
@@ -231,15 +231,15 @@ static struct i2c_driver driver = {
.owner = THIS_MODULE,
#endif
.name = "tv card mixer driver",
- .id = I2C_DRIVERID_TVMIXER,
+ .id = I2C_DRIVERID_TVMIXER,
#ifdef I2C_DF_DUMMY
.flags = I2C_DF_DUMMY,
#else
.flags = I2C_DF_NOTIFY,
- .detach_adapter = tvmixer_adapters,
+ .detach_adapter = tvmixer_adapters,
#endif
- .attach_adapter = tvmixer_adapters,
- .detach_client = tvmixer_clients,
+ .attach_adapter = tvmixer_adapters,
+ .detach_client = tvmixer_clients,
};
static struct file_operations tvmixer_fops = {
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
new file mode 100644
index 00000000000..81e6d4494e7
--- /dev/null
+++ b/drivers/media/video/tvp5150.c
@@ -0,0 +1,829 @@
+/*
+ * tvp5150 - Texas Instruments TVP5150A(M) video decoder driver
+ *
+ * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br)
+ * This code is placed under the terms of the GNU General Public License
+ */
+
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/delay.h>
+#include <linux/video_decoder.h>
+
+#include "tvp5150_reg.h"
+
+MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver"); /* standard i2c insmod options */
+MODULE_AUTHOR("Mauro Carvalho Chehab");
+MODULE_LICENSE("GPL");
+
+static unsigned short normal_i2c[] = {
+ 0xb8 >> 1,
+ 0xba >> 1,
+ I2C_CLIENT_END
+};
+
+I2C_CLIENT_INSMOD;
+
+static int debug = 0;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define dprintk(num, format, args...) \
+ do { \
+ if (debug >= num) \
+ printk(format , ##args); \
+ } while (0)
+
+/* supported controls */
+static struct v4l2_queryctrl tvp5150_qctrl[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = 0x10,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = 0x10,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 0x1,
+ .default_value = 0x10,
+ .flags = 0,
+ }
+};
+
+struct tvp5150 {
+ struct i2c_client *client;
+
+ int norm;
+ int input;
+ int enable;
+ int bright;
+ int contrast;
+ int hue;
+ int sat;
+};
+
+static inline int tvp5150_read(struct i2c_client *c, unsigned char addr)
+{
+ unsigned char buffer[1];
+ int rc;
+
+ buffer[0] = addr;
+ if (1 != (rc = i2c_master_send(c, buffer, 1)))
+ dprintk(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+
+ msleep(10);
+
+ if (1 != (rc = i2c_master_recv(c, buffer, 1)))
+ dprintk(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+
+ return (buffer[0]);
+}
+
+static inline void tvp5150_write(struct i2c_client *c, unsigned char addr,
+ unsigned char value)
+{
+ unsigned char buffer[2];
+ int rc;
+/* struct tvp5150 *core = i2c_get_clientdata(c); */
+
+ buffer[0] = addr;
+ buffer[1] = value;
+ dprintk(1, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
+ if (2 != (rc = i2c_master_send(c, buffer, 2)))
+ dprintk(0, "i2c i/o error: rc == %d (should be 2)\n", rc);
+}
+
+static void dump_reg(struct i2c_client *c)
+{
+ printk("tvp5150: Video input source selection #1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VD_IN_SRC_SEL_1));
+ printk("tvp5150: Analog channel controls = 0x%02x\n",
+ tvp5150_read(c, TVP5150_ANAL_CHL_CTL));
+ printk("tvp5150: Operation mode controls = 0x%02x\n",
+ tvp5150_read(c, TVP5150_OP_MODE_CTL));
+ printk("tvp5150: Miscellaneous controls = 0x%02x\n",
+ tvp5150_read(c, TVP5150_MISC_CTL));
+ printk("tvp5150: Autoswitch mask: TVP5150A / TVP5150AM = 0x%02x\n",
+ tvp5150_read(c, TVP5150_AUTOSW_MSK));
+ printk("tvp5150: Color killer threshold control = 0x%02x\n",
+ tvp5150_read(c, TVP5150_COLOR_KIL_THSH_CTL));
+ printk("tvp5150: Luminance processing control #1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LUMA_PROC_CTL_1));
+ printk("tvp5150: Luminance processing control #2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LUMA_PROC_CTL_2));
+ printk("tvp5150: Brightness control = 0x%02x\n",
+ tvp5150_read(c, TVP5150_BRIGHT_CTL));
+ printk("tvp5150: Color saturation control = 0x%02x\n",
+ tvp5150_read(c, TVP5150_SATURATION_CTL));
+ printk("tvp5150: Hue control = 0x%02x\n",
+ tvp5150_read(c, TVP5150_HUE_CTL));
+ printk("tvp5150: Contrast control = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CONTRAST_CTL));
+ printk("tvp5150: Outputs and data rates select = 0x%02x\n",
+ tvp5150_read(c, TVP5150_DATA_RATE_SEL));
+ printk("tvp5150: Luminance processing control #3 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LUMA_PROC_CTL_3));
+ printk("tvp5150: Configuration shared pins = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CONF_SHARED_PIN));
+ printk("tvp5150: Active video cropping start MSB = 0x%02x\n",
+ tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_MSB));
+ printk("tvp5150: Active video cropping start LSB = 0x%02x\n",
+ tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_LSB));
+ printk("tvp5150: Active video cropping stop MSB = 0x%02x\n",
+ tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_MSB));
+ printk("tvp5150: Active video cropping stop LSB = 0x%02x\n",
+ tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_LSB));
+ printk("tvp5150: Genlock/RTC = 0x%02x\n",
+ tvp5150_read(c, TVP5150_GENLOCK));
+ printk("tvp5150: Horizontal sync start = 0x%02x\n",
+ tvp5150_read(c, TVP5150_HORIZ_SYNC_START));
+ printk("tvp5150: Vertical blanking start = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VERT_BLANKING_START));
+ printk("tvp5150: Vertical blanking stop = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VERT_BLANKING_STOP));
+ printk("tvp5150: Chrominance processing control #1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_1));
+ printk("tvp5150: Chrominance processing control #2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_2));
+ printk("tvp5150: Interrupt reset register B = 0x%02x\n",
+ tvp5150_read(c, TVP5150_INT_RESET_REG_B));
+ printk("tvp5150: Interrupt enable register B = 0x%02x\n",
+ tvp5150_read(c, TVP5150_INT_ENABLE_REG_B));
+ printk("tvp5150: Interrupt configuration register B = 0x%02x\n",
+ tvp5150_read(c, TVP5150_INTT_CONFIG_REG_B));
+ printk("tvp5150: Video standard = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VIDEO_STD));
+ printk("tvp5150: Cb gain factor = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CB_GAIN_FACT));
+ printk("tvp5150: Cr gain factor = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CR_GAIN_FACTOR));
+ printk("tvp5150: Macrovision on counter = 0x%02x\n",
+ tvp5150_read(c, TVP5150_MACROVISION_ON_CTR));
+ printk("tvp5150: Macrovision off counter = 0x%02x\n",
+ tvp5150_read(c, TVP5150_MACROVISION_OFF_CTR));
+ printk("tvp5150: revision select (TVP5150AM1 only) = 0x%02x\n",
+ tvp5150_read(c, TVP5150_REV_SELECT));
+ printk("tvp5150: MSB of device ID = 0x%02x\n",
+ tvp5150_read(c, TVP5150_MSB_DEV_ID));
+ printk("tvp5150: LSB of device ID = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LSB_DEV_ID));
+ printk("tvp5150: ROM major version = 0x%02x\n",
+ tvp5150_read(c, TVP5150_ROM_MAJOR_VER));
+ printk("tvp5150: ROM minor version = 0x%02x\n",
+ tvp5150_read(c, TVP5150_ROM_MINOR_VER));
+ printk("tvp5150: Vertical line count MSB = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VERT_LN_COUNT_MSB));
+ printk("tvp5150: Vertical line count LSB = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VERT_LN_COUNT_LSB));
+ printk("tvp5150: Interrupt status register B = 0x%02x\n",
+ tvp5150_read(c, TVP5150_INT_STATUS_REG_B));
+ printk("tvp5150: Interrupt active register B = 0x%02x\n",
+ tvp5150_read(c, TVP5150_INT_ACTIVE_REG_B));
+ printk("tvp5150: Status register #1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_STATUS_REG_1));
+ printk("tvp5150: Status register #2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_STATUS_REG_2));
+ printk("tvp5150: Status register #3 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_STATUS_REG_3));
+ printk("tvp5150: Status register #4 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_STATUS_REG_4));
+ printk("tvp5150: Status register #5 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_STATUS_REG_5));
+ printk("tvp5150: Closed caption data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CC_DATA_REG1));
+ printk("tvp5150: Closed caption data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CC_DATA_REG2));
+ printk("tvp5150: Closed caption data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CC_DATA_REG3));
+ printk("tvp5150: Closed caption data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CC_DATA_REG4));
+ printk("tvp5150: WSS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_WSS_DATA_REG1));
+ printk("tvp5150: WSS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_WSS_DATA_REG2));
+ printk("tvp5150: WSS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_WSS_DATA_REG3));
+ printk("tvp5150: WSS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_WSS_DATA_REG4));
+ printk("tvp5150: WSS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_WSS_DATA_REG5));
+ printk("tvp5150: WSS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_WSS_DATA_REG6));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG1));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG2));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG3));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG4));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG5));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG6));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG7));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG8));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG9));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG10));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG11));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG12));
+ printk("tvp5150: VPS data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VPS_DATA_REG13));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG1));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG2));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG3));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG4));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG5));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG6));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG7));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG8));
+ printk("tvp5150: VITC data registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VITC_DATA_REG9));
+ printk("tvp5150: VBI FIFO read data = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VBI_FIFO_READ_DATA));
+ printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_1_1));
+ printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_1_2));
+ printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_1_3));
+ printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_1_4));
+ printk("tvp5150: Teletext filter 1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_1_5));
+ printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_2_1));
+ printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_2_2));
+ printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_2_3));
+ printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_2_4));
+ printk("tvp5150: Teletext filter 2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_2_5));
+ printk("tvp5150: Teletext filter enable = 0x%02x\n",
+ tvp5150_read(c, TVP5150_TELETEXT_FIL_ENA));
+ printk("tvp5150: Interrupt status register A = 0x%02x\n",
+ tvp5150_read(c, TVP5150_INT_STATUS_REG_A));
+ printk("tvp5150: Interrupt enable register A = 0x%02x\n",
+ tvp5150_read(c, TVP5150_INT_ENABLE_REG_A));
+ printk("tvp5150: Interrupt configuration = 0x%02x\n",
+ tvp5150_read(c, TVP5150_INT_CONF));
+ printk("tvp5150: VDP configuration RAM data = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VDP_CONF_RAM_DATA));
+ printk("tvp5150: Configuration RAM address low byte = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CONF_RAM_ADDR_LOW));
+ printk("tvp5150: Configuration RAM address high byte = 0x%02x\n",
+ tvp5150_read(c, TVP5150_CONF_RAM_ADDR_HIGH));
+ printk("tvp5150: VDP status register = 0x%02x\n",
+ tvp5150_read(c, TVP5150_VDP_STATUS_REG));
+ printk("tvp5150: FIFO word count = 0x%02x\n",
+ tvp5150_read(c, TVP5150_FIFO_WORD_COUNT));
+ printk("tvp5150: FIFO interrupt threshold = 0x%02x\n",
+ tvp5150_read(c, TVP5150_FIFO_INT_THRESHOLD));
+ printk("tvp5150: FIFO reset = 0x%02x\n",
+ tvp5150_read(c, TVP5150_FIFO_RESET));
+ printk("tvp5150: Line number interrupt = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_NUMBER_INT));
+ printk("tvp5150: Pixel alignment register low byte = 0x%02x\n",
+ tvp5150_read(c, TVP5150_PIX_ALIGN_REG_LOW));
+ printk("tvp5150: Pixel alignment register high byte = 0x%02x\n",
+ tvp5150_read(c, TVP5150_PIX_ALIGN_REG_HIGH));
+ printk("tvp5150: FIFO output control = 0x%02x\n",
+ tvp5150_read(c, TVP5150_FIFO_OUT_CTRL));
+ printk("tvp5150: Full field enable 1 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_FULL_FIELD_ENA_1));
+ printk("tvp5150: Full field enable 2 = 0x%02x\n",
+ tvp5150_read(c, TVP5150_FULL_FIELD_ENA_2));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_1));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_2));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_3));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_4));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_5));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_6));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_7));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_8));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_9));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_10));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_11));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_12));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_13));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_14));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_15));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_16));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_17));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_18));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_19));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_20));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_21));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_22));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_23));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_24));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_25));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_27));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_28));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_29));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_30));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_31));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_32));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_33));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_34));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_35));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_36));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_37));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_38));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_39));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_40));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_41));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_42));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_43));
+ printk("tvp5150: Line mode registers = 0x%02x\n",
+ tvp5150_read(c, TVP5150_LINE_MODE_REG_44));
+ printk("tvp5150: Full field mode register = 0x%02x\n",
+ tvp5150_read(c, TVP5150_FULL_FIELD_MODE_REG));
+}
+
+/****************************************************************************
+ Basic functions
+ ****************************************************************************/
+enum tvp5150_input {
+ TVP5150_ANALOG_CH0 = 0,
+ TVP5150_SVIDEO = 1,
+ TVP5150_ANALOG_CH1 = 2,
+ TVP5150_BLACK_SCREEN = 8
+};
+
+static inline void tvp5150_selmux(struct i2c_client *c,
+ enum tvp5150_input input)
+{
+ struct tvp5150 *decoder = i2c_get_clientdata(c);
+
+ if (!decoder->enable)
+ input |= TVP5150_BLACK_SCREEN;
+
+ tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, input);
+};
+
+static inline void tvp5150_reset(struct i2c_client *c)
+{
+ struct tvp5150 *decoder = i2c_get_clientdata(c);
+
+ tvp5150_write(c, TVP5150_CONF_SHARED_PIN, 2);
+
+ /* Automatic offset and AGC enabled */
+ tvp5150_write(c, TVP5150_ANAL_CHL_CTL, 0x15);
+
+ /* Normal Operation */
+// tvp5150_write(c, TVP5150_OP_MODE_CTL, 0x00);
+
+ /* Activate YCrCb output 0x9 or 0xd ? */
+ tvp5150_write(c, TVP5150_MISC_CTL, 0x6f);
+
+ /* Activates video std autodetection for all standards */
+ tvp5150_write(c, TVP5150_AUTOSW_MSK, 0x0);
+
+ /* Default format: 0x47, 4:2:2: 0x40 */
+ tvp5150_write(c, TVP5150_DATA_RATE_SEL, 0x47);
+
+ tvp5150_selmux(c, decoder->input);
+
+ tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_1, 0x0c);
+ tvp5150_write(c, TVP5150_CHROMA_PROC_CTL_2, 0x54);
+
+ tvp5150_write(c, 0x27, 0x20); /* ?????????? */
+
+ tvp5150_write(c, TVP5150_VIDEO_STD, 0x0); /* Auto switch */
+
+ tvp5150_write(c, TVP5150_BRIGHT_CTL, decoder->bright >> 8);
+ tvp5150_write(c, TVP5150_CONTRAST_CTL, decoder->contrast >> 8);
+ tvp5150_write(c, TVP5150_SATURATION_CTL, decoder->contrast >> 8);
+ tvp5150_write(c, TVP5150_HUE_CTL, (decoder->hue - 32768) >> 8);
+};
+
+static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
+{
+/* struct tvp5150 *decoder = i2c_get_clientdata(c); */
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = tvp5150_read(c, TVP5150_BRIGHT_CTL);
+ return 0;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = tvp5150_read(c, TVP5150_CONTRAST_CTL);
+ return 0;
+ case V4L2_CID_SATURATION:
+ ctrl->value = tvp5150_read(c, TVP5150_SATURATION_CTL);
+ return 0;
+ case V4L2_CID_HUE:
+ ctrl->value = tvp5150_read(c, TVP5150_HUE_CTL);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
+{
+/* struct tvp5150 *decoder = i2c_get_clientdata(c); */
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ tvp5150_write(c, TVP5150_BRIGHT_CTL, ctrl->value);
+ return 0;
+ case V4L2_CID_CONTRAST:
+ tvp5150_write(c, TVP5150_CONTRAST_CTL, ctrl->value);
+ return 0;
+ case V4L2_CID_SATURATION:
+ tvp5150_write(c, TVP5150_SATURATION_CTL, ctrl->value);
+ return 0;
+ case V4L2_CID_HUE:
+ tvp5150_write(c, TVP5150_HUE_CTL, ctrl->value);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/****************************************************************************
+ I2C Command
+ ****************************************************************************/
+static int tvp5150_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ struct tvp5150 *decoder = i2c_get_clientdata(client);
+
+ switch (cmd) {
+
+ case 0:
+ case DECODER_INIT:
+ tvp5150_reset(client);
+ break;
+
+ case DECODER_DUMP:
+ dump_reg(client);
+ break;
+
+ case DECODER_GET_CAPABILITIES:
+ {
+ struct video_decoder_capability *cap = arg;
+
+ cap->flags = VIDEO_DECODER_PAL |
+ VIDEO_DECODER_NTSC |
+ VIDEO_DECODER_SECAM |
+ VIDEO_DECODER_AUTO | VIDEO_DECODER_CCIR;
+ cap->inputs = 3;
+ cap->outputs = 1;
+ break;
+ }
+ case DECODER_GET_STATUS:
+ {
+ break;
+ }
+
+ case DECODER_SET_GPIO:
+ break;
+
+ case DECODER_SET_VBI_BYPASS:
+ break;
+
+ case DECODER_SET_NORM:
+ {
+ int *iarg = arg;
+
+ switch (*iarg) {
+
+ case VIDEO_MODE_NTSC:
+ break;
+
+ case VIDEO_MODE_PAL:
+ break;
+
+ case VIDEO_MODE_SECAM:
+ break;
+
+ case VIDEO_MODE_AUTO:
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+ decoder->norm = *iarg;
+ break;
+ }
+ case DECODER_SET_INPUT:
+ {
+ int *iarg = arg;
+ if (*iarg < 0 || *iarg > 3) {
+ return -EINVAL;
+ }
+
+ decoder->input = *iarg;
+ tvp5150_selmux(client, decoder->input);
+
+ break;
+ }
+ case DECODER_SET_OUTPUT:
+ {
+ int *iarg = arg;
+
+ /* not much choice of outputs */
+ if (*iarg != 0) {
+ return -EINVAL;
+ }
+ break;
+ }
+ case DECODER_ENABLE_OUTPUT:
+ {
+ int *iarg = arg;
+
+ decoder->enable = (*iarg != 0);
+
+ tvp5150_selmux(client, decoder->input);
+
+ break;
+ }
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+ u8 i, n;
+
+ dprintk(1, KERN_DEBUG "VIDIOC_QUERYCTRL");
+
+ n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
+ for (i = 0; i < n; i++)
+ if (qc->id && qc->id == tvp5150_qctrl[i].id) {
+ memcpy(qc, &(tvp5150_qctrl[i]),
+ sizeof(*qc));
+ return 0;
+ }
+
+ return -EINVAL;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+ dprintk(1, KERN_DEBUG "VIDIOC_G_CTRL");
+
+ return tvp5150_get_ctrl(client, ctrl);
+ }
+ case VIDIOC_S_CTRL_OLD: /* ??? */
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+ u8 i, n;
+ dprintk(1, KERN_DEBUG "VIDIOC_S_CTRL");
+ n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
+ for (i = 0; i < n; i++)
+ if (ctrl->id == tvp5150_qctrl[i].id) {
+ if (ctrl->value <
+ tvp5150_qctrl[i].minimum
+ || ctrl->value >
+ tvp5150_qctrl[i].maximum)
+ return -ERANGE;
+ dprintk(1,
+ KERN_DEBUG
+ "VIDIOC_S_CTRL: id=%d, value=%d",
+ ctrl->id, ctrl->value);
+ return tvp5150_set_ctrl(client, ctrl);
+ }
+ return -EINVAL;
+ }
+
+ case DECODER_SET_PICTURE:
+ {
+ struct video_picture *pic = arg;
+ if (decoder->bright != pic->brightness) {
+ /* We want 0 to 255 we get 0-65535 */
+ decoder->bright = pic->brightness;
+ tvp5150_write(client, TVP5150_BRIGHT_CTL,
+ decoder->bright >> 8);
+ }
+ if (decoder->contrast != pic->contrast) {
+ /* We want 0 to 255 we get 0-65535 */
+ decoder->contrast = pic->contrast;
+ tvp5150_write(client, TVP5150_CONTRAST_CTL,
+ decoder->contrast >> 8);
+ }
+ if (decoder->sat != pic->colour) {
+ /* We want 0 to 255 we get 0-65535 */
+ decoder->sat = pic->colour;
+ tvp5150_write(client, TVP5150_SATURATION_CTL,
+ decoder->contrast >> 8);
+ }
+ if (decoder->hue != pic->hue) {
+ /* We want -128 to 127 we get 0-65535 */
+ decoder->hue = pic->hue;
+ tvp5150_write(client, TVP5150_HUE_CTL,
+ (decoder->hue - 32768) >> 8);
+ }
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ I2C Client & Driver
+ ****************************************************************************/
+static struct i2c_driver driver;
+
+static struct i2c_client client_template = {
+ .name = "(unset)",
+ .flags = I2C_CLIENT_ALLOW_USE,
+ .driver = &driver,
+};
+
+static int tvp5150_detect_client(struct i2c_adapter *adapter,
+ int address, int kind)
+{
+ struct i2c_client *client;
+ struct tvp5150 *core;
+ int rv;
+
+ dprintk(1,
+ KERN_INFO
+ "tvp5150.c: detecting tvp5150 client on address 0x%x\n",
+ address << 1);
+
+ client_template.adapter = adapter;
+ client_template.addr = address;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality
+ (adapter,
+ I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+ memcpy(client, &client_template, sizeof(struct i2c_client));
+
+ core = kmalloc(sizeof(struct tvp5150), GFP_KERNEL);
+ if (core == 0) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ memset(core, 0, sizeof(struct tvp5150));
+ i2c_set_clientdata(client, core);
+
+ rv = i2c_attach_client(client);
+
+ core->norm = VIDEO_MODE_AUTO;
+ core->input = 2;
+ core->enable = 1;
+ core->bright = 32768;
+ core->contrast = 32768;
+ core->hue = 32768;
+ core->sat = 32768;
+
+ if (rv) {
+ kfree(client);
+ kfree(core);
+ return rv;
+ }
+
+ if (debug > 1)
+ dump_reg(client);
+
+ return 0;
+}
+
+static int tvp5150_attach_adapter(struct i2c_adapter *adapter)
+{
+ dprintk(1,
+ KERN_INFO
+ "tvp5150.c: starting probe for adapter %s (0x%x)\n",
+ adapter->name, adapter->id);
+ return i2c_probe(adapter, &addr_data, &tvp5150_detect_client);
+}
+
+static int tvp5150_detach_client(struct i2c_client *client)
+{
+ struct tvp5150 *decoder = i2c_get_clientdata(client);
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ return err;
+ }
+
+ kfree(decoder);
+ kfree(client);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver driver = {
+ .owner = THIS_MODULE,
+ .name = "tvp5150",
+
+ /* FIXME */
+ .id = I2C_DRIVERID_SAA7110,
+ .flags = I2C_DF_NOTIFY,
+
+ .attach_adapter = tvp5150_attach_adapter,
+ .detach_client = tvp5150_detach_client,
+
+ .command = tvp5150_command,
+};
+
+static int __init tvp5150_init(void)
+{
+ return i2c_add_driver(&driver);
+}
+
+static void __exit tvp5150_exit(void)
+{
+ i2c_del_driver(&driver);
+}
+
+module_init(tvp5150_init);
+module_exit(tvp5150_exit);
diff --git a/drivers/media/video/tvp5150_reg.h b/drivers/media/video/tvp5150_reg.h
new file mode 100644
index 00000000000..cd45c1ded78
--- /dev/null
+++ b/drivers/media/video/tvp5150_reg.h
@@ -0,0 +1,173 @@
+#define TVP5150_VD_IN_SRC_SEL_1 0x00 /* Video input source selection #1 */
+#define TVP5150_ANAL_CHL_CTL 0x01 /* Analog channel controls */
+#define TVP5150_OP_MODE_CTL 0x02 /* Operation mode controls */
+#define TVP5150_MISC_CTL 0x03 /* Miscellaneous controls */
+#define TVP5150_AUTOSW_MSK 0x04 /* Autoswitch mask: TVP5150A / TVP5150AM */
+
+/* Reserved 05h */
+
+#define TVP5150_COLOR_KIL_THSH_CTL 0x06 /* Color killer threshold control */
+#define TVP5150_LUMA_PROC_CTL_1 0x07 /* Luminance processing control #1 */
+#define TVP5150_LUMA_PROC_CTL_2 0x08 /* Luminance processing control #2 */
+#define TVP5150_BRIGHT_CTL 0x09 /* Brightness control */
+#define TVP5150_SATURATION_CTL 0x0a /* Color saturation control */
+#define TVP5150_HUE_CTL 0x0b /* Hue control */
+#define TVP5150_CONTRAST_CTL 0x0c /* Contrast control */
+#define TVP5150_DATA_RATE_SEL 0x0d /* Outputs and data rates select */
+#define TVP5150_LUMA_PROC_CTL_3 0x0e /* Luminance processing control #3 */
+#define TVP5150_CONF_SHARED_PIN 0x0f /* Configuration shared pins */
+
+/* Reserved 10h */
+
+#define TVP5150_ACT_VD_CROP_ST_MSB 0x11 /* Active video cropping start MSB */
+#define TVP5150_ACT_VD_CROP_ST_LSB 0x12 /* Active video cropping start LSB */
+#define TVP5150_ACT_VD_CROP_STP_MSB 0x13 /* Active video cropping stop MSB */
+#define TVP5150_ACT_VD_CROP_STP_LSB 0x14 /* Active video cropping stop LSB */
+#define TVP5150_GENLOCK 0x15 /* Genlock/RTC */
+#define TVP5150_HORIZ_SYNC_START 0x16 /* Horizontal sync start */
+
+/* Reserved 17h */
+
+#define TVP5150_VERT_BLANKING_START 0x18 /* Vertical blanking start */
+#define TVP5150_VERT_BLANKING_STOP 0x19 /* Vertical blanking stop */
+#define TVP5150_CHROMA_PROC_CTL_1 0x1a /* Chrominance processing control #1 */
+#define TVP5150_CHROMA_PROC_CTL_2 0x1b /* Chrominance processing control #2 */
+#define TVP5150_INT_RESET_REG_B 0x1c /* Interrupt reset register B */
+#define TVP5150_INT_ENABLE_REG_B 0x1d /* Interrupt enable register B */
+#define TVP5150_INTT_CONFIG_REG_B 0x1e /* Interrupt configuration register B */
+
+/* Reserved 1Fh-27h */
+
+#define TVP5150_VIDEO_STD 0x28 /* Video standard */
+
+/* Reserved 29h-2bh */
+
+#define TVP5150_CB_GAIN_FACT 0x2c /* Cb gain factor */
+#define TVP5150_CR_GAIN_FACTOR 0x2d /* Cr gain factor */
+#define TVP5150_MACROVISION_ON_CTR 0x2e /* Macrovision on counter */
+#define TVP5150_MACROVISION_OFF_CTR 0x2f /* Macrovision off counter */
+#define TVP5150_REV_SELECT 0x30 /* revision select (TVP5150AM1 only) */
+
+/* Reserved 31h-7Fh */
+
+#define TVP5150_MSB_DEV_ID 0x80 /* MSB of device ID */
+#define TVP5150_LSB_DEV_ID 0x81 /* LSB of device ID */
+#define TVP5150_ROM_MAJOR_VER 0x82 /* ROM major version */
+#define TVP5150_ROM_MINOR_VER 0x83 /* ROM minor version */
+#define TVP5150_VERT_LN_COUNT_MSB 0x84 /* Vertical line count MSB */
+#define TVP5150_VERT_LN_COUNT_LSB 0x85 /* Vertical line count LSB */
+#define TVP5150_INT_STATUS_REG_B 0x86 /* Interrupt status register B */
+#define TVP5150_INT_ACTIVE_REG_B 0x87 /* Interrupt active register B */
+#define TVP5150_STATUS_REG_1 0x88 /* Status register #1 */
+#define TVP5150_STATUS_REG_2 0x89 /* Status register #2 */
+#define TVP5150_STATUS_REG_3 0x8a /* Status register #3 */
+#define TVP5150_STATUS_REG_4 0x8b /* Status register #4 */
+#define TVP5150_STATUS_REG_5 0x8c /* Status register #5 */
+/* Reserved 8Dh-8Fh */
+#define TVP5150_CC_DATA_REG1 0x90 /* Closed caption data registers */
+#define TVP5150_CC_DATA_REG2 0x91 /* Closed caption data registers */
+#define TVP5150_CC_DATA_REG3 0x92 /* Closed caption data registers */
+#define TVP5150_CC_DATA_REG4 0x93 /* Closed caption data registers */
+#define TVP5150_WSS_DATA_REG1 0X94 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG2 0X95 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG3 0X96 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG4 0X97 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG5 0X98 /* WSS data registers */
+#define TVP5150_WSS_DATA_REG6 0X99 /* WSS data registers */
+#define TVP5150_VPS_DATA_REG1 0x9a /* VPS data registers */
+#define TVP5150_VPS_DATA_REG2 0x9b /* VPS data registers */
+#define TVP5150_VPS_DATA_REG3 0x9c /* VPS data registers */
+#define TVP5150_VPS_DATA_REG4 0x9d /* VPS data registers */
+#define TVP5150_VPS_DATA_REG5 0x9e /* VPS data registers */
+#define TVP5150_VPS_DATA_REG6 0x9f /* VPS data registers */
+#define TVP5150_VPS_DATA_REG7 0xa0 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG8 0xa1 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG9 0xa2 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG10 0xa3 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG11 0xa4 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG12 0xa5 /* VPS data registers */
+#define TVP5150_VPS_DATA_REG13 0xa6 /* VPS data registers */
+#define TVP5150_VITC_DATA_REG1 0xa7 /* VITC data registers */
+#define TVP5150_VITC_DATA_REG2 0xa8 /* VITC data registers */
+#define TVP5150_VITC_DATA_REG3 0xa9 /* VITC data registers */
+#define TVP5150_VITC_DATA_REG4 0xaa /* VITC data registers */
+#define TVP5150_VITC_DATA_REG5 0xab /* VITC data registers */
+#define TVP5150_VITC_DATA_REG6 0xac /* VITC data registers */
+#define TVP5150_VITC_DATA_REG7 0xad /* VITC data registers */
+#define TVP5150_VITC_DATA_REG8 0xae /* VITC data registers */
+#define TVP5150_VITC_DATA_REG9 0xaf /* VITC data registers */
+#define TVP5150_VBI_FIFO_READ_DATA 0xb0 /* VBI FIFO read data */
+#define TVP5150_TELETEXT_FIL_1_1 0xb1 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_1_2 0xb2 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_1_3 0xb3 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_1_4 0xb4 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_1_5 0xb5 /* Teletext filter 1 */
+#define TVP5150_TELETEXT_FIL_2_1 0xb6 /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_2_2 0xb7 /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_2_3 0xb8 /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_2_4 0xb9 /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_2_5 0xba /* Teletext filter 2 */
+#define TVP5150_TELETEXT_FIL_ENA 0xbb /* Teletext filter enable */
+/* Reserved BCh-BFh */
+#define TVP5150_INT_STATUS_REG_A 0xc0 /* Interrupt status register A */
+#define TVP5150_INT_ENABLE_REG_A 0xc1 /* Interrupt enable register A */
+#define TVP5150_INT_CONF 0xc2 /* Interrupt configuration */
+#define TVP5150_VDP_CONF_RAM_DATA 0xc3 /* VDP configuration RAM data */
+#define TVP5150_CONF_RAM_ADDR_LOW 0xc4 /* Configuration RAM address low byte */
+#define TVP5150_CONF_RAM_ADDR_HIGH 0xc5 /* Configuration RAM address high byte */
+#define TVP5150_VDP_STATUS_REG 0xc6 /* VDP status register */
+#define TVP5150_FIFO_WORD_COUNT 0xc7 /* FIFO word count */
+#define TVP5150_FIFO_INT_THRESHOLD 0xc8 /* FIFO interrupt threshold */
+#define TVP5150_FIFO_RESET 0xc9 /* FIFO reset */
+#define TVP5150_LINE_NUMBER_INT 0xca /* Line number interrupt */
+#define TVP5150_PIX_ALIGN_REG_LOW 0xcb /* Pixel alignment register low byte */
+#define TVP5150_PIX_ALIGN_REG_HIGH 0xcc /* Pixel alignment register high byte */
+#define TVP5150_FIFO_OUT_CTRL 0xcd /* FIFO output control */
+/* Reserved CEh */
+#define TVP5150_FULL_FIELD_ENA_1 0xcf /* Full field enable 1 */
+#define TVP5150_FULL_FIELD_ENA_2 0xd0 /* Full field enable 2 */
+#define TVP5150_LINE_MODE_REG_1 0xd1 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_2 0xd2 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_3 0xd3 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_4 0xd4 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_5 0xd5 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_6 0xd6 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_7 0xd7 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_8 0xd8 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_9 0xd9 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_10 0xda /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_11 0xdb /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_12 0xdc /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_13 0xdd /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_14 0xde /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_15 0xdf /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_16 0xe0 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_17 0xe1 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_18 0xe2 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_19 0xe3 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_20 0xe4 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_21 0xe5 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_22 0xe6 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_23 0xe7 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_24 0xe8 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_25 0xe9 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_27 0xea /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_28 0xeb /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_29 0xec /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_30 0xed /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_31 0xee /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_32 0xef /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_33 0xf0 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_34 0xf1 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_35 0xf2 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_36 0xf3 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_37 0xf4 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_38 0xf5 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_39 0xf6 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_40 0xf7 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_41 0xf8 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_42 0xf9 /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_43 0xfa /* Line mode registers */
+#define TVP5150_LINE_MODE_REG_44 0xfb /* Line mode registers */
+#define TVP5150_FULL_FIELD_MODE_REG 0xfc /* Full field mode register */
+/* Reserved FDh-FFh */
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index d679ca23ded..4134549d11a 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -708,7 +708,7 @@ v4l_compat_translate_ioctl(struct inode *inode,
}
case VIDIOCGFREQ: /* get frequency */
{
- int *freq = arg;
+ unsigned long *freq = arg;
freq2.tuner = 0;
err = drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
@@ -720,7 +720,7 @@ v4l_compat_translate_ioctl(struct inode *inode,
}
case VIDIOCSFREQ: /* set frequency */
{
- int *freq = arg;
+ unsigned long *freq = arg;
freq2.tuner = 0;
drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
@@ -960,7 +960,7 @@ v4l_compat_translate_ioctl(struct inode *inode,
fmt->start[1] = fmt2->fmt.vbi.start[1];
fmt->count[1] = fmt2->fmt.vbi.count[1];
fmt->flags = fmt2->fmt.vbi.flags & 0x03;
- break;
+ break;
}
case VIDIOCSVBIFMT:
{
diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
index 574b8e36f3c..acfd3a103f3 100644
--- a/drivers/media/video/video-buf.c
+++ b/drivers/media/video/video-buf.c
@@ -147,7 +147,7 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
data,size,dma->nr_pages);
down_read(&current->mm->mmap_sem);
- err = get_user_pages(current,current->mm,
+ err = get_user_pages(current,current->mm,
data & PAGE_MASK, dma->nr_pages,
rw == READ, 1, /* force */
dma->pages, NULL);
@@ -750,9 +750,9 @@ videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data,
{
enum v4l2_field field;
unsigned long flags;
- int retval;
+ int retval;
- /* setup stuff */
+ /* setup stuff */
retval = -ENOMEM;
q->read_buf = videobuf_alloc(q->msize);
if (NULL == q->read_buf)
@@ -760,18 +760,18 @@ videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data,
q->read_buf->memory = V4L2_MEMORY_USERPTR;
q->read_buf->baddr = (unsigned long)data;
- q->read_buf->bsize = count;
+ q->read_buf->bsize = count;
field = videobuf_next_field(q);
retval = q->ops->buf_prepare(q,q->read_buf,field);
if (0 != retval)
goto done;
- /* start capture & wait */
+ /* start capture & wait */
spin_lock_irqsave(q->irqlock,flags);
q->ops->buf_queue(q,q->read_buf);
spin_unlock_irqrestore(q->irqlock,flags);
- retval = videobuf_waiton(q->read_buf,0,0);
- if (0 == retval) {
+ retval = videobuf_waiton(q->read_buf,0,0);
+ if (0 == retval) {
videobuf_dma_pci_sync(q->pci,&q->read_buf->dma);
if (STATE_ERROR == q->read_buf->state)
retval = -EIO;
@@ -828,7 +828,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
}
/* wait until capture is done */
- retval = videobuf_waiton(q->read_buf, nonblocking, 1);
+ retval = videobuf_waiton(q->read_buf, nonblocking, 1);
if (0 != retval)
goto done;
videobuf_dma_pci_sync(q->pci,&q->read_buf->dma);
@@ -1096,7 +1096,7 @@ videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n",
vaddr,vma->vm_start,vma->vm_end);
- if (vaddr > vma->vm_end)
+ if (vaddr > vma->vm_end)
return NOPAGE_SIGBUS;
page = alloc_page(GFP_USER);
if (!page)
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
new file mode 100644
index 00000000000..22f28622200
--- /dev/null
+++ b/drivers/media/video/wm8775.c
@@ -0,0 +1,254 @@
+/*
+ * wm8775 - driver version 0.0.1
+ *
+ * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to>
+ *
+ * Based on saa7115 driver
+ *
+ * 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/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/videodev.h>
+#include <media/audiochip.h>
+
+MODULE_DESCRIPTION("wm8775 driver");
+MODULE_AUTHOR("Ulf Eklund");
+MODULE_LICENSE("GPL");
+
+#define wm8775_err(fmt, arg...) do { \
+ printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define wm8775_info(fmt, arg...) do { \
+ printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+
+static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+enum {
+ R7 = 7, R11 = 11,
+ R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R23 = 23,
+ TOT_REGS
+};
+
+struct wm8775_state {
+ u8 input; /* Last selected input (0-0xf) */
+ u8 muted;
+};
+
+static int wm8775_write(struct i2c_client *client, int reg, u16 val)
+{
+ int i;
+
+ if (reg < 0 || reg >= TOT_REGS) {
+ wm8775_err("Invalid register R%d\n", reg);
+ return -1;
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (i2c_smbus_write_byte_data(client, (reg << 1) |
+ (val >> 8), val & 0xff) == 0) {
+ return 0;
+ }
+ }
+ wm8775_err("I2C: cannot write %03x to register R%d\n", val, reg);
+ return -1;
+}
+
+static int wm8775_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ struct wm8775_state *state = i2c_get_clientdata(client);
+ int *input = arg;
+
+ switch (cmd) {
+ case AUDC_SET_INPUT:
+ wm8775_write(client, R21, 0x0c0);
+ wm8775_write(client, R14, 0x1d4);
+ wm8775_write(client, R15, 0x1d4);
+
+ if (*input == AUDIO_RADIO) {
+ wm8775_write(client, R21, 0x108);
+ state->input = 8;
+ state->muted = 0;
+ break;
+ }
+ if (*input == AUDIO_MUTE) {
+ state->muted = 1;
+ break;
+ }
+ if (*input == AUDIO_UNMUTE) {
+ wm8775_write(client, R21, 0x100 + state->input);
+ state->muted = 0;
+ break;
+ }
+ /* All other inputs... */
+ wm8775_write(client, R21, 0x102);
+ state->input = 2;
+ state->muted = 0;
+ break;
+
+ case VIDIOC_LOG_STATUS:
+ wm8775_info("Input: %s%s\n",
+ state->input == 8 ? "radio" : "default",
+ state->muted ? " (muted)" : "");
+ break;
+
+ case VIDIOC_S_FREQUENCY:
+ /* If I remove this, then it can happen that I have no
+ sound the first time I tune from static to a valid channel.
+ It's difficult to reproduce and is almost certainly related
+ to the zero cross detect circuit. */
+ wm8775_write(client, R21, 0x0c0);
+ wm8775_write(client, R14, 0x1d4);
+ wm8775_write(client, R15, 0x1d4);
+ wm8775_write(client, R21, 0x100 + state->input);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static struct i2c_driver i2c_driver;
+
+static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct wm8775_state *state;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+
+ memset(client, 0, sizeof(struct i2c_client));
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver;
+ client->flags = I2C_CLIENT_ALLOW_USE;
+ snprintf(client->name, sizeof(client->name) - 1, "wm8775");
+
+ wm8775_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+
+ state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL);
+ if (state == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ state->input = 2;
+ state->muted = 0;
+ i2c_set_clientdata(client, state);
+
+ /* initialize wm8775 */
+ wm8775_write(client, R23, 0x000); /* RESET */
+ wm8775_write(client, R7, 0x000); /* Disable zero cross detect timeout */
+ wm8775_write(client, R11, 0x021); /* Left justified, 24-bit mode */
+ wm8775_write(client, R12, 0x102); /* Master mode, clock ratio 256fs */
+ wm8775_write(client, R13, 0x000); /* Powered up */
+ wm8775_write(client, R14, 0x1d4); /* ADC gain +2.5dB, enable zero cross */
+ wm8775_write(client, R15, 0x1d4); /* ADC gain +2.5dB, enable zero cross */
+ wm8775_write(client, R16, 0x1bf); /* ALC Stereo, ALC target level -1dB FS */
+ /* max gain +8dB */
+ wm8775_write(client, R17, 0x185); /* Enable gain control, use zero cross */
+ /* detection, ALC hold time 42.6 ms */
+ wm8775_write(client, R18, 0x0a2); /* ALC gain ramp up delay 34 s, */
+ /* ALC gain ramp down delay 33 ms */
+ wm8775_write(client, R19, 0x005); /* Enable noise gate, threshold -72dBfs */
+ wm8775_write(client, R20, 0x07a); /* Transient window 4ms, lower PGA gain */
+ /* limit -1dB */
+ wm8775_write(client, R21, 0x102); /* LRBOTH = 1, use input 2. */
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+static int wm8775_probe(struct i2c_adapter *adapter)
+{
+#ifdef I2C_CLASS_TV_ANALOG
+ if (adapter->class & I2C_CLASS_TV_ANALOG)
+#else
+ if (adapter->id == I2C_HW_B_BT848)
+#endif
+ return i2c_probe(adapter, &addr_data, wm8775_attach);
+ return 0;
+}
+
+static int wm8775_detach(struct i2c_client *client)
+{
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ return err;
+ }
+ kfree(client);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver = {
+ .name = "wm8775",
+
+ .id = I2C_DRIVERID_WM8775,
+ .flags = I2C_DF_NOTIFY,
+
+ .attach_adapter = wm8775_probe,
+ .detach_client = wm8775_detach,
+ .command = wm8775_command,
+ .owner = THIS_MODULE,
+};
+
+
+static int __init wm8775_init_module(void)
+{
+ return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit wm8775_cleanup_module(void)
+{
+ i2c_del_driver(&i2c_driver);
+}
+
+module_init(wm8775_init_module);
+module_exit(wm8775_cleanup_module);
diff --git a/drivers/media/video/zr36016.c b/drivers/media/video/zr36016.c
index d4740a89cea..4ed898585c7 100644
--- a/drivers/media/video/zr36016.c
+++ b/drivers/media/video/zr36016.c
@@ -26,7 +26,6 @@
#define ZR016_VERSION "v0.7"
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
diff --git a/drivers/media/video/zr36050.c b/drivers/media/video/zr36050.c
index 13b1e7b6fd6..0144576a612 100644
--- a/drivers/media/video/zr36050.c
+++ b/drivers/media/video/zr36050.c
@@ -26,7 +26,6 @@
#define ZR050_VERSION "v0.7.1"
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
diff --git a/drivers/media/video/zr36060.c b/drivers/media/video/zr36060.c
index b50dc403e6d..129744a07ab 100644
--- a/drivers/media/video/zr36060.c
+++ b/drivers/media/video/zr36060.c
@@ -26,7 +26,6 @@
#define ZR060_VERSION "v0.7"
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 790a2932ded..74022316fc6 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -47,7 +47,6 @@
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#include <linux/config.h>
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
@@ -92,9 +91,9 @@ static int mfcounter = 0;
* Public data...
*/
int mpt_lan_index = -1;
-int mpt_stm_index = -1;
+static int mpt_stm_index = -1;
-struct proc_dir_entry *mpt_proc_root_dir;
+static struct proc_dir_entry *mpt_proc_root_dir;
#define WHOINIT_UNKNOWN 0xAA
@@ -6272,7 +6271,6 @@ EXPORT_SYMBOL(mpt_resume);
EXPORT_SYMBOL(mpt_suspend);
#endif
EXPORT_SYMBOL(ioc_list);
-EXPORT_SYMBOL(mpt_proc_root_dir);
EXPORT_SYMBOL(mpt_register);
EXPORT_SYMBOL(mpt_deregister);
EXPORT_SYMBOL(mpt_event_register);
@@ -6290,7 +6288,6 @@ EXPORT_SYMBOL(mpt_verify_adapter);
EXPORT_SYMBOL(mpt_GetIocState);
EXPORT_SYMBOL(mpt_print_ioc_summary);
EXPORT_SYMBOL(mpt_lan_index);
-EXPORT_SYMBOL(mpt_stm_index);
EXPORT_SYMBOL(mpt_HardResetHandler);
EXPORT_SYMBOL(mpt_config);
EXPORT_SYMBOL(mpt_toolbox);
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index e7efeb7740b..8ad277a9afa 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -49,7 +49,6 @@
#define MPTBASE_H_INCLUDED
/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#include <linux/version.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -1007,10 +1006,8 @@ extern int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
* Public data decl's...
*/
extern struct list_head ioc_list;
-extern struct proc_dir_entry *mpt_proc_root_dir;
extern int mpt_lan_index; /* needed by mptlan.c */
-extern int mpt_stm_index; /* needed by mptstm.c */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#endif /* } __KERNEL__ */
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index cb2d59d5f5a..602138f8544 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -45,7 +45,6 @@
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
diff --git a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h
index 28754a9cb80..518996e0348 100644
--- a/drivers/message/fusion/mptctl.h
+++ b/drivers/message/fusion/mptctl.h
@@ -49,7 +49,6 @@
#define MPTCTL_H_INCLUDED
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#include "linux/version.h"
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h
index 750e343eb98..3726ecba570 100644
--- a/drivers/message/fusion/mptlan.h
+++ b/drivers/message/fusion/mptlan.h
@@ -66,7 +66,6 @@
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/spinlock.h>
-#include <linux/version.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
// #include <linux/trdevice.h>
diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c
index 9c4dd682ac7..bc2b72b3290 100644
--- a/drivers/misc/hdpuftrs/hdpu_cpustate.c
+++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c
@@ -14,7 +14,6 @@
*
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c
index 165f3405df2..4bb46179385 100644
--- a/drivers/misc/hdpuftrs/hdpu_nexus.c
+++ b/drivers/misc/hdpuftrs/hdpu_nexus.c
@@ -14,7 +14,6 @@
*
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h
index ecce4ffd3e2..d7e20a34f88 100644
--- a/drivers/misc/ibmasm/ibmasm.h
+++ b/drivers/misc/ibmasm/ibmasm.h
@@ -31,7 +31,6 @@
#include <linux/slab.h>
#include <linux/config.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/input.h>
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c
index c4a19d2dc67..0807c1c91e5 100644
--- a/drivers/mtd/chips/cfi_cmdset_0020.c
+++ b/drivers/mtd/chips/cfi_cmdset_0020.c
@@ -20,7 +20,6 @@
* - Plugged memory leak in cfi_staa_writev().
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c
index de48b35f560..666cce1bf60 100644
--- a/drivers/mtd/devices/pmc551.c
+++ b/drivers/mtd/devices/pmc551.c
@@ -82,7 +82,6 @@
* * Comb the init routine. It's still a bit cludgy on a few things.
*/
-#include <linux/version.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/mtd/maps/ebony.c b/drivers/mtd/maps/ebony.c
index c0daf58357c..60a6e51d662 100644
--- a/drivers/mtd/maps/ebony.c
+++ b/drivers/mtd/maps/ebony.c
@@ -21,7 +21,6 @@
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/config.h>
-#include <linux/version.h>
#include <asm/io.h>
#include <asm/ibm44x.h>
#include <platforms/4xx/ebony.h>
diff --git a/drivers/mtd/maps/ocotea.c b/drivers/mtd/maps/ocotea.c
index 6e559bc1463..c223514ca2e 100644
--- a/drivers/mtd/maps/ocotea.c
+++ b/drivers/mtd/maps/ocotea.c
@@ -19,7 +19,6 @@
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/config.h>
-#include <linux/version.h>
#include <asm/io.h>
#include <asm/ibm44x.h>
#include <platforms/4xx/ocotea.h>
diff --git a/drivers/mtd/maps/walnut.c b/drivers/mtd/maps/walnut.c
index 5c17bca3a37..f46bec66150 100644
--- a/drivers/mtd/maps/walnut.c
+++ b/drivers/mtd/maps/walnut.c
@@ -21,7 +21,6 @@
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/config.h>
-#include <linux/version.h>
#include <asm/io.h>
#include <asm/ibm4xx.h>
#include <platforms/4xx/walnut.h>
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c
index 3cafcdf28ae..9c5945d6df8 100644
--- a/drivers/mtd/nand/au1550nd.c
+++ b/drivers/mtd/nand/au1550nd.c
@@ -17,6 +17,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/version.h>
#include <asm/io.h>
/* fixme: this is ugly */
diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c
index 056dfc17a07..a3c7fea404d 100644
--- a/drivers/mtd/nand/autcpu12.c
+++ b/drivers/mtd/nand/autcpu12.c
@@ -27,7 +27,6 @@
* 10-06-2002 TG 128K card support added
*/
-#include <linux/version.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/module.h>
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index cc38fa0d45c..f67d5d6eb9a 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -12,6 +12,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/jiffies.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/onenand.h>
#include <linux/mtd/partitions.h>
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c
index 041ee59ea77..0ab8d29caee 100644
--- a/drivers/mtd/rfd_ftl.c
+++ b/drivers/mtd/rfd_ftl.c
@@ -18,6 +18,7 @@
#include <linux/mtd/blktrans.h>
#include <linux/mtd/mtd.h>
#include <linux/vmalloc.h>
+#include <linux/jiffies.h>
#include <asm/types.h>
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 1958d9e16a3..5c69d57f854 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -447,7 +447,7 @@ config NET_SB1250_MAC
config SGI_IOC3_ETH
bool "SGI IOC3 Ethernet"
- depends on NET_ETHERNET && PCI && SGI_IP27 && BROKEN
+ depends on NET_ETHERNET && PCI && SGI_IP27
select CRC32
select MII
help
@@ -2523,6 +2523,19 @@ config PPP_BSDCOMP
module; it is called bsd_comp and will show up in the directory
modules once you have said "make modules". If unsure, say N.
+config PPP_MPPE
+ tristate "PPP MPPE compression (encryption) (EXPERIMENTAL)"
+ depends on PPP && EXPERIMENTAL
+ select CRYPTO
+ select CRYPTO_SHA1
+ select CRYPTO_ARC4
+ ---help---
+ Support for the MPPE Encryption protocol, as employed by the
+ Microsoft Point-to-Point Tunneling Protocol.
+
+ See http://pptpclient.sourceforge.net/ for information on
+ configuring PPTP clients and servers to utilize this method.
+
config PPPOE
tristate "PPP over Ethernet (EXPERIMENTAL)"
depends on EXPERIMENTAL && PPP
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 7c313cb341b..4cffd34442a 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -112,6 +112,7 @@ obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
+obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
obj-$(CONFIG_SLIP) += slip.o
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 0ee3e27969c..c53848f787e 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -18,7 +18,6 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/dma-mapping.h>
#include <asm/uaccess.h>
@@ -29,8 +28,8 @@
#define DRV_MODULE_NAME "b44"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "0.95"
-#define DRV_MODULE_RELDATE "Aug 3, 2004"
+#define DRV_MODULE_VERSION "0.96"
+#define DRV_MODULE_RELDATE "Nov 8, 2005"
#define B44_DEF_MSG_ENABLE \
(NETIF_MSG_DRV | \
@@ -102,14 +101,16 @@ MODULE_DEVICE_TABLE(pci, b44_pci_tbl);
static void b44_halt(struct b44 *);
static void b44_init_rings(struct b44 *);
static void b44_init_hw(struct b44 *);
-static int b44_poll(struct net_device *dev, int *budget);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void b44_poll_controller(struct net_device *dev);
-#endif
static int dma_desc_align_mask;
static int dma_desc_sync_size;
+static const char b44_gstrings[][ETH_GSTRING_LEN] = {
+#define _B44(x...) # x,
+B44_STAT_REG_DECLARE
+#undef _B44
+};
+
static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev,
dma_addr_t dma_base,
unsigned long offset,
@@ -502,7 +503,10 @@ static void b44_stats_update(struct b44 *bp)
for (reg = B44_TX_GOOD_O; reg <= B44_TX_PAUSE; reg += 4UL) {
*val++ += br32(bp, reg);
}
- val = &bp->hw_stats.rx_good_octets;
+
+ /* Pad */
+ reg += 8*4UL;
+
for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL) {
*val++ += br32(bp, reg);
}
@@ -653,7 +657,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
/* Hardware bug work-around, the chip is unable to do PCI DMA
to/from anything above 1GB :-( */
- if(mapping+RX_PKT_BUF_SZ > B44_DMA_MASK) {
+ if (mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) {
/* Sigh... */
pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(skb);
@@ -663,7 +667,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
mapping = pci_map_single(bp->pdev, skb->data,
RX_PKT_BUF_SZ,
PCI_DMA_FROMDEVICE);
- if(mapping+RX_PKT_BUF_SZ > B44_DMA_MASK) {
+ if (mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) {
pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(skb);
return -ENOMEM;
@@ -890,11 +894,10 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
struct b44 *bp = netdev_priv(dev);
- unsigned long flags;
u32 istat, imask;
int handled = 0;
- spin_lock_irqsave(&bp->lock, flags);
+ spin_lock(&bp->lock);
istat = br32(bp, B44_ISTAT);
imask = br32(bp, B44_IMASK);
@@ -905,6 +908,12 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id, struct pt_regs *regs)
istat &= imask;
if (istat) {
handled = 1;
+
+ if (unlikely(!netif_running(dev))) {
+ printk(KERN_INFO "%s: late interrupt.\n", dev->name);
+ goto irq_ack;
+ }
+
if (netif_rx_schedule_prep(dev)) {
/* NOTE: These writes are posted by the readback of
* the ISTAT register below.
@@ -917,10 +926,11 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id, struct pt_regs *regs)
dev->name);
}
+irq_ack:
bw32(bp, B44_ISTAT, istat);
br32(bp, B44_ISTAT);
}
- spin_unlock_irqrestore(&bp->lock, flags);
+ spin_unlock(&bp->lock);
return IRQ_RETVAL(handled);
}
@@ -948,6 +958,7 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct b44 *bp = netdev_priv(dev);
struct sk_buff *bounce_skb;
+ int rc = NETDEV_TX_OK;
dma_addr_t mapping;
u32 len, entry, ctrl;
@@ -957,29 +968,28 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* This is a hard error, log it. */
if (unlikely(TX_BUFFS_AVAIL(bp) < 1)) {
netif_stop_queue(dev);
- spin_unlock_irq(&bp->lock);
printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
dev->name);
- return 1;
+ goto err_out;
}
mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
- if(mapping+len > B44_DMA_MASK) {
+ if (mapping + len > B44_DMA_MASK) {
/* Chip can't handle DMA to/from >1GB, use bounce buffer */
pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE);
bounce_skb = __dev_alloc_skb(TX_PKT_BUF_SZ,
GFP_ATOMIC|GFP_DMA);
if (!bounce_skb)
- return NETDEV_TX_BUSY;
+ goto err_out;
mapping = pci_map_single(bp->pdev, bounce_skb->data,
len, PCI_DMA_TODEVICE);
- if(mapping+len > B44_DMA_MASK) {
+ if (mapping + len > B44_DMA_MASK) {
pci_unmap_single(bp->pdev, mapping,
len, PCI_DMA_TODEVICE);
dev_kfree_skb_any(bounce_skb);
- return NETDEV_TX_BUSY;
+ goto err_out;
}
memcpy(skb_put(bounce_skb, len), skb->data, skb->len);
@@ -1019,11 +1029,16 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (TX_BUFFS_AVAIL(bp) < 1)
netif_stop_queue(dev);
+ dev->trans_start = jiffies;
+
+out_unlock:
spin_unlock_irq(&bp->lock);
- dev->trans_start = jiffies;
+ return rc;
- return 0;
+err_out:
+ rc = NETDEV_TX_BUSY;
+ goto out_unlock;
}
static int b44_change_mtu(struct net_device *dev, int new_mtu)
@@ -1097,8 +1112,7 @@ static void b44_free_rings(struct b44 *bp)
*
* The chip has been shut down and the driver detached from
* the networking, so no interrupts or new tx packets will
- * end up in the driver. bp->lock is not held and we are not
- * in an interrupt context and thus may sleep.
+ * end up in the driver.
*/
static void b44_init_rings(struct b44 *bp)
{
@@ -1170,16 +1184,14 @@ static int b44_alloc_consistent(struct b44 *bp)
int size;
size = B44_RX_RING_SIZE * sizeof(struct ring_info);
- bp->rx_buffers = kmalloc(size, GFP_KERNEL);
+ bp->rx_buffers = kzalloc(size, GFP_KERNEL);
if (!bp->rx_buffers)
goto out_err;
- memset(bp->rx_buffers, 0, size);
size = B44_TX_RING_SIZE * sizeof(struct ring_info);
- bp->tx_buffers = kmalloc(size, GFP_KERNEL);
+ bp->tx_buffers = kzalloc(size, GFP_KERNEL);
if (!bp->tx_buffers)
goto out_err;
- memset(bp->tx_buffers, 0, size);
size = DMA_TABLE_BYTES;
bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma);
@@ -1190,10 +1202,10 @@ static int b44_alloc_consistent(struct b44 *bp)
struct dma_desc *rx_ring;
dma_addr_t rx_ring_dma;
- if (!(rx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL)))
+ rx_ring = kzalloc(size, GFP_KERNEL);
+ if (!rx_ring)
goto out_err;
- memset(rx_ring, 0, size);
rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring,
DMA_TABLE_BYTES,
DMA_BIDIRECTIONAL);
@@ -1216,10 +1228,10 @@ static int b44_alloc_consistent(struct b44 *bp)
struct dma_desc *tx_ring;
dma_addr_t tx_ring_dma;
- if (!(tx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL)))
+ tx_ring = kzalloc(size, GFP_KERNEL);
+ if (!tx_ring)
goto out_err;
- memset(tx_ring, 0, size);
tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring,
DMA_TABLE_BYTES,
DMA_TO_DEVICE);
@@ -1382,22 +1394,21 @@ static int b44_open(struct net_device *dev)
err = b44_alloc_consistent(bp);
if (err)
- return err;
-
- err = request_irq(dev->irq, b44_interrupt, SA_SHIRQ, dev->name, dev);
- if (err)
- goto err_out_free;
-
- spin_lock_irq(&bp->lock);
+ goto out;
b44_init_rings(bp);
b44_init_hw(bp);
- bp->flags |= B44_FLAG_INIT_COMPLETE;
netif_carrier_off(dev);
b44_check_phy(bp);
- spin_unlock_irq(&bp->lock);
+ err = request_irq(dev->irq, b44_interrupt, SA_SHIRQ, dev->name, dev);
+ if (unlikely(err < 0)) {
+ b44_chip_reset(bp);
+ b44_free_rings(bp);
+ b44_free_consistent(bp);
+ goto out;
+ }
init_timer(&bp->timer);
bp->timer.expires = jiffies + HZ;
@@ -1406,11 +1417,7 @@ static int b44_open(struct net_device *dev)
add_timer(&bp->timer);
b44_enable_ints(bp);
-
- return 0;
-
-err_out_free:
- b44_free_consistent(bp);
+out:
return err;
}
@@ -1445,6 +1452,8 @@ static int b44_close(struct net_device *dev)
netif_stop_queue(dev);
+ netif_poll_disable(dev);
+
del_timer_sync(&bp->timer);
spin_lock_irq(&bp->lock);
@@ -1454,13 +1463,14 @@ static int b44_close(struct net_device *dev)
#endif
b44_halt(bp);
b44_free_rings(bp);
- bp->flags &= ~B44_FLAG_INIT_COMPLETE;
netif_carrier_off(bp->dev);
spin_unlock_irq(&bp->lock);
free_irq(dev->irq, dev);
+ netif_poll_enable(dev);
+
b44_free_consistent(bp);
return 0;
@@ -1525,8 +1535,6 @@ static void __b44_set_rx_mode(struct net_device *dev)
{
struct b44 *bp = netdev_priv(dev);
u32 val;
- int i=0;
- unsigned char zero[6] = {0,0,0,0,0,0};
val = br32(bp, B44_RXCONFIG);
val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI);
@@ -1534,14 +1542,17 @@ static void __b44_set_rx_mode(struct net_device *dev)
val |= RXCONFIG_PROMISC;
bw32(bp, B44_RXCONFIG, val);
} else {
+ unsigned char zero[6] = {0, 0, 0, 0, 0, 0};
+ int i = 0;
+
__b44_set_mac_addr(bp);
if (dev->flags & IFF_ALLMULTI)
val |= RXCONFIG_ALLMULTI;
else
- i=__b44_load_mcast(bp, dev);
+ i = __b44_load_mcast(bp, dev);
- for(;i<64;i++) {
+ for (; i < 64; i++) {
__b44_cam_write(bp, zero, i);
}
bw32(bp, B44_RXCONFIG, val);
@@ -1605,7 +1616,7 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct b44 *bp = netdev_priv(dev);
- if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
+ if (!netif_running(dev))
return -EAGAIN;
cmd->supported = (SUPPORTED_Autoneg);
cmd->supported |= (SUPPORTED_100baseT_Half |
@@ -1643,7 +1654,7 @@ static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct b44 *bp = netdev_priv(dev);
- if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
+ if (!netif_running(dev))
return -EAGAIN;
/* We do not support gigabit. */
@@ -1773,6 +1784,37 @@ static int b44_set_pauseparam(struct net_device *dev,
return 0;
}
+static void b44_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ switch(stringset) {
+ case ETH_SS_STATS:
+ memcpy(data, *b44_gstrings, sizeof(b44_gstrings));
+ break;
+ }
+}
+
+static int b44_get_stats_count(struct net_device *dev)
+{
+ return ARRAY_SIZE(b44_gstrings);
+}
+
+static void b44_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct b44 *bp = netdev_priv(dev);
+ u32 *val = &bp->hw_stats.tx_good_octets;
+ u32 i;
+
+ spin_lock_irq(&bp->lock);
+
+ b44_stats_update(bp);
+
+ for (i = 0; i < ARRAY_SIZE(b44_gstrings); i++)
+ *data++ = *val++;
+
+ spin_unlock_irq(&bp->lock);
+}
+
static struct ethtool_ops b44_ethtool_ops = {
.get_drvinfo = b44_get_drvinfo,
.get_settings = b44_get_settings,
@@ -1785,6 +1827,9 @@ static struct ethtool_ops b44_ethtool_ops = {
.set_pauseparam = b44_set_pauseparam,
.get_msglevel = b44_get_msglevel,
.set_msglevel = b44_set_msglevel,
+ .get_strings = b44_get_strings,
+ .get_stats_count = b44_get_stats_count,
+ .get_ethtool_stats = b44_get_ethtool_stats,
.get_perm_addr = ethtool_op_get_perm_addr,
};
@@ -1893,9 +1938,9 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK);
if (err) {
- printk(KERN_ERR PFX "No usable DMA configuration, "
- "aborting.\n");
- goto err_out_free_res;
+ printk(KERN_ERR PFX "No usable DMA configuration, "
+ "aborting.\n");
+ goto err_out_free_res;
}
b44reg_base = pci_resource_start(pdev, 0);
@@ -1917,10 +1962,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
bp = netdev_priv(dev);
bp->pdev = pdev;
bp->dev = dev;
- if (b44_debug >= 0)
- bp->msg_enable = (1 << b44_debug) - 1;
- else
- bp->msg_enable = B44_DEF_MSG_ENABLE;
+
+ bp->msg_enable = netif_msg_init(b44_debug, B44_DEF_MSG_ENABLE);
spin_lock_init(&bp->lock);
@@ -2010,17 +2053,14 @@ err_out_disable_pdev:
static void __devexit b44_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
+ struct b44 *bp = netdev_priv(dev);
- if (dev) {
- struct b44 *bp = netdev_priv(dev);
-
- unregister_netdev(dev);
- iounmap(bp->regs);
- free_netdev(dev);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
- }
+ unregister_netdev(dev);
+ iounmap(bp->regs);
+ free_netdev(dev);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
}
static int b44_suspend(struct pci_dev *pdev, pm_message_t state)
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index 593cb0ad410..b178662978f 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -346,29 +346,63 @@ struct ring_info {
#define B44_MCAST_TABLE_SIZE 32
+#define B44_STAT_REG_DECLARE \
+ _B44(tx_good_octets) \
+ _B44(tx_good_pkts) \
+ _B44(tx_octets) \
+ _B44(tx_pkts) \
+ _B44(tx_broadcast_pkts) \
+ _B44(tx_multicast_pkts) \
+ _B44(tx_len_64) \
+ _B44(tx_len_65_to_127) \
+ _B44(tx_len_128_to_255) \
+ _B44(tx_len_256_to_511) \
+ _B44(tx_len_512_to_1023) \
+ _B44(tx_len_1024_to_max) \
+ _B44(tx_jabber_pkts) \
+ _B44(tx_oversize_pkts) \
+ _B44(tx_fragment_pkts) \
+ _B44(tx_underruns) \
+ _B44(tx_total_cols) \
+ _B44(tx_single_cols) \
+ _B44(tx_multiple_cols) \
+ _B44(tx_excessive_cols) \
+ _B44(tx_late_cols) \
+ _B44(tx_defered) \
+ _B44(tx_carrier_lost) \
+ _B44(tx_pause_pkts) \
+ _B44(rx_good_octets) \
+ _B44(rx_good_pkts) \
+ _B44(rx_octets) \
+ _B44(rx_pkts) \
+ _B44(rx_broadcast_pkts) \
+ _B44(rx_multicast_pkts) \
+ _B44(rx_len_64) \
+ _B44(rx_len_65_to_127) \
+ _B44(rx_len_128_to_255) \
+ _B44(rx_len_256_to_511) \
+ _B44(rx_len_512_to_1023) \
+ _B44(rx_len_1024_to_max) \
+ _B44(rx_jabber_pkts) \
+ _B44(rx_oversize_pkts) \
+ _B44(rx_fragment_pkts) \
+ _B44(rx_missed_pkts) \
+ _B44(rx_crc_align_errs) \
+ _B44(rx_undersize) \
+ _B44(rx_crc_errs) \
+ _B44(rx_align_errs) \
+ _B44(rx_symbol_errs) \
+ _B44(rx_pause_pkts) \
+ _B44(rx_nonpause_pkts)
+
/* SW copy of device statistics, kept up to date by periodic timer
- * which probes HW values. Must have same relative layout as HW
- * register above, because b44_stats_update depends upon this.
+ * which probes HW values. Check b44_stats_update if you mess with
+ * the layout
*/
struct b44_hw_stats {
- u32 tx_good_octets, tx_good_pkts, tx_octets;
- u32 tx_pkts, tx_broadcast_pkts, tx_multicast_pkts;
- u32 tx_len_64, tx_len_65_to_127, tx_len_128_to_255;
- u32 tx_len_256_to_511, tx_len_512_to_1023, tx_len_1024_to_max;
- u32 tx_jabber_pkts, tx_oversize_pkts, tx_fragment_pkts;
- u32 tx_underruns, tx_total_cols, tx_single_cols;
- u32 tx_multiple_cols, tx_excessive_cols, tx_late_cols;
- u32 tx_defered, tx_carrier_lost, tx_pause_pkts;
- u32 __pad1[8];
-
- u32 rx_good_octets, rx_good_pkts, rx_octets;
- u32 rx_pkts, rx_broadcast_pkts, rx_multicast_pkts;
- u32 rx_len_64, rx_len_65_to_127, rx_len_128_to_255;
- u32 rx_len_256_to_511, rx_len_512_to_1023, rx_len_1024_to_max;
- u32 rx_jabber_pkts, rx_oversize_pkts, rx_fragment_pkts;
- u32 rx_missed_pkts, rx_crc_align_errs, rx_undersize;
- u32 rx_crc_errs, rx_align_errs, rx_symbol_errs;
- u32 rx_pause_pkts, rx_nonpause_pkts;
+#define _B44(x) u32 x;
+B44_STAT_REG_DECLARE
+#undef _B44
};
struct b44 {
@@ -386,7 +420,6 @@ struct b44 {
u32 dma_offset;
u32 flags;
-#define B44_FLAG_INIT_COMPLETE 0x00000001
#define B44_FLAG_BUGGY_TXPTR 0x00000002
#define B44_FLAG_REORDER_BUG 0x00000004
#define B44_FLAG_PAUSE_AUTO 0x00008000
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 8032126fd58..94cec3cf2a1 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1604,35 +1604,27 @@ static int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_
(NETIF_F_SG|NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM)
/*
- * Compute the features available to the bonding device by
- * intersection of all of the slave devices' BOND_INTERSECT_FEATURES.
- * Call this after attaching or detaching a slave to update the
- * bond's features.
+ * Compute the common dev->feature set available to all slaves. Some
+ * feature bits are managed elsewhere, so preserve feature bits set on
+ * master device that are not part of the examined set.
*/
static int bond_compute_features(struct bonding *bond)
{
- int i;
+ unsigned long features = BOND_INTERSECT_FEATURES;
struct slave *slave;
struct net_device *bond_dev = bond->dev;
- int features = bond->bond_features;
+ int i;
- bond_for_each_slave(bond, slave, i) {
- struct net_device * slave_dev = slave->dev;
- if (i == 0) {
- features |= BOND_INTERSECT_FEATURES;
- }
- features &=
- ~(~slave_dev->features & BOND_INTERSECT_FEATURES);
- }
+ bond_for_each_slave(bond, slave, i)
+ features &= (slave->dev->features & BOND_INTERSECT_FEATURES);
- /* turn off NETIF_F_SG if we need a csum and h/w can't do it */
if ((features & NETIF_F_SG) &&
- !(features & (NETIF_F_IP_CSUM |
- NETIF_F_NO_CSUM |
- NETIF_F_HW_CSUM))) {
+ !(features & (NETIF_F_IP_CSUM |
+ NETIF_F_NO_CSUM |
+ NETIF_F_HW_CSUM)))
features &= ~NETIF_F_SG;
- }
+ features |= (bond_dev->features & ~BOND_INTERSECT_FEATURES);
bond_dev->features = features;
return 0;
@@ -4561,8 +4553,6 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par
NETIF_F_HW_VLAN_RX |
NETIF_F_HW_VLAN_FILTER);
- bond->bond_features = bond_dev->features;
-
#ifdef CONFIG_PROC_FS
bond_create_proc_entry(bond);
#endif
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index bbf9da8af62..1433e91db0f 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -40,8 +40,8 @@
#include "bond_3ad.h"
#include "bond_alb.h"
-#define DRV_VERSION "2.6.4"
-#define DRV_RELDATE "September 26, 2005"
+#define DRV_VERSION "2.6.5"
+#define DRV_RELDATE "November 4, 2005"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
@@ -211,9 +211,6 @@ struct bonding {
struct bond_params params;
struct list_head vlan_list;
struct vlan_group *vlgrp;
- /* the features the bonding device supports, independently
- * of any slaves */
- int bond_features;
};
/**
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 50f43dbf31a..1f7ca453bb4 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -67,7 +67,6 @@
*/
#include <linux/config.h>
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index b68b9cad76e..64105e4eaf3 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -409,7 +409,6 @@ static irqreturn_t e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static void e100_rx(struct net_device *dev);
static int e100_close(struct net_device *dev);
static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-static int e100_ethtool_ioctl(struct net_device* dev, struct ifreq *ifr);
static int e100_set_config(struct net_device* dev, struct ifmap* map);
static void e100_tx_timeout(struct net_device *dev);
static struct net_device_stats *e100_get_stats(struct net_device *dev);
@@ -436,6 +435,8 @@ static void e100_reset_transceiver(struct net_device* net);
static void e100_clear_network_leds(unsigned long dummy);
static void e100_set_network_leds(int active);
+static struct ethtool_ops e100_ethtool_ops;
+
static void broadcom_check_speed(struct net_device* dev);
static void broadcom_check_duplex(struct net_device* dev);
static void tdk_check_speed(struct net_device* dev);
@@ -495,6 +496,7 @@ etrax_ethernet_init(void)
dev->get_stats = e100_get_stats;
dev->set_multicast_list = set_multicast_list;
dev->set_mac_address = e100_set_mac_address;
+ dev->ethtool_ops = &e100_ethtool_ops;
dev->do_ioctl = e100_ioctl;
dev->set_config = e100_set_config;
dev->tx_timeout = e100_tx_timeout;
@@ -1448,8 +1450,6 @@ e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
spin_lock(&np->lock); /* Preempt protection */
switch (cmd) {
- case SIOCETHTOOL:
- return e100_ethtool_ioctl(dev,ifr);
case SIOCGMIIPHY: /* Get PHY address */
data->phy_id = mdio_phy_addr;
break;
@@ -1486,88 +1486,81 @@ e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return 0;
}
-static int
-e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
+static int e100_set_settings(struct net_device *dev,
+ struct ethtool_cmd *ecmd)
{
- struct ethtool_cmd ecmd;
-
- if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
- return -EFAULT;
-
- switch (ecmd.cmd) {
- case ETHTOOL_GSET:
- {
- memset((void *) &ecmd, 0, sizeof (ecmd));
- ecmd.supported =
- SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
+ ecmd->supported = SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
- ecmd.port = PORT_TP;
- ecmd.transceiver = XCVR_EXTERNAL;
- ecmd.phy_address = mdio_phy_addr;
- ecmd.speed = current_speed;
- ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
- ecmd.advertising = ADVERTISED_TP;
- if (current_duplex == autoneg && current_speed_selection == 0)
- ecmd.advertising |= ADVERTISED_Autoneg;
- else {
- ecmd.advertising |=
- ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
- ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
- if (current_speed_selection == 10)
- ecmd.advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full);
- else if (current_speed_selection == 100)
- ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full);
- if (current_duplex == half)
- ecmd.advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full);
- else if (current_duplex == full)
- ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half);
- }
- ecmd.autoneg = AUTONEG_ENABLE;
- if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
- return -EFAULT;
- }
- break;
- case ETHTOOL_SSET:
- {
- if (!capable(CAP_NET_ADMIN)) {
- return -EPERM;
- }
- if (ecmd.autoneg == AUTONEG_ENABLE) {
- e100_set_duplex(dev, autoneg);
- e100_set_speed(dev, 0);
- } else {
- e100_set_duplex(dev, ecmd.duplex == DUPLEX_HALF ? half : full);
- e100_set_speed(dev, ecmd.speed == SPEED_10 ? 10: 100);
- }
- }
- break;
- case ETHTOOL_GDRVINFO:
- {
- struct ethtool_drvinfo info;
- memset((void *) &info, 0, sizeof (info));
- strncpy(info.driver, "ETRAX 100LX", sizeof(info.driver) - 1);
- strncpy(info.version, "$Revision: 1.31 $", sizeof(info.version) - 1);
- strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1);
- strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1);
- info.regdump_len = 0;
- info.eedump_len = 0;
- info.testinfo_len = 0;
- if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
- return -EFAULT;
- }
- break;
- case ETHTOOL_NWAY_RST:
- if (current_duplex == autoneg && current_speed_selection == 0)
- e100_negotiate(dev);
- break;
- default:
- return -EOPNOTSUPP;
- break;
+ ecmd->port = PORT_TP;
+ ecmd->transceiver = XCVR_EXTERNAL;
+ ecmd->phy_address = mdio_phy_addr;
+ ecmd->speed = current_speed;
+ ecmd->duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+ ecmd->advertising = ADVERTISED_TP;
+
+ if (current_duplex == autoneg && current_speed_selection == 0)
+ ecmd->advertising |= ADVERTISED_Autoneg;
+ else {
+ ecmd->advertising |=
+ ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
+ if (current_speed_selection == 10)
+ ecmd->advertising &= ~(ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full);
+ else if (current_speed_selection == 100)
+ ecmd->advertising &= ~(ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full);
+ if (current_duplex == half)
+ ecmd->advertising &= ~(ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Full);
+ else if (current_duplex == full)
+ ecmd->advertising &= ~(ADVERTISED_10baseT_Half |
+ ADVERTISED_100baseT_Half);
+ }
+
+ ecmd->autoneg = AUTONEG_ENABLE;
+ return 0;
+}
+
+static int e100_set_settings(struct net_device *dev,
+ struct ethtool_cmd *ecmd)
+{
+ if (ecmd->autoneg == AUTONEG_ENABLE) {
+ e100_set_duplex(dev, autoneg);
+ e100_set_speed(dev, 0);
+ } else {
+ e100_set_duplex(dev, ecmd->duplex == DUPLEX_HALF ? half : full);
+ e100_set_speed(dev, ecmd->speed == SPEED_10 ? 10: 100);
}
+
+ return 0;
+}
+
+static void e100_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strncpy(info->driver, "ETRAX 100LX", sizeof(info->driver) - 1);
+ strncpy(info->version, "$Revision: 1.31 $", sizeof(info->version) - 1);
+ strncpy(info->fw_version, "N/A", sizeof(info->fw_version) - 1);
+ strncpy(info->bus_info, "N/A", sizeof(info->bus_info) - 1);
+}
+
+static int e100_nway_reset(struct net_device *dev)
+{
+ if (current_duplex == autoneg && current_speed_selection == 0)
+ e100_negotiate(dev);
return 0;
}
+static struct ethtool_ops e100_ethtool_ops = {
+ .get_settings = e100_get_settings,
+ .set_settings = e100_set_settings,
+ .get_drvinfo = e100_get_drvinfo,
+ .nway_reset = e100_nway_reset,
+ .get_link = ethtool_op_get_link,
+};
+
static int
e100_set_config(struct net_device *dev, struct ifmap *map)
{
diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c
index 7809838e6c4..2a290cc397a 100644
--- a/drivers/net/dgrs.c
+++ b/drivers/net/dgrs.c
@@ -1549,7 +1549,7 @@ MODULE_PARM_DESC(nicmode, "Digi RightSwitch operating mode (1: switch, 2: multi-
static int __init dgrs_init_module (void)
{
int i;
- int eisacount = 0, pcicount = 0;
+ int cardcount = 0;
/*
* Command line variable overrides
@@ -1591,15 +1591,13 @@ static int __init dgrs_init_module (void)
* Find and configure all the cards
*/
#ifdef CONFIG_EISA
- eisacount = eisa_driver_register(&dgrs_eisa_driver);
- if (eisacount < 0)
- return eisacount;
-#endif
-#ifdef CONFIG_PCI
- pcicount = pci_register_driver(&dgrs_pci_driver);
- if (pcicount)
- return pcicount;
+ cardcount = eisa_driver_register(&dgrs_eisa_driver);
+ if (cardcount < 0)
+ return cardcount;
#endif
+ cardcount = pci_register_driver(&dgrs_pci_driver);
+ if (cardcount)
+ return cardcount;
return 0;
}
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index c0af6fb1fbb..f8c9bcdab68 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -60,7 +60,6 @@
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/skbuff.h>
-#include <linux/version.h>
#include <linux/spinlock.h>
#include <linux/crc32.h>
#include <linux/mii.h>
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index eb169a8e877..7a6aeae2c9f 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1478,7 +1478,7 @@ static inline int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
if(pci_dma_mapping_error(rx->dma_addr)) {
dev_kfree_skb_any(rx->skb);
- rx->skb = 0;
+ rx->skb = NULL;
rx->dma_addr = 0;
return -ENOMEM;
}
@@ -1764,7 +1764,7 @@ static int e100_up(struct nic *nic)
if((err = e100_hw_init(nic)))
goto err_clean_cbs;
e100_set_multicast_list(nic->netdev);
- e100_start_receiver(nic, 0);
+ e100_start_receiver(nic, NULL);
mod_timer(&nic->watchdog, jiffies);
if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ,
nic->netdev->name, nic->netdev)))
@@ -1844,7 +1844,7 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,
BMCR_LOOPBACK);
- e100_start_receiver(nic, 0);
+ e100_start_receiver(nic, NULL);
if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) {
err = -ENOMEM;
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index 1105543b9d8..e7ec96c964a 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -4,7 +4,6 @@
#include <linux/mii.h>
#include <linux/netdevice.h>
#include <linux/types.h>
-#include <linux/version.h>
#include <linux/list.h>
#include <linux/fs_enet_pd.h>
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 962580f2c4a..54d294ad6df 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -90,7 +90,6 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/dma-mapping.h>
#include <linux/crc32.h>
#include <linux/mii.h>
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index c77ca6c0d04..220084e5334 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -43,7 +43,6 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/crc32.h>
#include <linux/workqueue.h>
#include <linux/ethtool.h>
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 68e3578e761..5a2d810ce57 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -34,7 +34,6 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/crc32.h>
#include <asm/types.h>
#include <asm/uaccess.h>
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index 5a74d3d3dbe..7263395d78b 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -32,7 +32,6 @@
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/platform_device.h>
#include <asm/ocp.h>
#include <linux/crc32.h>
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index b71fab6e34f..e92c17f6931 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -96,7 +96,6 @@
#undef HP100_MULTICAST_FILTER /* Need to be debugged... */
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 94239f67f3a..be191d80ef9 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -35,7 +35,6 @@
#include <linux/config.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/ioport.h>
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index 49e5467bdd7..6a3129bc15a 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -46,10 +46,8 @@
#include <linux/udp.h>
#ifdef CONFIG_SERIAL_8250
-#include <linux/serial.h>
-#include <asm/serial.h>
-#define IOC3_BAUD (22000000 / (3*16))
-#define IOC3_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#endif
#include <linux/netdevice.h>
@@ -1146,12 +1144,11 @@ static inline int ioc3_is_menet(struct pci_dev *pdev)
* around ioc3 oddities in this respect.
*
* The IOC3 serials use a 22MHz clock rate with an additional divider by 3.
- * (IOC3_BAUD = (22000000 / (3*16)))
*/
static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)
{
- struct serial_struct req;
+ struct uart_port port;
/*
* We need to recognice and treat the fourth MENET serial as it
@@ -1165,20 +1162,25 @@ static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)
if (ioc3_is_menet(pdev) && PCI_SLOT(pdev->devfn) == 3)
return;
- /* Register to interrupt zero because we share the interrupt with
- the serial driver which we don't properly support yet. */
- memset(&req, 0, sizeof(req));
- req.irq = 0;
- req.flags = IOC3_COM_FLAGS;
- req.io_type = SERIAL_IO_MEM;
- req.iomem_reg_shift = 0;
- req.baud_base = IOC3_BAUD;
-
- req.iomem_base = (unsigned char *) &ioc3->sregs.uarta;
- register_serial(&req);
-
- req.iomem_base = (unsigned char *) &ioc3->sregs.uartb;
- register_serial(&req);
+ /*
+ * Register to interrupt zero because we share the interrupt with
+ * the serial driver which we don't properly support yet.
+ *
+ * Can't use UPF_IOREMAP as the whole of IOC3 resources have already
+ * been registered.
+ */
+ memset(&port, 0, sizeof(port));
+ port.irq = 0;
+ port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+ port.iotype = UPIO_MEM;
+ port.regshift = 0;
+ port.uartclk = 22000000 / 3;
+
+ port.membase = (unsigned char *) &ioc3->sregs.uarta;
+ serial8250_register_port(&port);
+
+ port.membase = (unsigned char *) &ioc3->sregs.uartb;
+ serial8250_register_port(&port);
}
#endif
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 0282771b1cb..3137592d60c 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -1459,8 +1459,10 @@ toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
*/
IRDA_DEBUG (1, "%s(BANDWIDTH), %s, (%X/%ld\n", __FUNCTION__
,dev->name, INB (OBOE_STATUS), irq->ifr_baudrate );
- if (!in_interrupt () && !capable (CAP_NET_ADMIN))
- return -EPERM;
+ if (!in_interrupt () && !capable (CAP_NET_ADMIN)) {
+ ret = -EPERM;
+ goto out;
+ }
/* self->speed=irq->ifr_baudrate; */
/* toshoboe_setbaud(self); */
@@ -1470,8 +1472,10 @@ toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
case SIOCSMEDIABUSY: /* Set media busy */
IRDA_DEBUG (1, "%s(MEDIABUSY), %s, (%X/%x)\n", __FUNCTION__
,dev->name, INB (OBOE_STATUS), capable (CAP_NET_ADMIN) );
- if (!capable (CAP_NET_ADMIN))
- return -EPERM;
+ if (!capable (CAP_NET_ADMIN)) {
+ ret = -EPERM;
+ goto out;
+ }
irda_device_set_media_busy (self->netdev, TRUE);
break;
case SIOCGRECEIVING: /* Check if we are receiving right now */
@@ -1483,7 +1487,7 @@ toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
IRDA_DEBUG (1, "%s(?), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
ret = -EOPNOTSUPP;
}
-
+out:
spin_unlock_irqrestore(&self->spinlock, flags);
return ret;
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index d86d8f055a6..77eadf84cb2 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -58,7 +58,6 @@
#include <linux/config.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/ioport.h>
diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c
index ce5761816a6..d8c99f038fa 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/mac8390.c
@@ -15,7 +15,6 @@
* and fixed access to Sonic Sys card which masquerades as a Farallon
* by rayk@knightsmanor.org */
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h
index bcfda5192da..f769f9b626e 100644
--- a/drivers/net/mv643xx_eth.h
+++ b/drivers/net/mv643xx_eth.h
@@ -1,7 +1,6 @@
#ifndef __MV643XX_ETH_H__
#define __MV643XX_ETH_H__
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index a3c3fc9c0d8..f857ae94d26 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -110,7 +110,6 @@
#include <linux/init.h>
#include <linux/ip.h> /* for iph */
#include <linux/in.h> /* for IPPROTO_... */
-#include <linux/eeprom.h>
#include <linux/compiler.h>
#include <linux/prefetch.h>
#include <linux/ethtool.h>
@@ -445,7 +444,6 @@ struct ns83820 {
u32 MEAR_cache;
u32 IMR_cache;
- struct eeprom ee;
unsigned linkstate;
@@ -1558,15 +1556,13 @@ static void ns83820_getmac(struct ns83820 *dev, u8 *mac)
unsigned i;
for (i=0; i<3; i++) {
u32 data;
-#if 0 /* I've left this in as an example of how to use eeprom.h */
- data = eeprom_readw(&dev->ee, 0xa + 2 - i);
-#else
+
/* Read from the perfect match memory: this is loaded by
* the chip from the EEPROM via the EELOAD self test.
*/
writel(i*2, dev->base + RFCR);
data = readl(dev->base + RFDR);
-#endif
+
*mac++ = data;
*mac++ = data >> 8;
}
@@ -1851,8 +1847,6 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
spin_lock_init(&dev->misc_lock);
dev->pci_dev = pci_dev;
- dev->ee.cache = &dev->MEAR_cache;
- dev->ee.lock = &dev->misc_lock;
SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pci_dev->dev);
@@ -1887,9 +1881,6 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
dev->IMR_cache = 0;
- setup_ee_mem_bitbanger(&dev->ee, dev->base + MEAR, 3, 2, 1, 0,
- 0);
-
err = request_irq(pci_dev->irq, ns83820_irq, SA_SHIRQ,
DRV_NAME, ndev);
if (err) {
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index 59e8183c639..400f652282d 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -31,6 +31,7 @@
#include <linux/spinlock.h>
#include <linux/init.h>
#include <asm/uaccess.h>
+#include <asm/string.h>
#define PPP_VERSION "2.4.2"
@@ -835,8 +836,11 @@ process_input_packet(struct asyncppp *ap)
err:
/* frame had an error, remember that, reset SC_TOSS & SC_ESCAPE */
ap->state = SC_PREV_ERROR;
- if (skb)
+ if (skb) {
+ /* make skb appear as freshly allocated */
skb_trim(skb, 0);
+ skb_reserve(skb, - skb_headroom(skb));
+ }
}
/* Called when the tty driver has data for us. Runs parallel with the
@@ -889,10 +893,17 @@ ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2);
if (skb == 0)
goto nomem;
- /* Try to get the payload 4-byte aligned */
+ ap->rpkt = skb;
+ }
+ if (skb->len == 0) {
+ /* Try to get the payload 4-byte aligned.
+ * This should match the
+ * PPP_ALLSTATIONS/PPP_UI/compressed tests in
+ * process_input_packet, but we do not have
+ * enough chars here to test buf[1] and buf[2].
+ */
if (buf[0] != PPP_ALLSTATIONS)
skb_reserve(skb, 2 + (buf[0] & 1));
- ap->rpkt = skb;
}
if (n > skb_tailroom(skb)) {
/* packet overflowed MRU */
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index d3c9958b00d..50430f79f8c 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -137,13 +137,14 @@ struct ppp {
/*
* Bits in flags: SC_NO_TCP_CCID, SC_CCP_OPEN, SC_CCP_UP, SC_LOOP_TRAFFIC,
- * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP.
+ * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP,
+ * SC_MUST_COMP
* Bits in rstate: SC_DECOMP_RUN, SC_DC_ERROR, SC_DC_FERROR.
* Bits in xstate: SC_COMP_RUN
*/
#define SC_FLAG_BITS (SC_NO_TCP_CCID|SC_CCP_OPEN|SC_CCP_UP|SC_LOOP_TRAFFIC \
|SC_MULTILINK|SC_MP_SHORTSEQ|SC_MP_XSHORTSEQ \
- |SC_COMP_TCP|SC_REJ_COMP_TCP)
+ |SC_COMP_TCP|SC_REJ_COMP_TCP|SC_MUST_COMP)
/*
* Private data structure for each channel.
@@ -1027,6 +1028,56 @@ ppp_xmit_process(struct ppp *ppp)
ppp_xmit_unlock(ppp);
}
+static inline struct sk_buff *
+pad_compress_skb(struct ppp *ppp, struct sk_buff *skb)
+{
+ struct sk_buff *new_skb;
+ int len;
+ int new_skb_size = ppp->dev->mtu +
+ ppp->xcomp->comp_extra + ppp->dev->hard_header_len;
+ int compressor_skb_size = ppp->dev->mtu +
+ ppp->xcomp->comp_extra + PPP_HDRLEN;
+ new_skb = alloc_skb(new_skb_size, GFP_ATOMIC);
+ if (!new_skb) {
+ if (net_ratelimit())
+ printk(KERN_ERR "PPP: no memory (comp pkt)\n");
+ return NULL;
+ }
+ if (ppp->dev->hard_header_len > PPP_HDRLEN)
+ skb_reserve(new_skb,
+ ppp->dev->hard_header_len - PPP_HDRLEN);
+
+ /* compressor still expects A/C bytes in hdr */
+ len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
+ new_skb->data, skb->len + 2,
+ compressor_skb_size);
+ if (len > 0 && (ppp->flags & SC_CCP_UP)) {
+ kfree_skb(skb);
+ skb = new_skb;
+ skb_put(skb, len);
+ skb_pull(skb, 2); /* pull off A/C bytes */
+ } else if (len == 0) {
+ /* didn't compress, or CCP not up yet */
+ kfree_skb(new_skb);
+ new_skb = skb;
+ } else {
+ /*
+ * (len < 0)
+ * MPPE requires that we do not send unencrypted
+ * frames. The compressor will return -1 if we
+ * should drop the frame. We cannot simply test
+ * the compress_proto because MPPE and MPPC share
+ * the same number.
+ */
+ if (net_ratelimit())
+ printk(KERN_ERR "ppp: compressor dropped pkt\n");
+ kfree_skb(skb);
+ kfree_skb(new_skb);
+ new_skb = NULL;
+ }
+ return new_skb;
+}
+
/*
* Compress and send a frame.
* The caller should have locked the xmit path,
@@ -1113,29 +1164,14 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
/* try to do packet compression */
if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0
&& proto != PPP_LCP && proto != PPP_CCP) {
- new_skb = alloc_skb(ppp->dev->mtu + ppp->dev->hard_header_len,
- GFP_ATOMIC);
- if (new_skb == 0) {
- printk(KERN_ERR "PPP: no memory (comp pkt)\n");
+ if (!(ppp->flags & SC_CCP_UP) && (ppp->flags & SC_MUST_COMP)) {
+ if (net_ratelimit())
+ printk(KERN_ERR "ppp: compression required but down - pkt dropped.\n");
goto drop;
}
- if (ppp->dev->hard_header_len > PPP_HDRLEN)
- skb_reserve(new_skb,
- ppp->dev->hard_header_len - PPP_HDRLEN);
-
- /* compressor still expects A/C bytes in hdr */
- len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
- new_skb->data, skb->len + 2,
- ppp->dev->mtu + PPP_HDRLEN);
- if (len > 0 && (ppp->flags & SC_CCP_UP)) {
- kfree_skb(skb);
- skb = new_skb;
- skb_put(skb, len);
- skb_pull(skb, 2); /* pull off A/C bytes */
- } else {
- /* didn't compress, or CCP not up yet */
- kfree_skb(new_skb);
- }
+ skb = pad_compress_skb(ppp, skb);
+ if (!skb)
+ goto drop;
}
/*
@@ -1155,7 +1191,8 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
return;
drop:
- kfree_skb(skb);
+ if (skb)
+ kfree_skb(skb);
++ppp->stats.tx_errors;
}
@@ -1552,6 +1589,9 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
&& (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0)
skb = ppp_decompress_frame(ppp, skb);
+ if (ppp->flags & SC_MUST_COMP && ppp->rstate & SC_DC_FERROR)
+ goto err;
+
proto = PPP_PROTO(skb);
switch (proto) {
case PPP_VJC_COMP:
diff --git a/drivers/net/ppp_mppe.c b/drivers/net/ppp_mppe.c
new file mode 100644
index 00000000000..1985d1b57c4
--- /dev/null
+++ b/drivers/net/ppp_mppe.c
@@ -0,0 +1,724 @@
+/*
+ * ppp_mppe.c - interface MPPE to the PPP code.
+ * This version is for use with Linux kernel 2.6.14+
+ *
+ * By Frank Cusack <fcusack@fcusack.com>.
+ * Copyright (c) 2002,2003,2004 Google, Inc.
+ * All rights reserved.
+ *
+ * License:
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies. This software is provided without any
+ * warranty, express or implied.
+ *
+ * ALTERNATIVELY, provided that this notice is retained in full, this product
+ * may be distributed under the terms of the GNU General Public License (GPL),
+ * in which case the provisions of the GPL apply INSTEAD OF those given above.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * Changelog:
+ * 08/12/05 - Matt Domsch <Matt_Domsch@dell.com>
+ * Only need extra skb padding on transmit, not receive.
+ * 06/18/04 - Matt Domsch <Matt_Domsch@dell.com>, Oleg Makarenko <mole@quadra.ru>
+ * Use Linux kernel 2.6 arc4 and sha1 routines rather than
+ * providing our own.
+ * 2/15/04 - TS: added #include <version.h> and testing for Kernel
+ * version before using
+ * MOD_DEC_USAGE_COUNT/MOD_INC_USAGE_COUNT which are
+ * deprecated in 2.6
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/crypto.h>
+#include <linux/mm.h>
+#include <linux/ppp_defs.h>
+#include <linux/ppp-comp.h>
+#include <asm/scatterlist.h>
+
+#include "ppp_mppe.h"
+
+MODULE_AUTHOR("Frank Cusack <fcusack@fcusack.com>");
+MODULE_DESCRIPTION("Point-to-Point Protocol Microsoft Point-to-Point Encryption support");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE));
+MODULE_VERSION("1.0.2");
+
+static void
+setup_sg(struct scatterlist *sg, const void *address, unsigned int length)
+{
+ sg[0].page = virt_to_page(address);
+ sg[0].offset = offset_in_page(address);
+ sg[0].length = length;
+}
+
+#define SHA1_PAD_SIZE 40
+
+/*
+ * kernel crypto API needs its arguments to be in kmalloc'd memory, not in the module
+ * static data area. That means sha_pad needs to be kmalloc'd.
+ */
+
+struct sha_pad {
+ unsigned char sha_pad1[SHA1_PAD_SIZE];
+ unsigned char sha_pad2[SHA1_PAD_SIZE];
+};
+static struct sha_pad *sha_pad;
+
+static inline void sha_pad_init(struct sha_pad *shapad)
+{
+ memset(shapad->sha_pad1, 0x00, sizeof(shapad->sha_pad1));
+ memset(shapad->sha_pad2, 0xF2, sizeof(shapad->sha_pad2));
+}
+
+/*
+ * State for an MPPE (de)compressor.
+ */
+struct ppp_mppe_state {
+ struct crypto_tfm *arc4;
+ struct crypto_tfm *sha1;
+ unsigned char *sha1_digest;
+ unsigned char master_key[MPPE_MAX_KEY_LEN];
+ unsigned char session_key[MPPE_MAX_KEY_LEN];
+ unsigned keylen; /* key length in bytes */
+ /* NB: 128-bit == 16, 40-bit == 8! */
+ /* If we want to support 56-bit, */
+ /* the unit has to change to bits */
+ unsigned char bits; /* MPPE control bits */
+ unsigned ccount; /* 12-bit coherency count (seqno) */
+ unsigned stateful; /* stateful mode flag */
+ int discard; /* stateful mode packet loss flag */
+ int sanity_errors; /* take down LCP if too many */
+ int unit;
+ int debug;
+ struct compstat stats;
+};
+
+/* struct ppp_mppe_state.bits definitions */
+#define MPPE_BIT_A 0x80 /* Encryption table were (re)inititalized */
+#define MPPE_BIT_B 0x40 /* MPPC only (not implemented) */
+#define MPPE_BIT_C 0x20 /* MPPC only (not implemented) */
+#define MPPE_BIT_D 0x10 /* This is an encrypted frame */
+
+#define MPPE_BIT_FLUSHED MPPE_BIT_A
+#define MPPE_BIT_ENCRYPTED MPPE_BIT_D
+
+#define MPPE_BITS(p) ((p)[4] & 0xf0)
+#define MPPE_CCOUNT(p) ((((p)[4] & 0x0f) << 8) + (p)[5])
+#define MPPE_CCOUNT_SPACE 0x1000 /* The size of the ccount space */
+
+#define MPPE_OVHD 2 /* MPPE overhead/packet */
+#define SANITY_MAX 1600 /* Max bogon factor we will tolerate */
+
+/*
+ * Key Derivation, from RFC 3078, RFC 3079.
+ * Equivalent to Get_Key() for MS-CHAP as described in RFC 3079.
+ */
+static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *InterimKey)
+{
+ struct scatterlist sg[4];
+
+ setup_sg(&sg[0], state->master_key, state->keylen);
+ setup_sg(&sg[1], sha_pad->sha_pad1, sizeof(sha_pad->sha_pad1));
+ setup_sg(&sg[2], state->session_key, state->keylen);
+ setup_sg(&sg[3], sha_pad->sha_pad2, sizeof(sha_pad->sha_pad2));
+
+ crypto_digest_digest (state->sha1, sg, 4, state->sha1_digest);
+
+ memcpy(InterimKey, state->sha1_digest, state->keylen);
+}
+
+/*
+ * Perform the MPPE rekey algorithm, from RFC 3078, sec. 7.3.
+ * Well, not what's written there, but rather what they meant.
+ */
+static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
+{
+ unsigned char InterimKey[MPPE_MAX_KEY_LEN];
+ struct scatterlist sg_in[1], sg_out[1];
+
+ get_new_key_from_sha(state, InterimKey);
+ if (!initial_key) {
+ crypto_cipher_setkey(state->arc4, InterimKey, state->keylen);
+ setup_sg(sg_in, InterimKey, state->keylen);
+ setup_sg(sg_out, state->session_key, state->keylen);
+ if (crypto_cipher_encrypt(state->arc4, sg_out, sg_in,
+ state->keylen) != 0) {
+ printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n");
+ }
+ } else {
+ memcpy(state->session_key, InterimKey, state->keylen);
+ }
+ if (state->keylen == 8) {
+ /* See RFC 3078 */
+ state->session_key[0] = 0xd1;
+ state->session_key[1] = 0x26;
+ state->session_key[2] = 0x9e;
+ }
+ crypto_cipher_setkey(state->arc4, state->session_key, state->keylen);
+}
+
+/*
+ * Allocate space for a (de)compressor.
+ */
+static void *mppe_alloc(unsigned char *options, int optlen)
+{
+ struct ppp_mppe_state *state;
+ unsigned int digestsize;
+
+ if (optlen != CILEN_MPPE + sizeof(state->master_key)
+ || options[0] != CI_MPPE || options[1] != CILEN_MPPE)
+ goto out;
+
+ state = (struct ppp_mppe_state *) kmalloc(sizeof(*state), GFP_KERNEL);
+ if (state == NULL)
+ goto out;
+
+ memset(state, 0, sizeof(*state));
+
+ state->arc4 = crypto_alloc_tfm("arc4", 0);
+ if (!state->arc4)
+ goto out_free;
+
+ state->sha1 = crypto_alloc_tfm("sha1", 0);
+ if (!state->sha1)
+ goto out_free;
+
+ digestsize = crypto_tfm_alg_digestsize(state->sha1);
+ if (digestsize < MPPE_MAX_KEY_LEN)
+ goto out_free;
+
+ state->sha1_digest = kmalloc(digestsize, GFP_KERNEL);
+ if (!state->sha1_digest)
+ goto out_free;
+
+ /* Save keys. */
+ memcpy(state->master_key, &options[CILEN_MPPE],
+ sizeof(state->master_key));
+ memcpy(state->session_key, state->master_key,
+ sizeof(state->master_key));
+
+ /*
+ * We defer initial key generation until mppe_init(), as mppe_alloc()
+ * is called frequently during negotiation.
+ */
+
+ return (void *)state;
+
+ out_free:
+ if (state->sha1_digest)
+ kfree(state->sha1_digest);
+ if (state->sha1)
+ crypto_free_tfm(state->sha1);
+ if (state->arc4)
+ crypto_free_tfm(state->arc4);
+ kfree(state);
+ out:
+ return NULL;
+}
+
+/*
+ * Deallocate space for a (de)compressor.
+ */
+static void mppe_free(void *arg)
+{
+ struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+ if (state) {
+ if (state->sha1_digest)
+ kfree(state->sha1_digest);
+ if (state->sha1)
+ crypto_free_tfm(state->sha1);
+ if (state->arc4)
+ crypto_free_tfm(state->arc4);
+ kfree(state);
+ }
+}
+
+/*
+ * Initialize (de)compressor state.
+ */
+static int
+mppe_init(void *arg, unsigned char *options, int optlen, int unit, int debug,
+ const char *debugstr)
+{
+ struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+ unsigned char mppe_opts;
+
+ if (optlen != CILEN_MPPE
+ || options[0] != CI_MPPE || options[1] != CILEN_MPPE)
+ return 0;
+
+ MPPE_CI_TO_OPTS(&options[2], mppe_opts);
+ if (mppe_opts & MPPE_OPT_128)
+ state->keylen = 16;
+ else if (mppe_opts & MPPE_OPT_40)
+ state->keylen = 8;
+ else {
+ printk(KERN_WARNING "%s[%d]: unknown key length\n", debugstr,
+ unit);
+ return 0;
+ }
+ if (mppe_opts & MPPE_OPT_STATEFUL)
+ state->stateful = 1;
+
+ /* Generate the initial session key. */
+ mppe_rekey(state, 1);
+
+ if (debug) {
+ int i;
+ char mkey[sizeof(state->master_key) * 2 + 1];
+ char skey[sizeof(state->session_key) * 2 + 1];
+
+ printk(KERN_DEBUG "%s[%d]: initialized with %d-bit %s mode\n",
+ debugstr, unit, (state->keylen == 16) ? 128 : 40,
+ (state->stateful) ? "stateful" : "stateless");
+
+ for (i = 0; i < sizeof(state->master_key); i++)
+ sprintf(mkey + i * 2, "%02x", state->master_key[i]);
+ for (i = 0; i < sizeof(state->session_key); i++)
+ sprintf(skey + i * 2, "%02x", state->session_key[i]);
+ printk(KERN_DEBUG
+ "%s[%d]: keys: master: %s initial session: %s\n",
+ debugstr, unit, mkey, skey);
+ }
+
+ /*
+ * Initialize the coherency count. The initial value is not specified
+ * in RFC 3078, but we can make a reasonable assumption that it will
+ * start at 0. Setting it to the max here makes the comp/decomp code
+ * do the right thing (determined through experiment).
+ */
+ state->ccount = MPPE_CCOUNT_SPACE - 1;
+
+ /*
+ * Note that even though we have initialized the key table, we don't
+ * set the FLUSHED bit. This is contrary to RFC 3078, sec. 3.1.
+ */
+ state->bits = MPPE_BIT_ENCRYPTED;
+
+ state->unit = unit;
+ state->debug = debug;
+
+ return 1;
+}
+
+static int
+mppe_comp_init(void *arg, unsigned char *options, int optlen, int unit,
+ int hdrlen, int debug)
+{
+ /* ARGSUSED */
+ return mppe_init(arg, options, optlen, unit, debug, "mppe_comp_init");
+}
+
+/*
+ * We received a CCP Reset-Request (actually, we are sending a Reset-Ack),
+ * tell the compressor to rekey. Note that we MUST NOT rekey for
+ * every CCP Reset-Request; we only rekey on the next xmit packet.
+ * We might get multiple CCP Reset-Requests if our CCP Reset-Ack is lost.
+ * So, rekeying for every CCP Reset-Request is broken as the peer will not
+ * know how many times we've rekeyed. (If we rekey and THEN get another
+ * CCP Reset-Request, we must rekey again.)
+ */
+static void mppe_comp_reset(void *arg)
+{
+ struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+
+ state->bits |= MPPE_BIT_FLUSHED;
+}
+
+/*
+ * Compress (encrypt) a packet.
+ * It's strange to call this a compressor, since the output is always
+ * MPPE_OVHD + 2 bytes larger than the input.
+ */
+static int
+mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
+ int isize, int osize)
+{
+ struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+ int proto;
+ struct scatterlist sg_in[1], sg_out[1];
+
+ /*
+ * Check that the protocol is in the range we handle.
+ */
+ proto = PPP_PROTOCOL(ibuf);
+ if (proto < 0x0021 || proto > 0x00fa)
+ return 0;
+
+ /* Make sure we have enough room to generate an encrypted packet. */
+ if (osize < isize + MPPE_OVHD + 2) {
+ /* Drop the packet if we should encrypt it, but can't. */
+ printk(KERN_DEBUG "mppe_compress[%d]: osize too small! "
+ "(have: %d need: %d)\n", state->unit,
+ osize, osize + MPPE_OVHD + 2);
+ return -1;
+ }
+
+ osize = isize + MPPE_OVHD + 2;
+
+ /*
+ * Copy over the PPP header and set control bits.
+ */
+ obuf[0] = PPP_ADDRESS(ibuf);
+ obuf[1] = PPP_CONTROL(ibuf);
+ obuf[2] = PPP_COMP >> 8; /* isize + MPPE_OVHD + 1 */
+ obuf[3] = PPP_COMP; /* isize + MPPE_OVHD + 2 */
+ obuf += PPP_HDRLEN;
+
+ state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
+ if (state->debug >= 7)
+ printk(KERN_DEBUG "mppe_compress[%d]: ccount %d\n", state->unit,
+ state->ccount);
+ obuf[0] = state->ccount >> 8;
+ obuf[1] = state->ccount & 0xff;
+
+ if (!state->stateful || /* stateless mode */
+ ((state->ccount & 0xff) == 0xff) || /* "flag" packet */
+ (state->bits & MPPE_BIT_FLUSHED)) { /* CCP Reset-Request */
+ /* We must rekey */
+ if (state->debug && state->stateful)
+ printk(KERN_DEBUG "mppe_compress[%d]: rekeying\n",
+ state->unit);
+ mppe_rekey(state, 0);
+ state->bits |= MPPE_BIT_FLUSHED;
+ }
+ obuf[0] |= state->bits;
+ state->bits &= ~MPPE_BIT_FLUSHED; /* reset for next xmit */
+
+ obuf += MPPE_OVHD;
+ ibuf += 2; /* skip to proto field */
+ isize -= 2;
+
+ /* Encrypt packet */
+ setup_sg(sg_in, ibuf, isize);
+ setup_sg(sg_out, obuf, osize);
+ if (crypto_cipher_encrypt(state->arc4, sg_out, sg_in, isize) != 0) {
+ printk(KERN_DEBUG "crypto_cypher_encrypt failed\n");
+ return -1;
+ }
+
+ state->stats.unc_bytes += isize;
+ state->stats.unc_packets++;
+ state->stats.comp_bytes += osize;
+ state->stats.comp_packets++;
+
+ return osize;
+}
+
+/*
+ * Since every frame grows by MPPE_OVHD + 2 bytes, this is always going
+ * to look bad ... and the longer the link is up the worse it will get.
+ */
+static void mppe_comp_stats(void *arg, struct compstat *stats)
+{
+ struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+
+ *stats = state->stats;
+}
+
+static int
+mppe_decomp_init(void *arg, unsigned char *options, int optlen, int unit,
+ int hdrlen, int mru, int debug)
+{
+ /* ARGSUSED */
+ return mppe_init(arg, options, optlen, unit, debug, "mppe_decomp_init");
+}
+
+/*
+ * We received a CCP Reset-Ack. Just ignore it.
+ */
+static void mppe_decomp_reset(void *arg)
+{
+ /* ARGSUSED */
+ return;
+}
+
+/*
+ * Decompress (decrypt) an MPPE packet.
+ */
+static int
+mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
+ int osize)
+{
+ struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+ unsigned ccount;
+ int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED;
+ int sanity = 0;
+ struct scatterlist sg_in[1], sg_out[1];
+
+ if (isize <= PPP_HDRLEN + MPPE_OVHD) {
+ if (state->debug)
+ printk(KERN_DEBUG
+ "mppe_decompress[%d]: short pkt (%d)\n",
+ state->unit, isize);
+ return DECOMP_ERROR;
+ }
+
+ /*
+ * Make sure we have enough room to decrypt the packet.
+ * Note that for our test we only subtract 1 byte whereas in
+ * mppe_compress() we added 2 bytes (+MPPE_OVHD);
+ * this is to account for possible PFC.
+ */
+ if (osize < isize - MPPE_OVHD - 1) {
+ printk(KERN_DEBUG "mppe_decompress[%d]: osize too small! "
+ "(have: %d need: %d)\n", state->unit,
+ osize, isize - MPPE_OVHD - 1);
+ return DECOMP_ERROR;
+ }
+ osize = isize - MPPE_OVHD - 2; /* assume no PFC */
+
+ ccount = MPPE_CCOUNT(ibuf);
+ if (state->debug >= 7)
+ printk(KERN_DEBUG "mppe_decompress[%d]: ccount %d\n",
+ state->unit, ccount);
+
+ /* sanity checks -- terminate with extreme prejudice */
+ if (!(MPPE_BITS(ibuf) & MPPE_BIT_ENCRYPTED)) {
+ printk(KERN_DEBUG
+ "mppe_decompress[%d]: ENCRYPTED bit not set!\n",
+ state->unit);
+ state->sanity_errors += 100;
+ sanity = 1;
+ }
+ if (!state->stateful && !flushed) {
+ printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set in "
+ "stateless mode!\n", state->unit);
+ state->sanity_errors += 100;
+ sanity = 1;
+ }
+ if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) {
+ printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set on "
+ "flag packet!\n", state->unit);
+ state->sanity_errors += 100;
+ sanity = 1;
+ }
+
+ if (sanity) {
+ if (state->sanity_errors < SANITY_MAX)
+ return DECOMP_ERROR;
+ else
+ /*
+ * Take LCP down if the peer is sending too many bogons.
+ * We don't want to do this for a single or just a few
+ * instances since it could just be due to packet corruption.
+ */
+ return DECOMP_FATALERROR;
+ }
+
+ /*
+ * Check the coherency count.
+ */
+
+ if (!state->stateful) {
+ /* RFC 3078, sec 8.1. Rekey for every packet. */
+ while (state->ccount != ccount) {
+ mppe_rekey(state, 0);
+ state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
+ }
+ } else {
+ /* RFC 3078, sec 8.2. */
+ if (!state->discard) {
+ /* normal state */
+ state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
+ if (ccount != state->ccount) {
+ /*
+ * (ccount > state->ccount)
+ * Packet loss detected, enter the discard state.
+ * Signal the peer to rekey (by sending a CCP Reset-Request).
+ */
+ state->discard = 1;
+ return DECOMP_ERROR;
+ }
+ } else {
+ /* discard state */
+ if (!flushed) {
+ /* ccp.c will be silent (no additional CCP Reset-Requests). */
+ return DECOMP_ERROR;
+ } else {
+ /* Rekey for every missed "flag" packet. */
+ while ((ccount & ~0xff) !=
+ (state->ccount & ~0xff)) {
+ mppe_rekey(state, 0);
+ state->ccount =
+ (state->ccount +
+ 256) % MPPE_CCOUNT_SPACE;
+ }
+
+ /* reset */
+ state->discard = 0;
+ state->ccount = ccount;
+ /*
+ * Another problem with RFC 3078 here. It implies that the
+ * peer need not send a Reset-Ack packet. But RFC 1962
+ * requires it. Hopefully, M$ does send a Reset-Ack; even
+ * though it isn't required for MPPE synchronization, it is
+ * required to reset CCP state.
+ */
+ }
+ }
+ if (flushed)
+ mppe_rekey(state, 0);
+ }
+
+ /*
+ * Fill in the first part of the PPP header. The protocol field
+ * comes from the decrypted data.
+ */
+ obuf[0] = PPP_ADDRESS(ibuf); /* +1 */
+ obuf[1] = PPP_CONTROL(ibuf); /* +1 */
+ obuf += 2;
+ ibuf += PPP_HDRLEN + MPPE_OVHD;
+ isize -= PPP_HDRLEN + MPPE_OVHD; /* -6 */
+ /* net osize: isize-4 */
+
+ /*
+ * Decrypt the first byte in order to check if it is
+ * a compressed or uncompressed protocol field.
+ */
+ setup_sg(sg_in, ibuf, 1);
+ setup_sg(sg_out, obuf, 1);
+ if (crypto_cipher_decrypt(state->arc4, sg_out, sg_in, 1) != 0) {
+ printk(KERN_DEBUG "crypto_cypher_decrypt failed\n");
+ return DECOMP_ERROR;
+ }
+
+ /*
+ * Do PFC decompression.
+ * This would be nicer if we were given the actual sk_buff
+ * instead of a char *.
+ */
+ if ((obuf[0] & 0x01) != 0) {
+ obuf[1] = obuf[0];
+ obuf[0] = 0;
+ obuf++;
+ osize++;
+ }
+
+ /* And finally, decrypt the rest of the packet. */
+ setup_sg(sg_in, ibuf + 1, isize - 1);
+ setup_sg(sg_out, obuf + 1, osize - 1);
+ if (crypto_cipher_decrypt(state->arc4, sg_out, sg_in, isize - 1) != 0) {
+ printk(KERN_DEBUG "crypto_cypher_decrypt failed\n");
+ return DECOMP_ERROR;
+ }
+
+ state->stats.unc_bytes += osize;
+ state->stats.unc_packets++;
+ state->stats.comp_bytes += isize;
+ state->stats.comp_packets++;
+
+ /* good packet credit */
+ state->sanity_errors >>= 1;
+
+ return osize;
+}
+
+/*
+ * Incompressible data has arrived (this should never happen!).
+ * We should probably drop the link if the protocol is in the range
+ * of what should be encrypted. At the least, we should drop this
+ * packet. (How to do this?)
+ */
+static void mppe_incomp(void *arg, unsigned char *ibuf, int icnt)
+{
+ struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+
+ if (state->debug &&
+ (PPP_PROTOCOL(ibuf) >= 0x0021 && PPP_PROTOCOL(ibuf) <= 0x00fa))
+ printk(KERN_DEBUG
+ "mppe_incomp[%d]: incompressible (unencrypted) data! "
+ "(proto %04x)\n", state->unit, PPP_PROTOCOL(ibuf));
+
+ state->stats.inc_bytes += icnt;
+ state->stats.inc_packets++;
+ state->stats.unc_bytes += icnt;
+ state->stats.unc_packets++;
+}
+
+/*************************************************************
+ * Module interface table
+ *************************************************************/
+
+/*
+ * Procedures exported to if_ppp.c.
+ */
+static struct compressor ppp_mppe = {
+ .compress_proto = CI_MPPE,
+ .comp_alloc = mppe_alloc,
+ .comp_free = mppe_free,
+ .comp_init = mppe_comp_init,
+ .comp_reset = mppe_comp_reset,
+ .compress = mppe_compress,
+ .comp_stat = mppe_comp_stats,
+ .decomp_alloc = mppe_alloc,
+ .decomp_free = mppe_free,
+ .decomp_init = mppe_decomp_init,
+ .decomp_reset = mppe_decomp_reset,
+ .decompress = mppe_decompress,
+ .incomp = mppe_incomp,
+ .decomp_stat = mppe_comp_stats,
+ .owner = THIS_MODULE,
+ .comp_extra = MPPE_PAD,
+};
+
+/*
+ * ppp_mppe_init()
+ *
+ * Prior to allowing load, try to load the arc4 and sha1 crypto
+ * libraries. The actual use will be allocated later, but
+ * this way the module will fail to insmod if they aren't available.
+ */
+
+static int __init ppp_mppe_init(void)
+{
+ int answer;
+ if (!(crypto_alg_available("arc4", 0) &&
+ crypto_alg_available("sha1", 0)))
+ return -ENODEV;
+
+ sha_pad = kmalloc(sizeof(struct sha_pad), GFP_KERNEL);
+ if (!sha_pad)
+ return -ENOMEM;
+ sha_pad_init(sha_pad);
+
+ answer = ppp_register_compressor(&ppp_mppe);
+
+ if (answer == 0)
+ printk(KERN_INFO "PPP MPPE Compression module registered\n");
+ else
+ kfree(sha_pad);
+
+ return answer;
+}
+
+static void __exit ppp_mppe_cleanup(void)
+{
+ ppp_unregister_compressor(&ppp_mppe);
+ kfree(sha_pad);
+}
+
+module_init(ppp_mppe_init);
+module_exit(ppp_mppe_cleanup);
diff --git a/drivers/net/ppp_mppe.h b/drivers/net/ppp_mppe.h
new file mode 100644
index 00000000000..7a14e058c66
--- /dev/null
+++ b/drivers/net/ppp_mppe.h
@@ -0,0 +1,86 @@
+#define MPPE_PAD 4 /* MPPE growth per frame */
+#define MPPE_MAX_KEY_LEN 16 /* largest key length (128-bit) */
+
+/* option bits for ccp_options.mppe */
+#define MPPE_OPT_40 0x01 /* 40 bit */
+#define MPPE_OPT_128 0x02 /* 128 bit */
+#define MPPE_OPT_STATEFUL 0x04 /* stateful mode */
+/* unsupported opts */
+#define MPPE_OPT_56 0x08 /* 56 bit */
+#define MPPE_OPT_MPPC 0x10 /* MPPC compression */
+#define MPPE_OPT_D 0x20 /* Unknown */
+#define MPPE_OPT_UNSUPPORTED (MPPE_OPT_56|MPPE_OPT_MPPC|MPPE_OPT_D)
+#define MPPE_OPT_UNKNOWN 0x40 /* Bits !defined in RFC 3078 were set */
+
+/*
+ * This is not nice ... the alternative is a bitfield struct though.
+ * And unfortunately, we cannot share the same bits for the option
+ * names above since C and H are the same bit. We could do a u_int32
+ * but then we have to do a htonl() all the time and/or we still need
+ * to know which octet is which.
+ */
+#define MPPE_C_BIT 0x01 /* MPPC */
+#define MPPE_D_BIT 0x10 /* Obsolete, usage unknown */
+#define MPPE_L_BIT 0x20 /* 40-bit */
+#define MPPE_S_BIT 0x40 /* 128-bit */
+#define MPPE_M_BIT 0x80 /* 56-bit, not supported */
+#define MPPE_H_BIT 0x01 /* Stateless (in a different byte) */
+
+/* Does not include H bit; used for least significant octet only. */
+#define MPPE_ALL_BITS (MPPE_D_BIT|MPPE_L_BIT|MPPE_S_BIT|MPPE_M_BIT|MPPE_H_BIT)
+
+/* Build a CI from mppe opts (see RFC 3078) */
+#define MPPE_OPTS_TO_CI(opts, ci) \
+ do { \
+ u_char *ptr = ci; /* u_char[4] */ \
+ \
+ /* H bit */ \
+ if (opts & MPPE_OPT_STATEFUL) \
+ *ptr++ = 0x0; \
+ else \
+ *ptr++ = MPPE_H_BIT; \
+ *ptr++ = 0; \
+ *ptr++ = 0; \
+ \
+ /* S,L bits */ \
+ *ptr = 0; \
+ if (opts & MPPE_OPT_128) \
+ *ptr |= MPPE_S_BIT; \
+ if (opts & MPPE_OPT_40) \
+ *ptr |= MPPE_L_BIT; \
+ /* M,D,C bits not supported */ \
+ } while (/* CONSTCOND */ 0)
+
+/* The reverse of the above */
+#define MPPE_CI_TO_OPTS(ci, opts) \
+ do { \
+ u_char *ptr = ci; /* u_char[4] */ \
+ \
+ opts = 0; \
+ \
+ /* H bit */ \
+ if (!(ptr[0] & MPPE_H_BIT)) \
+ opts |= MPPE_OPT_STATEFUL; \
+ \
+ /* S,L bits */ \
+ if (ptr[3] & MPPE_S_BIT) \
+ opts |= MPPE_OPT_128; \
+ if (ptr[3] & MPPE_L_BIT) \
+ opts |= MPPE_OPT_40; \
+ \
+ /* M,D,C bits */ \
+ if (ptr[3] & MPPE_M_BIT) \
+ opts |= MPPE_OPT_56; \
+ if (ptr[3] & MPPE_D_BIT) \
+ opts |= MPPE_OPT_D; \
+ if (ptr[3] & MPPE_C_BIT) \
+ opts |= MPPE_OPT_MPPC; \
+ \
+ /* Other bits */ \
+ if (ptr[0] & ~MPPE_H_BIT) \
+ opts |= MPPE_OPT_UNKNOWN; \
+ if (ptr[1] || ptr[2]) \
+ opts |= MPPE_OPT_UNKNOWN; \
+ if (ptr[3] & ~MPPE_ALL_BITS) \
+ opts |= MPPE_OPT_UNKNOWN; \
+ } while (/* CONSTCOND */ 0)
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 0745dd9d01f..e57df8dfe6b 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -55,7 +55,6 @@
#include <linux/timex.h>
#include <linux/sched.h>
#include <linux/ethtool.h>
-#include <linux/version.h>
#include <linux/workqueue.h>
#include <linux/if_vlan.h>
@@ -1532,7 +1531,7 @@ static int init_nic(struct s2io_nic *nic)
#define LINK_UP_DOWN_INTERRUPT 1
#define MAC_RMAC_ERR_TIMER 2
-int s2io_link_fault_indication(nic_t *nic)
+static int s2io_link_fault_indication(nic_t *nic)
{
if (nic->intr_type != INTA)
return MAC_RMAC_ERR_TIMER;
@@ -1864,7 +1863,7 @@ static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag)
*
*/
-void fix_mac_address(nic_t * sp)
+static void fix_mac_address(nic_t * sp)
{
XENA_dev_config_t __iomem *bar0 = sp->bar0;
u64 val64;
@@ -2160,7 +2159,7 @@ int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb)
* SUCCESS on success or an appropriate -ve value on failure.
*/
-int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
+static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
{
struct net_device *dev = nic->dev;
struct sk_buff *skb;
@@ -2831,7 +2830,7 @@ static void alarm_intr_handler(struct s2io_nic *nic)
* SUCCESS on success and FAILURE on failure.
*/
-int wait_for_cmd_complete(nic_t * sp)
+static int wait_for_cmd_complete(nic_t * sp)
{
XENA_dev_config_t __iomem *bar0 = sp->bar0;
int ret = FAILURE, cnt = 0;
@@ -3077,7 +3076,7 @@ int s2io_set_swapper(nic_t * sp)
return SUCCESS;
}
-int wait_for_msix_trans(nic_t *nic, int i)
+static int wait_for_msix_trans(nic_t *nic, int i)
{
XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
u64 val64;
@@ -3116,7 +3115,7 @@ void restore_xmsi_data(nic_t *nic)
}
}
-void store_xmsi_data(nic_t *nic)
+static void store_xmsi_data(nic_t *nic)
{
XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
u64 val64, addr, data;
@@ -3288,7 +3287,7 @@ int s2io_enable_msi_x(nic_t *nic)
* file on failure.
*/
-int s2io_open(struct net_device *dev)
+static int s2io_open(struct net_device *dev)
{
nic_t *sp = dev->priv;
int err = 0;
@@ -3418,7 +3417,7 @@ hw_init_failed:
* file on failure.
*/
-int s2io_close(struct net_device *dev)
+static int s2io_close(struct net_device *dev)
{
nic_t *sp = dev->priv;
int i;
@@ -3467,7 +3466,7 @@ int s2io_close(struct net_device *dev)
* 0 on success & 1 on failure.
*/
-int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
+static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
{
nic_t *sp = dev->priv;
u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
@@ -3913,7 +3912,7 @@ static void s2io_updt_stats(nic_t *sp)
* pointer to the updated net_device_stats structure.
*/
-struct net_device_stats *s2io_get_stats(struct net_device *dev)
+static struct net_device_stats *s2io_get_stats(struct net_device *dev)
{
nic_t *sp = dev->priv;
mac_info_t *mac_control;
@@ -5106,19 +5105,20 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs;
}
-int s2io_ethtool_get_regs_len(struct net_device *dev)
+static int s2io_ethtool_get_regs_len(struct net_device *dev)
{
return (XENA_REG_SPACE);
}
-u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
+static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
{
nic_t *sp = dev->priv;
return (sp->rx_csum);
}
-int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
+
+static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
{
nic_t *sp = dev->priv;
@@ -5129,17 +5129,19 @@ int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
return 0;
}
-int s2io_get_eeprom_len(struct net_device *dev)
+
+static int s2io_get_eeprom_len(struct net_device *dev)
{
return (XENA_EEPROM_SPACE);
}
-int s2io_ethtool_self_test_count(struct net_device *dev)
+static int s2io_ethtool_self_test_count(struct net_device *dev)
{
return (S2IO_TEST_LEN);
}
-void s2io_ethtool_get_strings(struct net_device *dev,
- u32 stringset, u8 * data)
+
+static void s2io_ethtool_get_strings(struct net_device *dev,
+ u32 stringset, u8 * data)
{
switch (stringset) {
case ETH_SS_TEST:
@@ -5155,7 +5157,7 @@ static int s2io_ethtool_get_stats_count(struct net_device *dev)
return (S2IO_STAT_LEN);
}
-int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
+static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
{
if (data)
dev->features |= NETIF_F_IP_CSUM;
@@ -5208,7 +5210,7 @@ static struct ethtool_ops netdev_ethtool_ops = {
* function always return EOPNOTSUPPORTED
*/
-int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
return -EOPNOTSUPP;
}
@@ -5224,7 +5226,7 @@ int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
* file on failure.
*/
-int s2io_change_mtu(struct net_device *dev, int new_mtu)
+static int s2io_change_mtu(struct net_device *dev, int new_mtu)
{
nic_t *sp = dev->priv;
diff --git a/drivers/net/sk98lin/h/skdrv1st.h b/drivers/net/sk98lin/h/skdrv1st.h
index 308440bd0e1..91b8d4f4590 100644
--- a/drivers/net/sk98lin/h/skdrv1st.h
+++ b/drivers/net/sk98lin/h/skdrv1st.h
@@ -39,9 +39,6 @@
#ifndef __INC_SKDRV1ST_H
#define __INC_SKDRV1ST_H
-/* Check kernel version */
-#include <linux/version.h>
-
typedef struct s_AC SK_AC;
/* Set card versions */
diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c
index 4c56b8d8221..e5d6d95960c 100644
--- a/drivers/net/sk_mca.c
+++ b/drivers/net/sk_mca.c
@@ -93,7 +93,6 @@ History:
#include <linux/mca-legacy.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
diff --git a/drivers/net/sk_mca.h b/drivers/net/sk_mca.h
index 7e7c9958274..d6fa1823dfa 100644
--- a/drivers/net/sk_mca.h
+++ b/drivers/net/sk_mca.h
@@ -1,5 +1,3 @@
-#include <linux/version.h>
-
#ifndef _SK_MCA_INCLUDE_
#define _SK_MCA_INCLUDE_
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 572f121b1f4..596c93b12da 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -37,12 +37,13 @@
#include <linux/delay.h>
#include <linux/crc32.h>
#include <linux/dma-mapping.h>
+#include <linux/mii.h>
#include <asm/irq.h>
#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "1.1"
+#define DRV_VERSION "1.2"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
@@ -88,8 +89,8 @@ MODULE_DEVICE_TABLE(pci, skge_id_table);
static int skge_up(struct net_device *dev);
static int skge_down(struct net_device *dev);
static void skge_tx_clean(struct skge_port *skge);
-static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
-static void gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+static int xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+static int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
static void genesis_get_stats(struct skge_port *skge, u64 *data);
static void yukon_get_stats(struct skge_port *skge, u64 *data);
static void yukon_init(struct skge_hw *hw, int port);
@@ -129,7 +130,7 @@ static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs,
regs->len - B3_RI_WTO_R1);
}
-/* Wake on Lan only supported on Yukon chps with rev 1 or above */
+/* Wake on Lan only supported on Yukon chips with rev 1 or above */
static int wol_supported(const struct skge_hw *hw)
{
return !((hw->chip_id == CHIP_ID_GENESIS ||
@@ -169,8 +170,8 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
return 0;
}
-/* Determine supported/adverised modes based on hardware.
- * Note: ethtoool ADVERTISED_xxx == SUPPORTED_xxx
+/* Determine supported/advertised modes based on hardware.
+ * Note: ethtool ADVERTISED_xxx == SUPPORTED_xxx
*/
static u32 skge_supported_modes(const struct skge_hw *hw)
{
@@ -531,13 +532,13 @@ static inline u32 hwkhz(const struct skge_hw *hw)
return 78215; /* or: 78.125 MHz */
}
-/* Chip hz to microseconds */
+/* Chip HZ to microseconds */
static inline u32 skge_clk2usec(const struct skge_hw *hw, u32 ticks)
{
return (ticks * 1000) / hwkhz(hw);
}
-/* Microseconds to chip hz */
+/* Microseconds to chip HZ */
static inline u32 skge_usecs2clk(const struct skge_hw *hw, u32 usec)
{
return hwkhz(hw) * usec / 1000;
@@ -883,32 +884,37 @@ static void skge_link_down(struct skge_port *skge)
printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name);
}
-static u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg)
+static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val)
{
int i;
- u16 v;
xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
- v = xm_read16(hw, port, XM_PHY_DATA);
+ xm_read16(hw, port, XM_PHY_DATA);
/* Need to wait for external PHY */
for (i = 0; i < PHY_RETRIES; i++) {
udelay(1);
- if (xm_read16(hw, port, XM_MMU_CMD)
- & XM_MMU_PHY_RDY)
+ if (xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_RDY)
goto ready;
}
- printk(KERN_WARNING PFX "%s: phy read timed out\n",
- hw->dev[port]->name);
- return 0;
+ return -ETIMEDOUT;
ready:
- v = xm_read16(hw, port, XM_PHY_DATA);
+ *val = xm_read16(hw, port, XM_PHY_DATA);
+ return 0;
+}
+
+static u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg)
+{
+ u16 v = 0;
+ if (__xm_phy_read(hw, port, reg, &v))
+ printk(KERN_WARNING PFX "%s: phy read timed out\n",
+ hw->dev[port]->name);
return v;
}
-static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
+static int xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
{
int i;
@@ -918,19 +924,11 @@ static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
goto ready;
udelay(1);
}
- printk(KERN_WARNING PFX "%s: phy write failed to come ready\n",
- hw->dev[port]->name);
-
+ return -EIO;
ready:
xm_write16(hw, port, XM_PHY_DATA, val);
- for (i = 0; i < PHY_RETRIES; i++) {
- udelay(1);
- if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
- return;
- }
- printk(KERN_WARNING PFX "%s: phy write timed out\n",
- hw->dev[port]->name);
+ return 0;
}
static void genesis_init(struct skge_hw *hw)
@@ -1165,7 +1163,7 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo)
xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, ext);
xm_phy_write(hw, port, PHY_BCOM_CTRL, ctl);
- /* Use link status change interrrupt */
+ /* Use link status change interrupt */
xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
bcom_check_link(hw, port);
@@ -1205,7 +1203,7 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
skge_write32(hw, B2_GP_IO, r);
skge_read32(hw, B2_GP_IO);
- /* Enable GMII interfac */
+ /* Enable GMII interface */
xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
bcom_phy_init(skge, jumbo);
@@ -1256,7 +1254,7 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
* that jumbo frames larger than 8192 bytes will be
* truncated. Disabling all bad frame filtering causes
* the RX FIFO to operate in streaming mode, in which
- * case the XMAC will start transfering frames out of the
+ * case the XMAC will start transferring frames out of the
* RX FIFO as soon as the FIFO threshold is reached.
*/
xm_write32(hw, port, XM_MODE, XM_DEF_MODE);
@@ -1323,7 +1321,7 @@ static void genesis_stop(struct skge_port *skge)
port == 0 ? PA_CLR_TO_TX1 : PA_CLR_TO_TX2);
/*
- * If the transfer stucks at the MAC the STOP command will not
+ * If the transfer sticks at the MAC the STOP command will not
* terminate if we don't flush the XMAC's transmit FIFO !
*/
xm_write32(hw, port, XM_MODE,
@@ -1400,42 +1398,6 @@ static void genesis_mac_intr(struct skge_hw *hw, int port)
}
}
-static void gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
-{
- int i;
-
- gma_write16(hw, port, GM_SMI_DATA, val);
- gma_write16(hw, port, GM_SMI_CTRL,
- GM_SMI_CT_PHY_AD(hw->phy_addr) | GM_SMI_CT_REG_AD(reg));
- for (i = 0; i < PHY_RETRIES; i++) {
- udelay(1);
-
- if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY))
- break;
- }
-}
-
-static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg)
-{
- int i;
-
- gma_write16(hw, port, GM_SMI_CTRL,
- GM_SMI_CT_PHY_AD(hw->phy_addr)
- | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD);
-
- for (i = 0; i < PHY_RETRIES; i++) {
- udelay(1);
- if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL)
- goto ready;
- }
-
- printk(KERN_WARNING PFX "%s: phy read timeout\n",
- hw->dev[port]->name);
- return 0;
- ready:
- return gma_read16(hw, port, GM_SMI_DATA);
-}
-
static void genesis_link_up(struct skge_port *skge)
{
struct skge_hw *hw = skge->hw;
@@ -1549,7 +1511,55 @@ static inline void bcom_phy_intr(struct skge_port *skge)
}
-/* Marvell Phy Initailization */
+static int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
+{
+ int i;
+
+ gma_write16(hw, port, GM_SMI_DATA, val);
+ gma_write16(hw, port, GM_SMI_CTRL,
+ GM_SMI_CT_PHY_AD(hw->phy_addr) | GM_SMI_CT_REG_AD(reg));
+ for (i = 0; i < PHY_RETRIES; i++) {
+ udelay(1);
+
+ if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY))
+ return 0;
+ }
+
+ printk(KERN_WARNING PFX "%s: phy write timeout\n",
+ hw->dev[port]->name);
+ return -EIO;
+}
+
+static int __gm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val)
+{
+ int i;
+
+ gma_write16(hw, port, GM_SMI_CTRL,
+ GM_SMI_CT_PHY_AD(hw->phy_addr)
+ | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD);
+
+ for (i = 0; i < PHY_RETRIES; i++) {
+ udelay(1);
+ if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL)
+ goto ready;
+ }
+
+ return -ETIMEDOUT;
+ ready:
+ *val = gma_read16(hw, port, GM_SMI_DATA);
+ return 0;
+}
+
+static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg)
+{
+ u16 v = 0;
+ if (__gm_phy_read(hw, port, reg, &v))
+ printk(KERN_WARNING PFX "%s: phy read timeout\n",
+ hw->dev[port]->name);
+ return v;
+}
+
+/* Marvell Phy Initialization */
static void yukon_init(struct skge_hw *hw, int port)
{
struct skge_port *skge = netdev_priv(hw->dev[port]);
@@ -1794,6 +1804,25 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
skge_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
}
+/* Go into power down mode */
+static void yukon_suspend(struct skge_hw *hw, int port)
+{
+ u16 ctrl;
+
+ ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+ ctrl |= PHY_M_PC_POL_R_DIS;
+ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+
+ ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL);
+ ctrl |= PHY_CT_RESET;
+ gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+
+ /* switch IEEE compatible power down mode on */
+ ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL);
+ ctrl |= PHY_CT_PDOWN;
+ gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+}
+
static void yukon_stop(struct skge_port *skge)
{
struct skge_hw *hw = skge->hw;
@@ -1807,14 +1836,7 @@ static void yukon_stop(struct skge_port *skge)
& ~(GM_GPCR_TX_ENA|GM_GPCR_RX_ENA));
gma_read16(hw, port, GM_GP_CTRL);
- if (hw->chip_id == CHIP_ID_YUKON_LITE &&
- hw->chip_rev >= CHIP_REV_YU_LITE_A3) {
- u32 io = skge_read32(hw, B2_GP_IO);
-
- io |= GP_DIR_9 | GP_IO_9;
- skge_write32(hw, B2_GP_IO, io);
- skge_read32(hw, B2_GP_IO);
- }
+ yukon_suspend(hw, port);
/* set GPHY Control reset */
skge_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET);
@@ -1997,6 +2019,51 @@ static void yukon_phy_intr(struct skge_port *skge)
/* XXX restart autonegotiation? */
}
+/* Basic MII support */
+static int skge_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct mii_ioctl_data *data = if_mii(ifr);
+ struct skge_port *skge = netdev_priv(dev);
+ struct skge_hw *hw = skge->hw;
+ int err = -EOPNOTSUPP;
+
+ if (!netif_running(dev))
+ return -ENODEV; /* Phy still in reset */
+
+ switch(cmd) {
+ case SIOCGMIIPHY:
+ data->phy_id = hw->phy_addr;
+
+ /* fallthru */
+ case SIOCGMIIREG: {
+ u16 val = 0;
+ spin_lock_bh(&hw->phy_lock);
+ if (hw->chip_id == CHIP_ID_GENESIS)
+ err = __xm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val);
+ else
+ err = __gm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val);
+ spin_unlock_bh(&hw->phy_lock);
+ data->val_out = val;
+ break;
+ }
+
+ case SIOCSMIIREG:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ spin_lock_bh(&hw->phy_lock);
+ if (hw->chip_id == CHIP_ID_GENESIS)
+ err = xm_phy_write(hw, skge->port, data->reg_num & 0x1f,
+ data->val_in);
+ else
+ err = gm_phy_write(hw, skge->port, data->reg_num & 0x1f,
+ data->val_in);
+ spin_unlock_bh(&hw->phy_lock);
+ break;
+ }
+ return err;
+}
+
static void skge_ramset(struct skge_hw *hw, u16 q, u32 start, size_t len)
{
u32 end;
@@ -2089,7 +2156,7 @@ static int skge_up(struct net_device *dev)
hw->intr_mask |= portirqmask[port];
skge_write32(hw, B0_IMSK, hw->intr_mask);
- /* Initialze MAC */
+ /* Initialize MAC */
spin_lock_bh(&hw->phy_lock);
if (hw->chip_id == CHIP_ID_GENESIS)
genesis_mac_init(hw, port);
@@ -2409,7 +2476,7 @@ static void yukon_set_multicast(struct net_device *dev)
reg = gma_read16(hw, port, GM_RX_CTRL);
reg |= GM_RXCR_UCF_ENA;
- if (dev->flags & IFF_PROMISC) /* promiscious */
+ if (dev->flags & IFF_PROMISC) /* promiscuous */
reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
else if (dev->flags & IFF_ALLMULTI) /* all multicast */
memset(filter, 0xff, sizeof(filter));
@@ -2560,7 +2627,7 @@ static int skge_poll(struct net_device *dev, int *budget)
unsigned int to_do = min(dev->quota, *budget);
unsigned int work_done = 0;
- for (e = ring->to_clean; work_done < to_do; e = e->next) {
+ for (e = ring->to_clean; prefetch(e->next), work_done < to_do; e = e->next) {
struct skge_rx_desc *rd = e->desc;
struct sk_buff *skb;
u32 control;
@@ -2593,11 +2660,11 @@ static int skge_poll(struct net_device *dev, int *budget)
if (work_done >= to_do)
return 1; /* not done */
- local_irq_disable();
- __netif_rx_complete(dev);
+ netif_rx_complete(dev);
hw->intr_mask |= portirqmask[skge->port];
skge_write32(hw, B0_IMSK, hw->intr_mask);
- local_irq_enable();
+ skge_read32(hw, B0_IMSK);
+
return 0;
}
@@ -2609,7 +2676,7 @@ static inline void skge_tx_intr(struct net_device *dev)
struct skge_element *e;
spin_lock(&skge->tx_lock);
- for (e = ring->to_clean; e != ring->to_use; e = e->next) {
+ for (e = ring->to_clean; prefetch(e->next), e != ring->to_use; e = e->next) {
struct skge_tx_desc *td = e->desc;
u32 control;
@@ -2732,7 +2799,7 @@ static void skge_error_irq(struct skge_hw *hw)
}
/*
- * Interrrupt from PHY are handled in tasklet (soft irq)
+ * Interrupt from PHY are handled in tasklet (soft irq)
* because accessing phy registers requires spin wait which might
* cause excess interrupt latency.
*/
@@ -2762,6 +2829,14 @@ static void skge_extirq(unsigned long data)
local_irq_enable();
}
+static inline void skge_wakeup(struct net_device *dev)
+{
+ struct skge_port *skge = netdev_priv(dev);
+
+ prefetch(skge->rx_ring.to_clean);
+ netif_rx_schedule(dev);
+}
+
static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
{
struct skge_hw *hw = dev_id;
@@ -2773,12 +2848,12 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
status &= hw->intr_mask;
if (status & IS_R1_F) {
hw->intr_mask &= ~IS_R1_F;
- netif_rx_schedule(hw->dev[0]);
+ skge_wakeup(hw->dev[0]);
}
if (status & IS_R2_F) {
hw->intr_mask &= ~IS_R2_F;
- netif_rx_schedule(hw->dev[1]);
+ skge_wakeup(hw->dev[1]);
}
if (status & IS_XA1_F)
@@ -2893,6 +2968,7 @@ static const char *skge_board_name(const struct skge_hw *hw)
*/
static int skge_reset(struct skge_hw *hw)
{
+ u32 reg;
u16 ctst;
u8 t8, mac_cfg, pmd_type, phy_type;
int i;
@@ -2971,6 +3047,7 @@ static int skge_reset(struct skge_hw *hw)
/* switch power to VCC (WA for VAUX problem) */
skge_write8(hw, B0_POWER_CTRL,
PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
+
/* avoid boards with stuck Hardware error bits */
if ((skge_read32(hw, B0_ISRC) & IS_HW_ERR) &&
(skge_read32(hw, B0_HWE_ISRC) & IS_IRQ_SENSOR)) {
@@ -2978,6 +3055,14 @@ static int skge_reset(struct skge_hw *hw)
hw->intr_mask &= ~IS_HW_ERR;
}
+ /* Clear PHY COMA */
+ skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+ pci_read_config_dword(hw->pdev, PCI_DEV_REG1, &reg);
+ reg &= ~PCI_PHY_COMA;
+ pci_write_config_dword(hw->pdev, PCI_DEV_REG1, reg);
+ skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+
for (i = 0; i < hw->ports; i++) {
skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
@@ -3048,6 +3133,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
SET_NETDEV_DEV(dev, &hw->pdev->dev);
dev->open = skge_up;
dev->stop = skge_down;
+ dev->do_ioctl = skge_ioctl;
dev->hard_start_xmit = skge_xmit_frame;
dev->get_stats = skge_get_stats;
if (hw->chip_id == CHIP_ID_GENESIS)
@@ -3147,7 +3233,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
}
#ifdef __BIG_ENDIAN
- /* byte swap decriptors in hardware */
+ /* byte swap descriptors in hardware */
{
u32 reg;
@@ -3158,14 +3244,13 @@ static int __devinit skge_probe(struct pci_dev *pdev,
#endif
err = -ENOMEM;
- hw = kmalloc(sizeof(*hw), GFP_KERNEL);
+ hw = kzalloc(sizeof(*hw), GFP_KERNEL);
if (!hw) {
printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n",
pci_name(pdev));
goto err_out_free_regions;
}
- memset(hw, 0, sizeof(*hw));
hw->pdev = pdev;
spin_lock_init(&hw->phy_lock);
tasklet_init(&hw->ext_tasklet, skge_extirq, (unsigned long) hw);
@@ -3188,7 +3273,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
if (err)
goto err_out_free_irq;
- printk(KERN_INFO PFX "addr 0x%lx irq %d chip %s rev %d\n",
+ printk(KERN_INFO PFX DRV_VERSION " addr 0x%lx irq %d chip %s rev %d\n",
pci_resource_start(pdev, 0), pdev->irq,
skge_board_name(hw), hw->chip_rev);
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index 72c175b87a5..ee123c15f54 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -6,6 +6,8 @@
/* PCI config registers */
#define PCI_DEV_REG1 0x40
+#define PCI_PHY_COMA 0x8000000
+#define PCI_VIO 0x2000000
#define PCI_DEV_REG2 0x44
#define PCI_REV_DESC 0x4
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 38b2b0a3ce9..d167deda9a5 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -147,7 +147,6 @@ TODO: - fix forced speed/duplexing code (broken a long time ago, when
#define DRV_RELDATE "October 3, 2005"
#include <linux/config.h>
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index a368d08e7d1..82c6b757d30 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -61,7 +61,6 @@
#include <linux/timer.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/version.h>
#include <linux/string.h>
#include <linux/wait.h>
#include <asm/io.h>
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 6afc6e5dee9..340ab4ee4b6 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -4535,9 +4535,8 @@ static int proc_status_open( struct inode *inode, struct file *file ) {
StatusRid status_rid;
int i;
- if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+ if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
- memset(file->private_data, 0, sizeof(struct proc_data));
data = (struct proc_data *)file->private_data;
if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
kfree (file->private_data);
@@ -4615,9 +4614,8 @@ static int proc_stats_rid_open( struct inode *inode,
int i, j;
u32 *vals = stats.vals;
- if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+ if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
- memset(file->private_data, 0, sizeof(struct proc_data));
data = (struct proc_data *)file->private_data;
if ((data->rbuffer = kmalloc( 4096, GFP_KERNEL )) == NULL) {
kfree (file->private_data);
@@ -4881,20 +4879,18 @@ static int proc_config_open( struct inode *inode, struct file *file ) {
struct airo_info *ai = dev->priv;
int i;
- if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+ if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
- memset(file->private_data, 0, sizeof(struct proc_data));
data = (struct proc_data *)file->private_data;
if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
kfree (file->private_data);
return -ENOMEM;
}
- if ((data->wbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) {
+ if ((data->wbuffer = kzalloc( 2048, GFP_KERNEL )) == NULL) {
kfree (data->rbuffer);
kfree (file->private_data);
return -ENOMEM;
}
- memset( data->wbuffer, 0, 2048 );
data->maxwritelen = 2048;
data->on_close = proc_config_on_close;
@@ -5155,24 +5151,21 @@ static int proc_wepkey_open( struct inode *inode, struct file *file ) {
int j=0;
int rc;
- if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+ if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
- memset(file->private_data, 0, sizeof(struct proc_data));
memset(&wkr, 0, sizeof(wkr));
data = (struct proc_data *)file->private_data;
- if ((data->rbuffer = kmalloc( 180, GFP_KERNEL )) == NULL) {
+ if ((data->rbuffer = kzalloc( 180, GFP_KERNEL )) == NULL) {
kfree (file->private_data);
return -ENOMEM;
}
- memset(data->rbuffer, 0, 180);
data->writelen = 0;
data->maxwritelen = 80;
- if ((data->wbuffer = kmalloc( 80, GFP_KERNEL )) == NULL) {
+ if ((data->wbuffer = kzalloc( 80, GFP_KERNEL )) == NULL) {
kfree (data->rbuffer);
kfree (file->private_data);
return -ENOMEM;
}
- memset( data->wbuffer, 0, 80 );
data->on_close = proc_wepkey_on_close;
ptr = data->rbuffer;
@@ -5203,9 +5196,8 @@ static int proc_SSID_open( struct inode *inode, struct file *file ) {
char *ptr;
SsidRid SSID_rid;
- if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+ if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
- memset(file->private_data, 0, sizeof(struct proc_data));
data = (struct proc_data *)file->private_data;
if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
kfree (file->private_data);
@@ -5213,12 +5205,11 @@ static int proc_SSID_open( struct inode *inode, struct file *file ) {
}
data->writelen = 0;
data->maxwritelen = 33*3;
- if ((data->wbuffer = kmalloc( 33*3, GFP_KERNEL )) == NULL) {
+ if ((data->wbuffer = kzalloc( 33*3, GFP_KERNEL )) == NULL) {
kfree (data->rbuffer);
kfree (file->private_data);
return -ENOMEM;
}
- memset( data->wbuffer, 0, 33*3 );
data->on_close = proc_SSID_on_close;
readSsidRid(ai, &SSID_rid);
@@ -5247,9 +5238,8 @@ static int proc_APList_open( struct inode *inode, struct file *file ) {
char *ptr;
APListRid APList_rid;
- if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+ if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
- memset(file->private_data, 0, sizeof(struct proc_data));
data = (struct proc_data *)file->private_data;
if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) {
kfree (file->private_data);
@@ -5257,12 +5247,11 @@ static int proc_APList_open( struct inode *inode, struct file *file ) {
}
data->writelen = 0;
data->maxwritelen = 4*6*3;
- if ((data->wbuffer = kmalloc( data->maxwritelen, GFP_KERNEL )) == NULL) {
+ if ((data->wbuffer = kzalloc( data->maxwritelen, GFP_KERNEL )) == NULL) {
kfree (data->rbuffer);
kfree (file->private_data);
return -ENOMEM;
}
- memset( data->wbuffer, 0, data->maxwritelen );
data->on_close = proc_APList_on_close;
readAPListRid(ai, &APList_rid);
@@ -5297,9 +5286,8 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
/* If doLoseSync is not 1, we won't do a Lose Sync */
int doLoseSync = -1;
- if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+ if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
- memset(file->private_data, 0, sizeof(struct proc_data));
data = (struct proc_data *)file->private_data;
if ((data->rbuffer = kmalloc( 1024, GFP_KERNEL )) == NULL) {
kfree (file->private_data);
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index 96ed8da8661..e328547599d 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -170,12 +170,11 @@ static dev_link_t *airo_attach(void)
DEBUG(0, "airo_attach()\n");
/* Initialize the dev_link_t structure */
- link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+ link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL);
if (!link) {
printk(KERN_ERR "airo_cs: no memory for new device\n");
return NULL;
}
- memset(link, 0, sizeof(struct dev_link_t));
/* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
@@ -194,13 +193,12 @@ static dev_link_t *airo_attach(void)
link->conf.IntType = INT_MEMORY_AND_IO;
/* Allocate space for private device-specific data */
- local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+ local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local) {
printk(KERN_ERR "airo_cs: no memory for new device\n");
kfree (link);
return NULL;
}
- memset(local, 0, sizeof(local_info_t));
link->priv = local;
/* Register with Card Services */
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 1fbe027d26b..a3e23527fe7 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -2217,7 +2217,7 @@ static int atmel_get_range(struct net_device *dev,
int k,i,j;
dwrq->length = sizeof(struct iw_range);
- memset(range, 0, sizeof(range));
+ memset(range, 0, sizeof(struct iw_range));
range->min_nwid = 0x0000;
range->max_nwid = 0x0000;
range->num_channels = 0;
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index 195cb36619e..1bd13146c64 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -180,12 +180,11 @@ static dev_link_t *atmel_attach(void)
DEBUG(0, "atmel_attach()\n");
/* Initialize the dev_link_t structure */
- link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+ link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL);
if (!link) {
printk(KERN_ERR "atmel_cs: no memory for new device\n");
return NULL;
}
- memset(link, 0, sizeof(struct dev_link_t));
/* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
@@ -204,13 +203,12 @@ static dev_link_t *atmel_attach(void)
link->conf.IntType = INT_MEMORY_AND_IO;
/* Allocate space for private device-specific data */
- local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+ local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local) {
printk(KERN_ERR "atmel_cs: no memory for new device\n");
kfree (link);
return NULL;
}
- memset(local, 0, sizeof(local_info_t));
link->priv = local;
/* Register with Card Services */
diff --git a/drivers/net/wireless/hostap/hostap.c b/drivers/net/wireless/hostap/hostap.c
index 6a96cd9f268..3d2ea61033b 100644
--- a/drivers/net/wireless/hostap/hostap.c
+++ b/drivers/net/wireless/hostap/hostap.c
@@ -13,7 +13,6 @@
*/
#include <linux/config.h>
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index 59fc1557239..abfae7fedeb 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -31,7 +31,6 @@
#include <linux/config.h>
-#include <linux/version.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index da0c80fb941..2e85bdced2d 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -5,7 +5,6 @@
* Andy Warner <andyw@pobox.com> */
#include <linux/config.h>
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/if.h>
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index 78d67b408b2..94fe2449f09 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -8,7 +8,6 @@
#include <linux/config.h>
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/if.h>
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index ad7f8cd76db..a2e6214169e 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -167,17 +167,16 @@ that only one external action is invoked at a time.
#include "ipw2100.h"
-#define IPW2100_VERSION "1.1.0"
+#define IPW2100_VERSION "1.1.3"
#define DRV_NAME "ipw2100"
#define DRV_VERSION IPW2100_VERSION
#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver"
-#define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation"
-
+#define DRV_COPYRIGHT "Copyright(c) 2003-2005 Intel Corporation"
/* Debugging stuff */
#ifdef CONFIG_IPW_DEBUG
-#define CONFIG_IPW2100_RX_DEBUG /* Reception debugging */
+#define CONFIG_IPW2100_RX_DEBUG /* Reception debugging */
#endif
MODULE_DESCRIPTION(DRV_DESCRIPTION);
@@ -220,18 +219,18 @@ do { \
} while (0)
#else
#define IPW_DEBUG(level, message...) do {} while (0)
-#endif /* CONFIG_IPW_DEBUG */
+#endif /* CONFIG_IPW_DEBUG */
#ifdef CONFIG_IPW_DEBUG
static const char *command_types[] = {
"undefined",
- "unused", /* HOST_ATTENTION */
+ "unused", /* HOST_ATTENTION */
"HOST_COMPLETE",
- "unused", /* SLEEP */
- "unused", /* HOST_POWER_DOWN */
+ "unused", /* SLEEP */
+ "unused", /* HOST_POWER_DOWN */
"unused",
"SYSTEM_CONFIG",
- "unused", /* SET_IMR */
+ "unused", /* SET_IMR */
"SSID",
"MANDATORY_BSSID",
"AUTHENTICATION_TYPE",
@@ -277,17 +276,16 @@ static const char *command_types[] = {
"GROUP_ORDINALS",
"SHORT_RETRY_LIMIT",
"LONG_RETRY_LIMIT",
- "unused", /* SAVE_CALIBRATION */
- "unused", /* RESTORE_CALIBRATION */
+ "unused", /* SAVE_CALIBRATION */
+ "unused", /* RESTORE_CALIBRATION */
"undefined",
"undefined",
"undefined",
"HOST_PRE_POWER_DOWN",
- "unused", /* HOST_INTERRUPT_COALESCING */
+ "unused", /* HOST_INTERRUPT_COALESCING */
"undefined",
"CARD_DISABLE_PHY_OFF",
- "MSDU_TX_RATES"
- "undefined",
+ "MSDU_TX_RATES" "undefined",
"undefined",
"SET_STATION_STAT_BITS",
"CLEAR_STATIONS_STAT_BITS",
@@ -298,7 +296,6 @@ static const char *command_types[] = {
};
#endif
-
/* Pre-decl until we get the code solid and then we can clean it up */
static void ipw2100_tx_send_commands(struct ipw2100_priv *priv);
static void ipw2100_tx_send_data(struct ipw2100_priv *priv);
@@ -321,11 +318,10 @@ static void ipw2100_release_firmware(struct ipw2100_priv *priv,
static int ipw2100_ucode_download(struct ipw2100_priv *priv,
struct ipw2100_fw *fw);
static void ipw2100_wx_event_work(struct ipw2100_priv *priv);
-static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev);
+static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev);
static struct iw_handler_def ipw2100_wx_handler_def;
-
-static inline void read_register(struct net_device *dev, u32 reg, u32 *val)
+static inline void read_register(struct net_device *dev, u32 reg, u32 * val)
{
*val = readl((void __iomem *)(dev->base_addr + reg));
IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val);
@@ -337,13 +333,14 @@ static inline void write_register(struct net_device *dev, u32 reg, u32 val)
IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val);
}
-static inline void read_register_word(struct net_device *dev, u32 reg, u16 *val)
+static inline void read_register_word(struct net_device *dev, u32 reg,
+ u16 * val)
{
*val = readw((void __iomem *)(dev->base_addr + reg));
IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val);
}
-static inline void read_register_byte(struct net_device *dev, u32 reg, u8 *val)
+static inline void read_register_byte(struct net_device *dev, u32 reg, u8 * val)
{
*val = readb((void __iomem *)(dev->base_addr + reg));
IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val);
@@ -355,14 +352,13 @@ static inline void write_register_word(struct net_device *dev, u32 reg, u16 val)
IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val);
}
-
static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val)
{
writeb(val, (void __iomem *)(dev->base_addr + reg));
IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val);
}
-static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 *val)
+static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 * val)
{
write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
addr & IPW_REG_INDIRECT_ADDR_MASK);
@@ -376,7 +372,7 @@ static inline void write_nic_dword(struct net_device *dev, u32 addr, u32 val)
write_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
}
-static inline void read_nic_word(struct net_device *dev, u32 addr, u16 *val)
+static inline void read_nic_word(struct net_device *dev, u32 addr, u16 * val)
{
write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
addr & IPW_REG_INDIRECT_ADDR_MASK);
@@ -390,7 +386,7 @@ static inline void write_nic_word(struct net_device *dev, u32 addr, u16 val)
write_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
}
-static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 *val)
+static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 * val)
{
write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
addr & IPW_REG_INDIRECT_ADDR_MASK);
@@ -416,7 +412,7 @@ static inline void write_nic_dword_auto_inc(struct net_device *dev, u32 val)
}
static inline void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
- const u8 *buf)
+ const u8 * buf)
{
u32 aligned_addr;
u32 aligned_len;
@@ -431,32 +427,30 @@ static inline void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
aligned_addr);
for (i = dif_len; i < 4; i++, buf++)
- write_register_byte(
- dev, IPW_REG_INDIRECT_ACCESS_DATA + i,
- *buf);
+ write_register_byte(dev,
+ IPW_REG_INDIRECT_ACCESS_DATA + i,
+ *buf);
len -= dif_len;
aligned_addr += 4;
}
/* read DWs through autoincrement registers */
- write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS,
- aligned_addr);
+ write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
aligned_len = len & (~0x3);
for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
- write_register(
- dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *)buf);
+ write_register(dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *) buf);
/* copy the last nibble */
dif_len = len - aligned_len;
write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
for (i = 0; i < dif_len; i++, buf++)
- write_register_byte(
- dev, IPW_REG_INDIRECT_ACCESS_DATA + i, *buf);
+ write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i,
+ *buf);
}
static inline void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
- u8 *buf)
+ u8 * buf)
{
u32 aligned_addr;
u32 aligned_len;
@@ -471,39 +465,38 @@ static inline void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
aligned_addr);
for (i = dif_len; i < 4; i++, buf++)
- read_register_byte(
- dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf);
+ read_register_byte(dev,
+ IPW_REG_INDIRECT_ACCESS_DATA + i,
+ buf);
len -= dif_len;
aligned_addr += 4;
}
/* read DWs through autoincrement registers */
- write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS,
- aligned_addr);
+ write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
aligned_len = len & (~0x3);
for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
- read_register(dev, IPW_REG_AUTOINCREMENT_DATA,
- (u32 *)buf);
+ read_register(dev, IPW_REG_AUTOINCREMENT_DATA, (u32 *) buf);
/* copy the last nibble */
dif_len = len - aligned_len;
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- aligned_addr);
+ write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
for (i = 0; i < dif_len; i++, buf++)
- read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA +
- i, buf);
+ read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf);
}
static inline int ipw2100_hw_is_adapter_in_system(struct net_device *dev)
{
return (dev->base_addr &&
- (readl((void __iomem *)(dev->base_addr + IPW_REG_DOA_DEBUG_AREA_START))
+ (readl
+ ((void __iomem *)(dev->base_addr +
+ IPW_REG_DOA_DEBUG_AREA_START))
== IPW_DATA_DOA_DEBUG_VALUE));
}
static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,
- void *val, u32 *len)
+ void *val, u32 * len)
{
struct ipw2100_ordinals *ordinals = &priv->ordinals;
u32 addr;
@@ -529,8 +522,8 @@ static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,
return -EINVAL;
}
- read_nic_dword(priv->net_dev, ordinals->table1_addr + (ord << 2),
- &addr);
+ read_nic_dword(priv->net_dev,
+ ordinals->table1_addr + (ord << 2), &addr);
read_nic_dword(priv->net_dev, addr, val);
*len = IPW_ORD_TAB_1_ENTRY_SIZE;
@@ -543,8 +536,8 @@ static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,
ord -= IPW_START_ORD_TAB_2;
/* get the address of statistic */
- read_nic_dword(priv->net_dev, ordinals->table2_addr + (ord << 3),
- &addr);
+ read_nic_dword(priv->net_dev,
+ ordinals->table2_addr + (ord << 3), &addr);
/* get the second DW of statistics ;
* two 16-bit words - first is length, second is count */
@@ -553,10 +546,10 @@ static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,
&field_info);
/* get each entry length */
- field_len = *((u16 *)&field_info);
+ field_len = *((u16 *) & field_info);
/* get number of entries */
- field_count = *(((u16 *)&field_info) + 1);
+ field_count = *(((u16 *) & field_info) + 1);
/* abort if no enought memory */
total_length = field_len * field_count;
@@ -581,8 +574,8 @@ static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,
return -EINVAL;
}
-static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 *val,
- u32 *len)
+static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 * val,
+ u32 * len)
{
struct ipw2100_ordinals *ordinals = &priv->ordinals;
u32 addr;
@@ -594,8 +587,8 @@ static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 *val,
return -EINVAL;
}
- read_nic_dword(priv->net_dev, ordinals->table1_addr + (ord << 2),
- &addr);
+ read_nic_dword(priv->net_dev,
+ ordinals->table1_addr + (ord << 2), &addr);
write_nic_dword(priv->net_dev, addr, *val);
@@ -612,7 +605,7 @@ static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 *val,
}
static char *snprint_line(char *buf, size_t count,
- const u8 *data, u32 len, u32 ofs)
+ const u8 * data, u32 len, u32 ofs)
{
int out, i, j, l;
char c;
@@ -646,7 +639,7 @@ static char *snprint_line(char *buf, size_t count,
return buf;
}
-static void printk_buf(int level, const u8 *data, u32 len)
+static void printk_buf(int level, const u8 * data, u32 len)
{
char line[81];
u32 ofs = 0;
@@ -662,8 +655,6 @@ static void printk_buf(int level, const u8 *data, u32 len)
}
}
-
-
#define MAX_RESET_BACKOFF 10
static inline void schedule_reset(struct ipw2100_priv *priv)
@@ -703,7 +694,7 @@ static inline void schedule_reset(struct ipw2100_priv *priv)
#define HOST_COMPLETE_TIMEOUT (2 * HZ)
static int ipw2100_hw_send_command(struct ipw2100_priv *priv,
- struct host_command * cmd)
+ struct host_command *cmd)
{
struct list_head *element;
struct ipw2100_tx_packet *packet;
@@ -713,25 +704,28 @@ static int ipw2100_hw_send_command(struct ipw2100_priv *priv,
IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n",
command_types[cmd->host_command], cmd->host_command,
cmd->host_command_length);
- printk_buf(IPW_DL_HC, (u8*)cmd->host_command_parameters,
+ printk_buf(IPW_DL_HC, (u8 *) cmd->host_command_parameters,
cmd->host_command_length);
spin_lock_irqsave(&priv->low_lock, flags);
if (priv->fatal_error) {
- IPW_DEBUG_INFO("Attempt to send command while hardware in fatal error condition.\n");
+ IPW_DEBUG_INFO
+ ("Attempt to send command while hardware in fatal error condition.\n");
err = -EIO;
goto fail_unlock;
}
if (!(priv->status & STATUS_RUNNING)) {
- IPW_DEBUG_INFO("Attempt to send command while hardware is not running.\n");
+ IPW_DEBUG_INFO
+ ("Attempt to send command while hardware is not running.\n");
err = -EIO;
goto fail_unlock;
}
if (priv->status & STATUS_CMD_ACTIVE) {
- IPW_DEBUG_INFO("Attempt to send command while another command is pending.\n");
+ IPW_DEBUG_INFO
+ ("Attempt to send command while another command is pending.\n");
err = -EBUSY;
goto fail_unlock;
}
@@ -752,7 +746,8 @@ static int ipw2100_hw_send_command(struct ipw2100_priv *priv,
/* initialize the firmware command packet */
packet->info.c_struct.cmd->host_command_reg = cmd->host_command;
packet->info.c_struct.cmd->host_command_reg1 = cmd->host_command1;
- packet->info.c_struct.cmd->host_command_len_reg = cmd->host_command_length;
+ packet->info.c_struct.cmd->host_command_len_reg =
+ cmd->host_command_length;
packet->info.c_struct.cmd->sequence = cmd->host_command_sequence;
memcpy(packet->info.c_struct.cmd->host_command_params_reg,
@@ -776,13 +771,15 @@ static int ipw2100_hw_send_command(struct ipw2100_priv *priv,
* then there is a problem.
*/
- err = wait_event_interruptible_timeout(
- priv->wait_command_queue, !(priv->status & STATUS_CMD_ACTIVE),
- HOST_COMPLETE_TIMEOUT);
+ err =
+ wait_event_interruptible_timeout(priv->wait_command_queue,
+ !(priv->
+ status & STATUS_CMD_ACTIVE),
+ HOST_COMPLETE_TIMEOUT);
if (err == 0) {
IPW_DEBUG_INFO("Command completion failed out after %dms.\n",
- HOST_COMPLETE_TIMEOUT / (HZ / 100));
+ 1000 * (HOST_COMPLETE_TIMEOUT / HZ));
priv->fatal_error = IPW2100_ERR_MSG_TIMEOUT;
priv->status &= ~STATUS_CMD_ACTIVE;
schedule_reset(priv);
@@ -804,13 +801,12 @@ static int ipw2100_hw_send_command(struct ipw2100_priv *priv,
return 0;
- fail_unlock:
+ fail_unlock:
spin_unlock_irqrestore(&priv->low_lock, flags);
return err;
}
-
/*
* Verify the values and data access of the hardware
* No locks needed or used. No functions called.
@@ -825,8 +821,7 @@ static int ipw2100_verify(struct ipw2100_priv *priv)
/* Domain 0 check - all values should be DOA_DEBUG */
for (address = IPW_REG_DOA_DEBUG_AREA_START;
- address < IPW_REG_DOA_DEBUG_AREA_END;
- address += sizeof(u32)) {
+ address < IPW_REG_DOA_DEBUG_AREA_END; address += sizeof(u32)) {
read_register(priv->net_dev, address, &data1);
if (data1 != IPW_DATA_DOA_DEBUG_VALUE)
return -EIO;
@@ -898,7 +893,6 @@ static int ipw2100_wait_for_card_state(struct ipw2100_priv *priv, int state)
return -EIO;
}
-
/*********************************************************************
Procedure : sw_reset_and_clock
Purpose : Asserts s/w reset, asserts clock initialization
@@ -975,17 +969,16 @@ static int ipw2100_download_firmware(struct ipw2100_priv *priv)
if (priv->fatal_error) {
IPW_DEBUG_ERROR("%s: ipw2100_download_firmware called after "
- "fatal error %d. Interface must be brought down.\n",
- priv->net_dev->name, priv->fatal_error);
+ "fatal error %d. Interface must be brought down.\n",
+ priv->net_dev->name, priv->fatal_error);
return -EINVAL;
}
-
#ifdef CONFIG_PM
if (!ipw2100_firmware.version) {
err = ipw2100_get_firmware(priv, &ipw2100_firmware);
if (err) {
IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
- priv->net_dev->name, err);
+ priv->net_dev->name, err);
priv->fatal_error = IPW2100_ERR_FW_LOAD;
goto fail;
}
@@ -994,7 +987,7 @@ static int ipw2100_download_firmware(struct ipw2100_priv *priv)
err = ipw2100_get_firmware(priv, &ipw2100_firmware);
if (err) {
IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
- priv->net_dev->name, err);
+ priv->net_dev->name, err);
priv->fatal_error = IPW2100_ERR_FW_LOAD;
goto fail;
}
@@ -1005,21 +998,20 @@ static int ipw2100_download_firmware(struct ipw2100_priv *priv)
err = sw_reset_and_clock(priv);
if (err) {
IPW_DEBUG_ERROR("%s: sw_reset_and_clock failed: %d\n",
- priv->net_dev->name, err);
+ priv->net_dev->name, err);
goto fail;
}
err = ipw2100_verify(priv);
if (err) {
IPW_DEBUG_ERROR("%s: ipw2100_verify failed: %d\n",
- priv->net_dev->name, err);
+ priv->net_dev->name, err);
goto fail;
}
/* Hold ARC */
write_nic_dword(priv->net_dev,
- IPW_INTERNAL_REGISTER_HALT_AND_RESET,
- 0x80000000);
+ IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x80000000);
/* allow ARC to run */
write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
@@ -1034,13 +1026,13 @@ static int ipw2100_download_firmware(struct ipw2100_priv *priv)
/* release ARC */
write_nic_dword(priv->net_dev,
- IPW_INTERNAL_REGISTER_HALT_AND_RESET,
- 0x00000000);
+ IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x00000000);
/* s/w reset and clock stabilization (again!!!) */
err = sw_reset_and_clock(priv);
if (err) {
- printk(KERN_ERR DRV_NAME ": %s: sw_reset_and_clock failed: %d\n",
+ printk(KERN_ERR DRV_NAME
+ ": %s: sw_reset_and_clock failed: %d\n",
priv->net_dev->name, err);
goto fail;
}
@@ -1049,10 +1041,9 @@ static int ipw2100_download_firmware(struct ipw2100_priv *priv)
err = ipw2100_fw_download(priv, &ipw2100_firmware);
if (err) {
IPW_DEBUG_ERROR("%s: Error loading firmware: %d\n",
- priv->net_dev->name, err);
+ priv->net_dev->name, err);
goto fail;
}
-
#ifndef CONFIG_PM
/*
* When the .resume method of the driver is called, the other
@@ -1084,7 +1075,7 @@ static int ipw2100_download_firmware(struct ipw2100_priv *priv)
return 0;
- fail:
+ fail:
ipw2100_release_firmware(priv, &ipw2100_firmware);
return err;
}
@@ -1105,7 +1096,6 @@ static inline void ipw2100_disable_interrupts(struct ipw2100_priv *priv)
write_register(priv->net_dev, IPW_REG_INTA_MASK, 0x0);
}
-
static void ipw2100_initialize_ordinals(struct ipw2100_priv *priv)
{
struct ipw2100_ordinals *ord = &priv->ordinals;
@@ -1177,11 +1167,10 @@ static int ipw2100_get_hw_features(struct ipw2100_priv *priv)
* EEPROM_SRAM_DB_START_ADDRESS using ordinal in ordinal table 1
*/
len = sizeof(addr);
- if (ipw2100_get_ordinal(
- priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS,
- &addr, &len)) {
+ if (ipw2100_get_ordinal
+ (priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, &addr, &len)) {
IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
+ __LINE__);
return -EIO;
}
@@ -1194,7 +1183,7 @@ static int ipw2100_get_hw_features(struct ipw2100_priv *priv)
priv->eeprom_version = (val >> 24) & 0xFF;
IPW_DEBUG_INFO("EEPROM version: %d\n", priv->eeprom_version);
- /*
+ /*
* HW RF Kill enable is bit 0 in byte at offset 0x21 in firmware
*
* notice that the EEPROM bit is reverse polarity, i.e.
@@ -1206,8 +1195,7 @@ static int ipw2100_get_hw_features(struct ipw2100_priv *priv)
priv->hw_features |= HW_FEATURE_RFKILL;
IPW_DEBUG_INFO("HW RF Kill: %ssupported.\n",
- (priv->hw_features & HW_FEATURE_RFKILL) ?
- "" : "not ");
+ (priv->hw_features & HW_FEATURE_RFKILL) ? "" : "not ");
return 0;
}
@@ -1234,7 +1222,8 @@ static int ipw2100_start_adapter(struct ipw2100_priv *priv)
* fw & dino ucode
*/
if (ipw2100_download_firmware(priv)) {
- printk(KERN_ERR DRV_NAME ": %s: Failed to power on the adapter.\n",
+ printk(KERN_ERR DRV_NAME
+ ": %s: Failed to power on the adapter.\n",
priv->net_dev->name);
return -EIO;
}
@@ -1293,7 +1282,8 @@ static int ipw2100_start_adapter(struct ipw2100_priv *priv)
i ? "SUCCESS" : "FAILED");
if (!i) {
- printk(KERN_WARNING DRV_NAME ": %s: Firmware did not initialize.\n",
+ printk(KERN_WARNING DRV_NAME
+ ": %s: Firmware did not initialize.\n",
priv->net_dev->name);
return -EIO;
}
@@ -1326,7 +1316,6 @@ static inline void ipw2100_reset_fatalerror(struct ipw2100_priv *priv)
priv->fatal_error = 0;
}
-
/* NOTE: Our interrupt is disabled when this method is called */
static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv)
{
@@ -1350,19 +1339,19 @@ static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv)
if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
break;
- } while(i--);
+ } while (i--);
priv->status &= ~STATUS_RESET_PENDING;
if (!i) {
- IPW_DEBUG_INFO("exit - waited too long for master assert stop\n");
+ IPW_DEBUG_INFO
+ ("exit - waited too long for master assert stop\n");
return -EIO;
}
write_register(priv->net_dev, IPW_REG_RESET_REG,
IPW_AUX_HOST_RESET_REG_SW_RESET);
-
/* Reset any fatal_error conditions */
ipw2100_reset_fatalerror(priv);
@@ -1415,7 +1404,6 @@ static int ipw2100_hw_phy_off(struct ipw2100_priv *priv)
return -EIO;
}
-
static int ipw2100_enable_adapter(struct ipw2100_priv *priv)
{
struct host_command cmd = {
@@ -1445,9 +1433,8 @@ static int ipw2100_enable_adapter(struct ipw2100_priv *priv)
err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_ENABLED);
if (err) {
- IPW_DEBUG_INFO(
- "%s: card not responding to init command.\n",
- priv->net_dev->name);
+ IPW_DEBUG_INFO("%s: card not responding to init command.\n",
+ priv->net_dev->name);
goto fail_up;
}
@@ -1456,7 +1443,7 @@ static int ipw2100_enable_adapter(struct ipw2100_priv *priv)
queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2);
}
-fail_up:
+ fail_up:
up(&priv->adapter_sem);
return err;
}
@@ -1488,7 +1475,8 @@ static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv)
err = ipw2100_hw_phy_off(priv);
if (err)
- printk(KERN_WARNING DRV_NAME ": Error disabling radio %d\n", err);
+ printk(KERN_WARNING DRV_NAME
+ ": Error disabling radio %d\n", err);
/*
* If in D0-standby mode going directly to D3 may cause a
@@ -1566,7 +1554,6 @@ static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv)
return 0;
}
-
static int ipw2100_disable_adapter(struct ipw2100_priv *priv)
{
struct host_command cmd = {
@@ -1593,19 +1580,21 @@ static int ipw2100_disable_adapter(struct ipw2100_priv *priv)
err = ipw2100_hw_send_command(priv, &cmd);
if (err) {
- printk(KERN_WARNING DRV_NAME ": exit - failed to send CARD_DISABLE command\n");
+ printk(KERN_WARNING DRV_NAME
+ ": exit - failed to send CARD_DISABLE command\n");
goto fail_up;
}
err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_DISABLED);
if (err) {
- printk(KERN_WARNING DRV_NAME ": exit - card failed to change to DISABLED\n");
+ printk(KERN_WARNING DRV_NAME
+ ": exit - card failed to change to DISABLED\n");
goto fail_up;
}
IPW_DEBUG_INFO("TODO: implement scan state machine\n");
-fail_up:
+ fail_up:
up(&priv->adapter_sem);
return err;
}
@@ -1627,7 +1616,7 @@ static int ipw2100_set_scan_options(struct ipw2100_priv *priv)
if (!(priv->config & CFG_ASSOCIATE))
cmd.host_command_parameters[0] |= IPW_SCAN_NOASSOCIATE;
- if ((priv->sec.flags & SEC_ENABLED) && priv->sec.enabled)
+ if ((priv->ieee->sec.flags & SEC_ENABLED) && priv->ieee->sec.enabled)
cmd.host_command_parameters[0] |= IPW_SCAN_MIXED_CELL;
if (priv->config & CFG_PASSIVE_SCAN)
cmd.host_command_parameters[0] |= IPW_SCAN_PASSIVE;
@@ -1709,8 +1698,9 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
(priv->status & STATUS_RESET_PENDING)) {
/* Power cycle the card ... */
if (ipw2100_power_cycle_adapter(priv)) {
- printk(KERN_WARNING DRV_NAME ": %s: Could not cycle adapter.\n",
- priv->net_dev->name);
+ printk(KERN_WARNING DRV_NAME
+ ": %s: Could not cycle adapter.\n",
+ priv->net_dev->name);
rc = 1;
goto exit;
}
@@ -1719,8 +1709,9 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
/* Load the firmware, start the clocks, etc. */
if (ipw2100_start_adapter(priv)) {
- printk(KERN_ERR DRV_NAME ": %s: Failed to start the firmware.\n",
- priv->net_dev->name);
+ printk(KERN_ERR DRV_NAME
+ ": %s: Failed to start the firmware.\n",
+ priv->net_dev->name);
rc = 1;
goto exit;
}
@@ -1729,16 +1720,18 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
/* Determine capabilities of this particular HW configuration */
if (ipw2100_get_hw_features(priv)) {
- printk(KERN_ERR DRV_NAME ": %s: Failed to determine HW features.\n",
- priv->net_dev->name);
+ printk(KERN_ERR DRV_NAME
+ ": %s: Failed to determine HW features.\n",
+ priv->net_dev->name);
rc = 1;
goto exit;
}
lock = LOCK_NONE;
if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) {
- printk(KERN_ERR DRV_NAME ": %s: Failed to clear ordinal lock.\n",
- priv->net_dev->name);
+ printk(KERN_ERR DRV_NAME
+ ": %s: Failed to clear ordinal lock.\n",
+ priv->net_dev->name);
rc = 1;
goto exit;
}
@@ -1764,7 +1757,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
* HOST_COMPLETE */
if (ipw2100_adapter_setup(priv)) {
printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n",
- priv->net_dev->name);
+ priv->net_dev->name);
rc = 1;
goto exit;
}
@@ -1773,20 +1766,19 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
/* Enable the adapter - sends HOST_COMPLETE */
if (ipw2100_enable_adapter(priv)) {
printk(KERN_ERR DRV_NAME ": "
- "%s: failed in call to enable adapter.\n",
- priv->net_dev->name);
+ "%s: failed in call to enable adapter.\n",
+ priv->net_dev->name);
ipw2100_hw_stop_adapter(priv);
rc = 1;
goto exit;
}
-
/* Start a scan . . . */
ipw2100_set_scan_options(priv);
ipw2100_start_scan(priv);
}
- exit:
+ exit:
return rc;
}
@@ -1802,8 +1794,7 @@ static void ipw2100_down(struct ipw2100_priv *priv)
unsigned long flags;
union iwreq_data wrqu = {
.ap_addr = {
- .sa_family = ARPHRD_ETHER
- }
+ .sa_family = ARPHRD_ETHER}
};
int associated = priv->status & STATUS_ASSOCIATED;
@@ -1842,7 +1833,7 @@ static void ipw2100_down(struct ipw2100_priv *priv)
#ifdef ACPI_CSTATE_LIMIT_DEFINED
if (priv->config & CFG_C3_DISABLED) {
- IPW_DEBUG_INFO(DRV_NAME ": Resetting C3 transitions.\n");
+ IPW_DEBUG_INFO(": Resetting C3 transitions.\n");
acpi_set_cstate_limit(priv->cstate_limit);
priv->config &= ~CFG_C3_DISABLED;
}
@@ -1862,14 +1853,12 @@ static void ipw2100_reset_adapter(struct ipw2100_priv *priv)
unsigned long flags;
union iwreq_data wrqu = {
.ap_addr = {
- .sa_family = ARPHRD_ETHER
- }
+ .sa_family = ARPHRD_ETHER}
};
int associated = priv->status & STATUS_ASSOCIATED;
spin_lock_irqsave(&priv->low_lock, flags);
- IPW_DEBUG_INFO(DRV_NAME ": %s: Restarting adapter.\n",
- priv->net_dev->name);
+ IPW_DEBUG_INFO(": %s: Restarting adapter.\n", priv->net_dev->name);
priv->resets++;
priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
priv->status |= STATUS_SECURITY_UPDATED;
@@ -1894,7 +1883,6 @@ static void ipw2100_reset_adapter(struct ipw2100_priv *priv)
}
-
static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
{
@@ -1904,7 +1892,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
u32 txrate;
u32 chan;
char *txratename;
- u8 bssid[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
/*
* TBD: BSSID is usually 00:00:00:00:00:00 here and not
@@ -1918,16 +1906,15 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
essid, &essid_len);
if (ret) {
IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
+ __LINE__);
return;
}
len = sizeof(u32);
- ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE,
- &txrate, &len);
+ ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &txrate, &len);
if (ret) {
IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
+ __LINE__);
return;
}
@@ -1935,19 +1922,18 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &len);
if (ret) {
IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
+ __LINE__);
return;
}
len = ETH_ALEN;
- ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len);
+ ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len);
if (ret) {
IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
+ __LINE__);
return;
}
memcpy(priv->ieee->bssid, bssid, ETH_ALEN);
-
switch (txrate) {
case TX_RATE_1_MBIT:
txratename = "1Mbps";
@@ -1974,7 +1960,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
/* now we copy read ssid into dev */
if (!(priv->config & CFG_STATIC_ESSID)) {
- priv->essid_len = min((u8)essid_len, (u8)IW_ESSID_MAX_SIZE);
+ priv->essid_len = min((u8) essid_len, (u8) IW_ESSID_MAX_SIZE);
memcpy(priv->essid, essid, priv->essid_len);
}
priv->channel = chan;
@@ -1986,7 +1972,6 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
queue_delayed_work(priv->workqueue, &priv->wx_event_work, HZ / 10);
}
-
static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
int length, int batch_mode)
{
@@ -2001,8 +1986,7 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
IPW_DEBUG_HC("SSID: '%s'\n", escape_essid(essid, ssid_len));
if (ssid_len)
- memcpy((char*)cmd.host_command_parameters,
- essid, ssid_len);
+ memcpy(cmd.host_command_parameters, essid, ssid_len);
if (!batch_mode) {
err = ipw2100_disable_adapter(priv);
@@ -2014,7 +1998,7 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
* disable auto association -- so we cheat by setting a bogus SSID */
if (!ssid_len && !(priv->config & CFG_ASSOCIATE)) {
int i;
- u8 *bogus = (u8*)cmd.host_command_parameters;
+ u8 *bogus = (u8 *) cmd.host_command_parameters;
for (i = 0; i < IW_ESSID_MAX_SIZE; i++)
bogus[i] = 0x18 + i;
cmd.host_command_length = IW_ESSID_MAX_SIZE;
@@ -2025,8 +2009,7 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
err = ipw2100_hw_send_command(priv, &cmd);
if (!err) {
- memset(priv->essid + ssid_len, 0,
- IW_ESSID_MAX_SIZE - ssid_len);
+ memset(priv->essid + ssid_len, 0, IW_ESSID_MAX_SIZE - ssid_len);
memcpy(priv->essid, essid, ssid_len);
priv->essid_len = ssid_len;
}
@@ -2071,14 +2054,14 @@ static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
{
IPW_DEBUG_INFO("%s: RF Kill state changed to radio OFF.\n",
- priv->net_dev->name);
+ priv->net_dev->name);
/* RF_KILL is now enabled (else we wouldn't be here) */
priv->status |= STATUS_RF_KILL_HW;
#ifdef ACPI_CSTATE_LIMIT_DEFINED
if (priv->config & CFG_C3_DISABLED) {
- IPW_DEBUG_INFO(DRV_NAME ": Resetting C3 transitions.\n");
+ IPW_DEBUG_INFO(": Resetting C3 transitions.\n");
acpi_set_cstate_limit(priv->cstate_limit);
priv->config &= ~CFG_C3_DISABLED;
}
@@ -2102,16 +2085,16 @@ static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
#define IPW2100_HANDLER(v, f) { v, f, # v }
struct ipw2100_status_indicator {
int status;
- void (*cb)(struct ipw2100_priv *priv, u32 status);
+ void (*cb) (struct ipw2100_priv * priv, u32 status);
char *name;
};
#else
#define IPW2100_HANDLER(v, f) { v, f }
struct ipw2100_status_indicator {
int status;
- void (*cb)(struct ipw2100_priv *priv, u32 status);
+ void (*cb) (struct ipw2100_priv * priv, u32 status);
};
-#endif /* CONFIG_IPW_DEBUG */
+#endif /* CONFIG_IPW_DEBUG */
static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status)
{
@@ -2135,7 +2118,6 @@ static const struct ipw2100_status_indicator status_handlers[] = {
IPW2100_HANDLER(-1, NULL)
};
-
static void isr_status_change(struct ipw2100_priv *priv, int status)
{
int i;
@@ -2153,7 +2135,7 @@ static void isr_status_change(struct ipw2100_priv *priv, int status)
for (i = 0; status_handlers[i].status != -1; i++) {
if (status == status_handlers[i].status) {
IPW_DEBUG_NOTIF("Status change: %s\n",
- status_handlers[i].name);
+ status_handlers[i].name);
if (status_handlers[i].cb)
status_handlers[i].cb(priv, status);
priv->wstats.status = status;
@@ -2164,9 +2146,8 @@ static void isr_status_change(struct ipw2100_priv *priv, int status)
IPW_DEBUG_NOTIF("unknown status received: %04x\n", status);
}
-static void isr_rx_complete_command(
- struct ipw2100_priv *priv,
- struct ipw2100_cmd_header *cmd)
+static void isr_rx_complete_command(struct ipw2100_priv *priv,
+ struct ipw2100_cmd_header *cmd)
{
#ifdef CONFIG_IPW_DEBUG
if (cmd->host_command_reg < ARRAY_SIZE(command_types)) {
@@ -2196,10 +2177,8 @@ static const char *frame_types[] = {
};
#endif
-
-static inline int ipw2100_alloc_skb(
- struct ipw2100_priv *priv,
- struct ipw2100_rx_packet *packet)
+static inline int ipw2100_alloc_skb(struct ipw2100_priv *priv,
+ struct ipw2100_rx_packet *packet)
{
packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx));
if (!packet->skb)
@@ -2215,7 +2194,6 @@ static inline int ipw2100_alloc_skb(
return 0;
}
-
#define SEARCH_ERROR 0xffffffff
#define SEARCH_FAIL 0xfffffffe
#define SEARCH_SUCCESS 0xfffffff0
@@ -2229,10 +2207,10 @@ static inline int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
if (priv->snapshot[0])
return 1;
for (i = 0; i < 0x30; i++) {
- priv->snapshot[i] = (u8*)kmalloc(0x1000, GFP_ATOMIC);
+ priv->snapshot[i] = (u8 *) kmalloc(0x1000, GFP_ATOMIC);
if (!priv->snapshot[i]) {
IPW_DEBUG_INFO("%s: Error allocating snapshot "
- "buffer %d\n", priv->net_dev->name, i);
+ "buffer %d\n", priv->net_dev->name, i);
while (i > 0)
kfree(priv->snapshot[--i]);
priv->snapshot[0] = NULL;
@@ -2253,7 +2231,7 @@ static inline void ipw2100_snapshot_free(struct ipw2100_priv *priv)
priv->snapshot[0] = NULL;
}
-static inline u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 *in_buf,
+static inline u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
size_t len, int mode)
{
u32 i, j;
@@ -2270,9 +2248,9 @@ static inline u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 *in_buf,
for (ret = SEARCH_FAIL, i = 0; i < 0x30000; i += 4) {
read_nic_dword(priv->net_dev, i, &tmp);
if (mode == SEARCH_SNAPSHOT)
- *(u32 *)SNAPSHOT_ADDR(i) = tmp;
+ *(u32 *) SNAPSHOT_ADDR(i) = tmp;
if (ret == SEARCH_FAIL) {
- d = (u8*)&tmp;
+ d = (u8 *) & tmp;
for (j = 0; j < 4; j++) {
if (*s != *d) {
s = in_buf;
@@ -2310,8 +2288,7 @@ static inline u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 *in_buf,
static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
#endif
-static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv,
- int i)
+static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
{
#ifdef CONFIG_IPW_DEBUG_C3
struct ipw2100_status *status = &priv->status_queue.drv[i];
@@ -2322,11 +2299,11 @@ static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv,
int limit;
#endif
- IPW_DEBUG_INFO(DRV_NAME ": PCI latency error detected at "
- "0x%04zX.\n", i * sizeof(struct ipw2100_status));
+ IPW_DEBUG_INFO(": PCI latency error detected at 0x%04zX.\n",
+ i * sizeof(struct ipw2100_status));
#ifdef ACPI_CSTATE_LIMIT_DEFINED
- IPW_DEBUG_INFO(DRV_NAME ": Disabling C3 transitions.\n");
+ IPW_DEBUG_INFO(": Disabling C3 transitions.\n");
limit = acpi_get_cstate_limit();
if (limit > 2) {
priv->cstate_limit = limit;
@@ -2346,9 +2323,9 @@ static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv,
if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
break;
- } while (j--);
+ } while (j--);
- match = ipw2100_match_buf(priv, (u8*)status,
+ match = ipw2100_match_buf(priv, (u8 *) status,
sizeof(struct ipw2100_status),
SEARCH_SNAPSHOT);
if (match < SEARCH_SUCCESS)
@@ -2360,7 +2337,7 @@ static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv,
IPW_DEBUG_INFO("%s: No DMA status match in "
"Firmware.\n", priv->net_dev->name);
- printk_buf((u8*)priv->status_queue.drv,
+ printk_buf((u8 *) priv->status_queue.drv,
sizeof(struct ipw2100_status) * RX_QUEUE_LENGTH);
#endif
@@ -2392,26 +2369,26 @@ static inline void isr_rx(struct ipw2100_priv *priv, int i,
IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
return;
}
-
+#ifdef CONFIG_IPW2100_MONITOR
if (unlikely(priv->ieee->iw_mode == IW_MODE_MONITOR &&
+ priv->config & CFG_CRC_CHECK &&
status->flags & IPW_STATUS_FLAG_CRC_ERROR)) {
IPW_DEBUG_RX("CRC error in packet. Dropping.\n");
priv->ieee->stats.rx_errors++;
return;
}
+#endif
if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR &&
- !(priv->status & STATUS_ASSOCIATED))) {
+ !(priv->status & STATUS_ASSOCIATED))) {
IPW_DEBUG_DROP("Dropping packet while not associated.\n");
priv->wstats.discard.misc++;
return;
}
-
pci_unmap_single(priv->pci_dev,
packet->dma_addr,
- sizeof(struct ipw2100_rx),
- PCI_DMA_FROMDEVICE);
+ sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE);
skb_put(packet->skb, status->frame_size);
@@ -2438,8 +2415,8 @@ static inline void isr_rx(struct ipw2100_priv *priv, int i,
/* We need to allocate a new SKB and attach it to the RDB. */
if (unlikely(ipw2100_alloc_skb(priv, packet))) {
printk(KERN_WARNING DRV_NAME ": "
- "%s: Unable to allocate SKB onto RBD ring - disabling "
- "adapter.\n", priv->net_dev->name);
+ "%s: Unable to allocate SKB onto RBD ring - disabling "
+ "adapter.\n", priv->net_dev->name);
/* TODO: schedule adapter shutdown */
IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
}
@@ -2534,11 +2511,11 @@ static inline void __ipw2100_rx_process(struct ipw2100_priv *priv)
/* Sync the DMA for the STATUS buffer so CPU is sure to get
* the correct values */
- pci_dma_sync_single_for_cpu(
- priv->pci_dev,
- sq->nic + sizeof(struct ipw2100_status) * i,
- sizeof(struct ipw2100_status),
- PCI_DMA_FROMDEVICE);
+ pci_dma_sync_single_for_cpu(priv->pci_dev,
+ sq->nic +
+ sizeof(struct ipw2100_status) * i,
+ sizeof(struct ipw2100_status),
+ PCI_DMA_FROMDEVICE);
/* Sync the DMA for the RX buffer so CPU is sure to get
* the correct values */
@@ -2552,8 +2529,7 @@ static inline void __ipw2100_rx_process(struct ipw2100_priv *priv)
}
u = packet->rxp;
- frame_type = sq->drv[i].status_fields &
- STATUS_TYPE_MASK;
+ frame_type = sq->drv[i].status_fields & STATUS_TYPE_MASK;
stats.rssi = sq->drv[i].rssi + IPW2100_RSSI_TO_DBM;
stats.len = sq->drv[i].frame_size;
@@ -2562,16 +2538,14 @@ static inline void __ipw2100_rx_process(struct ipw2100_priv *priv)
stats.mask |= IEEE80211_STATMASK_RSSI;
stats.freq = IEEE80211_24GHZ_BAND;
- IPW_DEBUG_RX(
- "%s: '%s' frame type received (%d).\n",
- priv->net_dev->name, frame_types[frame_type],
- stats.len);
+ IPW_DEBUG_RX("%s: '%s' frame type received (%d).\n",
+ priv->net_dev->name, frame_types[frame_type],
+ stats.len);
switch (frame_type) {
case COMMAND_STATUS_VAL:
/* Reset Rx watchdog */
- isr_rx_complete_command(
- priv, &u->rx_data.command);
+ isr_rx_complete_command(priv, &u->rx_data.command);
break;
case STATUS_CHANGE_VAL:
@@ -2588,12 +2562,10 @@ static inline void __ipw2100_rx_process(struct ipw2100_priv *priv)
#endif
if (stats.len < sizeof(u->rx_data.header))
break;
- switch (WLAN_FC_GET_TYPE(u->rx_data.header.
- frame_ctl)) {
+ switch (WLAN_FC_GET_TYPE(u->rx_data.header.frame_ctl)) {
case IEEE80211_FTYPE_MGMT:
ieee80211_rx_mgt(priv->ieee,
- &u->rx_data.header,
- &stats);
+ &u->rx_data.header, &stats);
break;
case IEEE80211_FTYPE_CTL:
@@ -2607,7 +2579,7 @@ static inline void __ipw2100_rx_process(struct ipw2100_priv *priv)
break;
}
- increment:
+ increment:
/* clear status field associated with this RBD */
rxq->drv[i].status.info.field = 0;
@@ -2619,12 +2591,10 @@ static inline void __ipw2100_rx_process(struct ipw2100_priv *priv)
rxq->next = (i ? i : rxq->entries) - 1;
write_register(priv->net_dev,
- IPW_MEM_HOST_SHARED_RX_WRITE_INDEX,
- rxq->next);
+ IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, rxq->next);
}
}
-
/*
* __ipw2100_tx_process
*
@@ -2667,7 +2637,7 @@ static inline void __ipw2100_rx_process(struct ipw2100_priv *priv)
static inline int __ipw2100_tx_process(struct ipw2100_priv *priv)
{
struct ipw2100_bd_queue *txq = &priv->tx_queue;
- struct ipw2100_bd *tbd;
+ struct ipw2100_bd *tbd;
struct list_head *element;
struct ipw2100_tx_packet *packet;
int descriptors_used;
@@ -2680,7 +2650,7 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv)
element = priv->fw_pend_list.next;
packet = list_entry(element, struct ipw2100_tx_packet, list);
- tbd = &txq->drv[packet->index];
+ tbd = &txq->drv[packet->index];
/* Determine how many TBD entries must be finished... */
switch (packet->type) {
@@ -2693,14 +2663,14 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv)
case DATA:
/* DATA uses two slots; advance and loop position. */
descriptors_used = tbd->num_fragments;
- frag_num = tbd->num_fragments - 1;
+ frag_num = tbd->num_fragments - 1;
e = txq->oldest + frag_num;
e %= txq->entries;
break;
default:
printk(KERN_WARNING DRV_NAME ": %s: Bad fw_pend_list entry!\n",
- priv->net_dev->name);
+ priv->net_dev->name);
return 0;
}
@@ -2716,13 +2686,12 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv)
printk(KERN_WARNING DRV_NAME ": %s: write index mismatch\n",
priv->net_dev->name);
- /*
+ /*
* txq->next is the index of the last packet written txq->oldest is
* the index of the r is the index of the next packet to be read by
* firmware
*/
-
/*
* Quick graphic to help you visualize the following
* if / else statement
@@ -2750,23 +2719,20 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv)
#ifdef CONFIG_IPW_DEBUG
{
int i = txq->oldest;
- IPW_DEBUG_TX(
- "TX%d V=%p P=%04X T=%04X L=%d\n", i,
- &txq->drv[i],
- (u32)(txq->nic + i * sizeof(struct ipw2100_bd)),
- txq->drv[i].host_addr,
- txq->drv[i].buf_length);
+ IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
+ &txq->drv[i],
+ (u32) (txq->nic + i * sizeof(struct ipw2100_bd)),
+ txq->drv[i].host_addr, txq->drv[i].buf_length);
if (packet->type == DATA) {
i = (i + 1) % txq->entries;
- IPW_DEBUG_TX(
- "TX%d V=%p P=%04X T=%04X L=%d\n", i,
- &txq->drv[i],
- (u32)(txq->nic + i *
- sizeof(struct ipw2100_bd)),
- (u32)txq->drv[i].host_addr,
- txq->drv[i].buf_length);
+ IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
+ &txq->drv[i],
+ (u32) (txq->nic + i *
+ sizeof(struct ipw2100_bd)),
+ (u32) txq->drv[i].host_addr,
+ txq->drv[i].buf_length);
}
}
#endif
@@ -2780,23 +2746,18 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv)
priv->net_dev->name, txq->oldest, packet->index);
/* DATA packet; we have to unmap and free the SKB */
- priv->ieee->stats.tx_packets++;
for (i = 0; i < frag_num; i++) {
- tbd = &txq->drv[(packet->index + 1 + i) %
- txq->entries];
+ tbd = &txq->drv[(packet->index + 1 + i) % txq->entries];
- IPW_DEBUG_TX(
- "TX%d P=%08x L=%d\n",
- (packet->index + 1 + i) % txq->entries,
- tbd->host_addr, tbd->buf_length);
+ IPW_DEBUG_TX("TX%d P=%08x L=%d\n",
+ (packet->index + 1 + i) % txq->entries,
+ tbd->host_addr, tbd->buf_length);
pci_unmap_single(priv->pci_dev,
tbd->host_addr,
- tbd->buf_length,
- PCI_DMA_TODEVICE);
+ tbd->buf_length, PCI_DMA_TODEVICE);
}
- priv->ieee->stats.tx_bytes += packet->info.d_struct.txb->payload_size;
ieee80211_txb_free(packet->info.d_struct.txb);
packet->info.d_struct.txb = NULL;
@@ -2805,13 +2766,8 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv)
/* We have a free slot in the Tx queue, so wake up the
* transmit layer if it is stopped. */
- if (priv->status & STATUS_ASSOCIATED &&
- netif_queue_stopped(priv->net_dev)) {
- IPW_DEBUG_INFO(KERN_INFO
- "%s: Waking net queue.\n",
- priv->net_dev->name);
+ if (priv->status & STATUS_ASSOCIATED)
netif_wake_queue(priv->net_dev);
- }
/* A packet was processed by the hardware, so update the
* watchdog */
@@ -2829,11 +2785,12 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv)
#ifdef CONFIG_IPW_DEBUG
if (packet->info.c_struct.cmd->host_command_reg <
sizeof(command_types) / sizeof(*command_types))
- IPW_DEBUG_TX(
- "Command '%s (%d)' processed: %d.\n",
- command_types[packet->info.c_struct.cmd->host_command_reg],
- packet->info.c_struct.cmd->host_command_reg,
- packet->info.c_struct.cmd->cmd_status_reg);
+ IPW_DEBUG_TX("Command '%s (%d)' processed: %d.\n",
+ command_types[packet->info.c_struct.cmd->
+ host_command_reg],
+ packet->info.c_struct.cmd->
+ host_command_reg,
+ packet->info.c_struct.cmd->cmd_status_reg);
#endif
list_add_tail(element, &priv->msg_free_list);
@@ -2848,17 +2805,17 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv)
SET_STAT(&priv->txq_stat, txq->available);
IPW_DEBUG_TX("packet latency (send to process) %ld jiffies\n",
- jiffies - packet->jiffy_start);
+ jiffies - packet->jiffy_start);
return (!list_empty(&priv->fw_pend_list));
}
-
static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv)
{
int i = 0;
- while (__ipw2100_tx_process(priv) && i < 200) i++;
+ while (__ipw2100_tx_process(priv) && i < 200)
+ i++;
if (i == 200) {
printk(KERN_WARNING DRV_NAME ": "
@@ -2867,7 +2824,6 @@ static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv)
}
}
-
static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
{
struct list_head *element;
@@ -2892,13 +2848,12 @@ static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
list_del(element);
DEC_STAT(&priv->msg_pend_stat);
- packet = list_entry(element,
- struct ipw2100_tx_packet, list);
+ packet = list_entry(element, struct ipw2100_tx_packet, list);
IPW_DEBUG_TX("using TBD at virt=%p, phys=%p\n",
- &txq->drv[txq->next],
- (void*)(txq->nic + txq->next *
- sizeof(struct ipw2100_bd)));
+ &txq->drv[txq->next],
+ (void *)(txq->nic + txq->next *
+ sizeof(struct ipw2100_bd)));
packet->index = txq->next;
@@ -2911,8 +2866,8 @@ static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
* with f/w debug version */
tbd->num_fragments = 1;
tbd->status.info.field =
- IPW_BD_STATUS_TX_FRAME_COMMAND |
- IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
+ IPW_BD_STATUS_TX_FRAME_COMMAND |
+ IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
/* update TBD queue counters */
txq->next++;
@@ -2934,7 +2889,6 @@ static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
}
}
-
/*
* ipw2100_tx_send_data
*
@@ -2946,7 +2900,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
struct ipw2100_bd_queue *txq = &priv->tx_queue;
struct ipw2100_bd *tbd;
int next = txq->next;
- int i = 0;
+ int i = 0;
struct ipw2100_data_header *ipw_hdr;
struct ieee80211_hdr_3addr *hdr;
@@ -2958,20 +2912,18 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
* maintained between the r and w indexes
*/
element = priv->tx_pend_list.next;
- packet = list_entry(element, struct ipw2100_tx_packet, list);
+ packet = list_entry(element, struct ipw2100_tx_packet, list);
if (unlikely(1 + packet->info.d_struct.txb->nr_frags >
IPW_MAX_BDS)) {
/* TODO: Support merging buffers if more than
* IPW_MAX_BDS are used */
- IPW_DEBUG_INFO(
- "%s: Maximum BD theshold exceeded. "
- "Increase fragmentation level.\n",
- priv->net_dev->name);
+ IPW_DEBUG_INFO("%s: Maximum BD theshold exceeded. "
+ "Increase fragmentation level.\n",
+ priv->net_dev->name);
}
- if (txq->available <= 3 +
- packet->info.d_struct.txb->nr_frags) {
+ if (txq->available <= 3 + packet->info.d_struct.txb->nr_frags) {
IPW_DEBUG_TX("no room in tx_queue\n");
break;
}
@@ -2985,7 +2937,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
ipw_hdr = packet->info.d_struct.data;
hdr = (struct ieee80211_hdr_3addr *)packet->info.d_struct.txb->
- fragments[0]->data;
+ fragments[0]->data;
if (priv->ieee->iw_mode == IW_MODE_INFRA) {
/* To DS: Addr1 = BSSID, Addr2 = SA,
@@ -3007,7 +2959,8 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
ipw_hdr->encrypted = packet->info.d_struct.txb->encrypted;
if (packet->info.d_struct.txb->nr_frags > 1)
ipw_hdr->fragment_size =
- packet->info.d_struct.txb->frag_size - IEEE80211_3ADDR_LEN;
+ packet->info.d_struct.txb->frag_size -
+ IEEE80211_3ADDR_LEN;
else
ipw_hdr->fragment_size = 0;
@@ -3015,54 +2968,53 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
tbd->buf_length = sizeof(struct ipw2100_data_header);
tbd->num_fragments = 1 + packet->info.d_struct.txb->nr_frags;
tbd->status.info.field =
- IPW_BD_STATUS_TX_FRAME_802_3 |
- IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
+ IPW_BD_STATUS_TX_FRAME_802_3 |
+ IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
txq->next++;
txq->next %= txq->entries;
- IPW_DEBUG_TX(
- "data header tbd TX%d P=%08x L=%d\n",
- packet->index, tbd->host_addr,
- tbd->buf_length);
+ IPW_DEBUG_TX("data header tbd TX%d P=%08x L=%d\n",
+ packet->index, tbd->host_addr, tbd->buf_length);
#ifdef CONFIG_IPW_DEBUG
if (packet->info.d_struct.txb->nr_frags > 1)
IPW_DEBUG_FRAG("fragment Tx: %d frames\n",
packet->info.d_struct.txb->nr_frags);
#endif
- for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) {
- tbd = &txq->drv[txq->next];
+ for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) {
+ tbd = &txq->drv[txq->next];
if (i == packet->info.d_struct.txb->nr_frags - 1)
tbd->status.info.field =
- IPW_BD_STATUS_TX_FRAME_802_3 |
- IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
+ IPW_BD_STATUS_TX_FRAME_802_3 |
+ IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
else
tbd->status.info.field =
- IPW_BD_STATUS_TX_FRAME_802_3 |
- IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
+ IPW_BD_STATUS_TX_FRAME_802_3 |
+ IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
tbd->buf_length = packet->info.d_struct.txb->
- fragments[i]->len - IEEE80211_3ADDR_LEN;
+ fragments[i]->len - IEEE80211_3ADDR_LEN;
- tbd->host_addr = pci_map_single(
- priv->pci_dev,
- packet->info.d_struct.txb->fragments[i]->data +
- IEEE80211_3ADDR_LEN,
- tbd->buf_length,
- PCI_DMA_TODEVICE);
+ tbd->host_addr = pci_map_single(priv->pci_dev,
+ packet->info.d_struct.
+ txb->fragments[i]->
+ data +
+ IEEE80211_3ADDR_LEN,
+ tbd->buf_length,
+ PCI_DMA_TODEVICE);
- IPW_DEBUG_TX(
- "data frag tbd TX%d P=%08x L=%d\n",
- txq->next, tbd->host_addr, tbd->buf_length);
+ IPW_DEBUG_TX("data frag tbd TX%d P=%08x L=%d\n",
+ txq->next, tbd->host_addr,
+ tbd->buf_length);
- pci_dma_sync_single_for_device(
- priv->pci_dev, tbd->host_addr,
- tbd->buf_length,
- PCI_DMA_TODEVICE);
+ pci_dma_sync_single_for_device(priv->pci_dev,
+ tbd->host_addr,
+ tbd->buf_length,
+ PCI_DMA_TODEVICE);
txq->next++;
txq->next %= txq->entries;
- }
+ }
txq->available -= 1 + packet->info.d_struct.txb->nr_frags;
SET_STAT(&priv->txq_stat, txq->available);
@@ -3078,7 +3030,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
txq->next);
}
- return;
+ return;
}
static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
@@ -3106,11 +3058,9 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
if (inta & IPW2100_INTA_FATAL_ERROR) {
printk(KERN_WARNING DRV_NAME
- ": Fatal interrupt. Scheduling firmware restart.\n");
+ ": Fatal interrupt. Scheduling firmware restart.\n");
priv->inta_other++;
- write_register(
- dev, IPW_REG_INTA,
- IPW2100_INTA_FATAL_ERROR);
+ write_register(dev, IPW_REG_INTA, IPW2100_INTA_FATAL_ERROR);
read_nic_dword(dev, IPW_NIC_FATAL_ERROR, &priv->fatal_error);
IPW_DEBUG_INFO("%s: Fatal error value: 0x%08X\n",
@@ -3125,11 +3075,10 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
}
if (inta & IPW2100_INTA_PARITY_ERROR) {
- printk(KERN_ERR DRV_NAME ": ***** PARITY ERROR INTERRUPT !!!! \n");
+ printk(KERN_ERR DRV_NAME
+ ": ***** PARITY ERROR INTERRUPT !!!! \n");
priv->inta_other++;
- write_register(
- dev, IPW_REG_INTA,
- IPW2100_INTA_PARITY_ERROR);
+ write_register(dev, IPW_REG_INTA, IPW2100_INTA_PARITY_ERROR);
}
if (inta & IPW2100_INTA_RX_TRANSFER) {
@@ -3137,9 +3086,7 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
priv->rx_interrupts++;
- write_register(
- dev, IPW_REG_INTA,
- IPW2100_INTA_RX_TRANSFER);
+ write_register(dev, IPW_REG_INTA, IPW2100_INTA_RX_TRANSFER);
__ipw2100_rx_process(priv);
__ipw2100_tx_complete(priv);
@@ -3150,8 +3097,7 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
priv->tx_interrupts++;
- write_register(dev, IPW_REG_INTA,
- IPW2100_INTA_TX_TRANSFER);
+ write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_TRANSFER);
__ipw2100_tx_complete(priv);
ipw2100_tx_send_commands(priv);
@@ -3161,9 +3107,7 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
if (inta & IPW2100_INTA_TX_COMPLETE) {
IPW_DEBUG_ISR("TX complete\n");
priv->inta_other++;
- write_register(
- dev, IPW_REG_INTA,
- IPW2100_INTA_TX_COMPLETE);
+ write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_COMPLETE);
__ipw2100_tx_complete(priv);
}
@@ -3171,9 +3115,7 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
if (inta & IPW2100_INTA_EVENT_INTERRUPT) {
/* ipw2100_handle_event(dev); */
priv->inta_other++;
- write_register(
- dev, IPW_REG_INTA,
- IPW2100_INTA_EVENT_INTERRUPT);
+ write_register(dev, IPW_REG_INTA, IPW2100_INTA_EVENT_INTERRUPT);
}
if (inta & IPW2100_INTA_FW_INIT_DONE) {
@@ -3183,30 +3125,25 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
read_register(dev, IPW_REG_INTA, &tmp);
if (tmp & (IPW2100_INTA_FATAL_ERROR |
IPW2100_INTA_PARITY_ERROR)) {
- write_register(
- dev, IPW_REG_INTA,
- IPW2100_INTA_FATAL_ERROR |
- IPW2100_INTA_PARITY_ERROR);
+ write_register(dev, IPW_REG_INTA,
+ IPW2100_INTA_FATAL_ERROR |
+ IPW2100_INTA_PARITY_ERROR);
}
- write_register(dev, IPW_REG_INTA,
- IPW2100_INTA_FW_INIT_DONE);
+ write_register(dev, IPW_REG_INTA, IPW2100_INTA_FW_INIT_DONE);
}
if (inta & IPW2100_INTA_STATUS_CHANGE) {
IPW_DEBUG_ISR("Status change interrupt\n");
priv->inta_other++;
- write_register(
- dev, IPW_REG_INTA,
- IPW2100_INTA_STATUS_CHANGE);
+ write_register(dev, IPW_REG_INTA, IPW2100_INTA_STATUS_CHANGE);
}
if (inta & IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE) {
IPW_DEBUG_ISR("slave host mode interrupt\n");
priv->inta_other++;
- write_register(
- dev, IPW_REG_INTA,
- IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE);
+ write_register(dev, IPW_REG_INTA,
+ IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE);
}
priv->in_isr--;
@@ -3217,9 +3154,7 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
IPW_DEBUG_ISR("exit\n");
}
-
-static irqreturn_t ipw2100_interrupt(int irq, void *data,
- struct pt_regs *regs)
+static irqreturn_t ipw2100_interrupt(int irq, void *data, struct pt_regs *regs)
{
struct ipw2100_priv *priv = data;
u32 inta, inta_mask;
@@ -3227,7 +3162,7 @@ static irqreturn_t ipw2100_interrupt(int irq, void *data,
if (!data)
return IRQ_NONE;
- spin_lock(&priv->low_lock);
+ spin_lock(&priv->low_lock);
/* We check to see if we should be ignoring interrupts before
* we touch the hardware. During ucode load if we try and handle
@@ -3261,10 +3196,10 @@ static irqreturn_t ipw2100_interrupt(int irq, void *data,
ipw2100_disable_interrupts(priv);
tasklet_schedule(&priv->irq_tasklet);
- spin_unlock(&priv->low_lock);
+ spin_unlock(&priv->low_lock);
return IRQ_HANDLED;
- none:
+ none:
spin_unlock(&priv->low_lock);
return IRQ_NONE;
}
@@ -3294,10 +3229,8 @@ static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev,
packet->info.d_struct.txb = txb;
- IPW_DEBUG_TX("Sending fragment (%d bytes):\n",
- txb->fragments[0]->len);
- printk_buf(IPW_DL_TX, txb->fragments[0]->data,
- txb->fragments[0]->len);
+ IPW_DEBUG_TX("Sending fragment (%d bytes):\n", txb->fragments[0]->len);
+ printk_buf(IPW_DL_TX, txb->fragments[0]->data, txb->fragments[0]->len);
packet->jiffy_start = jiffies;
@@ -3312,22 +3245,23 @@ static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev,
spin_unlock_irqrestore(&priv->low_lock, flags);
return 0;
- fail_unlock:
+ fail_unlock:
netif_stop_queue(dev);
spin_unlock_irqrestore(&priv->low_lock, flags);
return 1;
}
-
static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
{
int i, j, err = -EINVAL;
void *v;
dma_addr_t p;
- priv->msg_buffers = (struct ipw2100_tx_packet *)kmalloc(
- IPW_COMMAND_POOL_SIZE * sizeof(struct ipw2100_tx_packet),
- GFP_KERNEL);
+ priv->msg_buffers =
+ (struct ipw2100_tx_packet *)kmalloc(IPW_COMMAND_POOL_SIZE *
+ sizeof(struct
+ ipw2100_tx_packet),
+ GFP_KERNEL);
if (!priv->msg_buffers) {
printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for msg "
"buffers.\n", priv->net_dev->name);
@@ -3335,15 +3269,12 @@ static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
}
for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
- v = pci_alloc_consistent(
- priv->pci_dev,
- sizeof(struct ipw2100_cmd_header),
- &p);
+ v = pci_alloc_consistent(priv->pci_dev,
+ sizeof(struct ipw2100_cmd_header), &p);
if (!v) {
printk(KERN_ERR DRV_NAME ": "
"%s: PCI alloc failed for msg "
- "buffers.\n",
- priv->net_dev->name);
+ "buffers.\n", priv->net_dev->name);
err = -ENOMEM;
break;
}
@@ -3352,7 +3283,7 @@ static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
priv->msg_buffers[i].type = COMMAND;
priv->msg_buffers[i].info.c_struct.cmd =
- (struct ipw2100_cmd_header*)v;
+ (struct ipw2100_cmd_header *)v;
priv->msg_buffers[i].info.c_struct.cmd_phys = p;
}
@@ -3360,11 +3291,11 @@ static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
return 0;
for (j = 0; j < i; j++) {
- pci_free_consistent(
- priv->pci_dev,
- sizeof(struct ipw2100_cmd_header),
- priv->msg_buffers[j].info.c_struct.cmd,
- priv->msg_buffers[j].info.c_struct.cmd_phys);
+ pci_free_consistent(priv->pci_dev,
+ sizeof(struct ipw2100_cmd_header),
+ priv->msg_buffers[j].info.c_struct.cmd,
+ priv->msg_buffers[j].info.c_struct.
+ cmd_phys);
}
kfree(priv->msg_buffers);
@@ -3398,7 +3329,8 @@ static void ipw2100_msg_free(struct ipw2100_priv *priv)
pci_free_consistent(priv->pci_dev,
sizeof(struct ipw2100_cmd_header),
priv->msg_buffers[i].info.c_struct.cmd,
- priv->msg_buffers[i].info.c_struct.cmd_phys);
+ priv->msg_buffers[i].info.c_struct.
+ cmd_phys);
}
kfree(priv->msg_buffers);
@@ -3424,6 +3356,7 @@ static ssize_t show_pci(struct device *d, struct device_attribute *attr,
return out - buf;
}
+
static DEVICE_ATTR(pci, S_IRUGO, show_pci, NULL);
static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
@@ -3432,209 +3365,269 @@ static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
struct ipw2100_priv *p = d->driver_data;
return sprintf(buf, "0x%08x\n", (int)p->config);
}
+
static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL);
static ssize_t show_status(struct device *d, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
struct ipw2100_priv *p = d->driver_data;
return sprintf(buf, "0x%08x\n", (int)p->status);
}
+
static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
static ssize_t show_capability(struct device *d, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
struct ipw2100_priv *p = d->driver_data;
return sprintf(buf, "0x%08x\n", (int)p->capability);
}
-static DEVICE_ATTR(capability, S_IRUGO, show_capability, NULL);
+static DEVICE_ATTR(capability, S_IRUGO, show_capability, NULL);
#define IPW2100_REG(x) { IPW_ ##x, #x }
static const struct {
u32 addr;
const char *name;
} hw_data[] = {
- IPW2100_REG(REG_GP_CNTRL),
- IPW2100_REG(REG_GPIO),
- IPW2100_REG(REG_INTA),
- IPW2100_REG(REG_INTA_MASK),
- IPW2100_REG(REG_RESET_REG),
-};
+IPW2100_REG(REG_GP_CNTRL),
+ IPW2100_REG(REG_GPIO),
+ IPW2100_REG(REG_INTA),
+ IPW2100_REG(REG_INTA_MASK), IPW2100_REG(REG_RESET_REG),};
#define IPW2100_NIC(x, s) { x, #x, s }
static const struct {
u32 addr;
const char *name;
size_t size;
} nic_data[] = {
- IPW2100_NIC(IPW2100_CONTROL_REG, 2),
- IPW2100_NIC(0x210014, 1),
- IPW2100_NIC(0x210000, 1),
-};
+IPW2100_NIC(IPW2100_CONTROL_REG, 2),
+ IPW2100_NIC(0x210014, 1), IPW2100_NIC(0x210000, 1),};
#define IPW2100_ORD(x, d) { IPW_ORD_ ##x, #x, d }
static const struct {
u8 index;
const char *name;
const char *desc;
} ord_data[] = {
- IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"),
- IPW2100_ORD(STAT_TX_HOST_COMPLETE, "successful Host Tx's (MSDU)"),
- IPW2100_ORD(STAT_TX_DIR_DATA, "successful Directed Tx's (MSDU)"),
- IPW2100_ORD(STAT_TX_DIR_DATA1, "successful Directed Tx's (MSDU) @ 1MB"),
- IPW2100_ORD(STAT_TX_DIR_DATA2, "successful Directed Tx's (MSDU) @ 2MB"),
- IPW2100_ORD(STAT_TX_DIR_DATA5_5, "successful Directed Tx's (MSDU) @ 5_5MB"),
- IPW2100_ORD(STAT_TX_DIR_DATA11, "successful Directed Tx's (MSDU) @ 11MB"),
- IPW2100_ORD(STAT_TX_NODIR_DATA1, "successful Non_Directed Tx's (MSDU) @ 1MB"),
- IPW2100_ORD(STAT_TX_NODIR_DATA2, "successful Non_Directed Tx's (MSDU) @ 2MB"),
- IPW2100_ORD(STAT_TX_NODIR_DATA5_5, "successful Non_Directed Tx's (MSDU) @ 5.5MB"),
- IPW2100_ORD(STAT_TX_NODIR_DATA11, "successful Non_Directed Tx's (MSDU) @ 11MB"),
- IPW2100_ORD(STAT_NULL_DATA, "successful NULL data Tx's"),
- IPW2100_ORD(STAT_TX_RTS, "successful Tx RTS"),
- IPW2100_ORD(STAT_TX_CTS, "successful Tx CTS"),
- IPW2100_ORD(STAT_TX_ACK, "successful Tx ACK"),
- IPW2100_ORD(STAT_TX_ASSN, "successful Association Tx's"),
- IPW2100_ORD(STAT_TX_ASSN_RESP, "successful Association response Tx's"),
- IPW2100_ORD(STAT_TX_REASSN, "successful Reassociation Tx's"),
- IPW2100_ORD(STAT_TX_REASSN_RESP, "successful Reassociation response Tx's"),
- IPW2100_ORD(STAT_TX_PROBE, "probes successfully transmitted"),
- IPW2100_ORD(STAT_TX_PROBE_RESP, "probe responses successfully transmitted"),
- IPW2100_ORD(STAT_TX_BEACON, "tx beacon"),
- IPW2100_ORD(STAT_TX_ATIM, "Tx ATIM"),
- IPW2100_ORD(STAT_TX_DISASSN, "successful Disassociation TX"),
- IPW2100_ORD(STAT_TX_AUTH, "successful Authentication Tx"),
- IPW2100_ORD(STAT_TX_DEAUTH, "successful Deauthentication TX"),
- IPW2100_ORD(STAT_TX_TOTAL_BYTES, "Total successful Tx data bytes"),
- IPW2100_ORD(STAT_TX_RETRIES, "Tx retries"),
- IPW2100_ORD(STAT_TX_RETRY1, "Tx retries at 1MBPS"),
- IPW2100_ORD(STAT_TX_RETRY2, "Tx retries at 2MBPS"),
- IPW2100_ORD(STAT_TX_RETRY5_5, "Tx retries at 5.5MBPS"),
- IPW2100_ORD(STAT_TX_RETRY11, "Tx retries at 11MBPS"),
- IPW2100_ORD(STAT_TX_FAILURES, "Tx Failures"),
- IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP,"times max tries in a hop failed"),
- IPW2100_ORD(STAT_TX_DISASSN_FAIL, "times disassociation failed"),
- IPW2100_ORD(STAT_TX_ERR_CTS, "missed/bad CTS frames"),
- IPW2100_ORD(STAT_TX_ERR_ACK, "tx err due to acks"),
- IPW2100_ORD(STAT_RX_HOST, "packets passed to host"),
- IPW2100_ORD(STAT_RX_DIR_DATA, "directed packets"),
- IPW2100_ORD(STAT_RX_DIR_DATA1, "directed packets at 1MB"),
- IPW2100_ORD(STAT_RX_DIR_DATA2, "directed packets at 2MB"),
- IPW2100_ORD(STAT_RX_DIR_DATA5_5, "directed packets at 5.5MB"),
- IPW2100_ORD(STAT_RX_DIR_DATA11, "directed packets at 11MB"),
- IPW2100_ORD(STAT_RX_NODIR_DATA,"nondirected packets"),
- IPW2100_ORD(STAT_RX_NODIR_DATA1, "nondirected packets at 1MB"),
- IPW2100_ORD(STAT_RX_NODIR_DATA2, "nondirected packets at 2MB"),
- IPW2100_ORD(STAT_RX_NODIR_DATA5_5, "nondirected packets at 5.5MB"),
- IPW2100_ORD(STAT_RX_NODIR_DATA11, "nondirected packets at 11MB"),
- IPW2100_ORD(STAT_RX_NULL_DATA, "null data rx's"),
- IPW2100_ORD(STAT_RX_RTS, "Rx RTS"),
- IPW2100_ORD(STAT_RX_CTS, "Rx CTS"),
- IPW2100_ORD(STAT_RX_ACK, "Rx ACK"),
- IPW2100_ORD(STAT_RX_CFEND, "Rx CF End"),
- IPW2100_ORD(STAT_RX_CFEND_ACK, "Rx CF End + CF Ack"),
- IPW2100_ORD(STAT_RX_ASSN, "Association Rx's"),
- IPW2100_ORD(STAT_RX_ASSN_RESP, "Association response Rx's"),
- IPW2100_ORD(STAT_RX_REASSN, "Reassociation Rx's"),
- IPW2100_ORD(STAT_RX_REASSN_RESP, "Reassociation response Rx's"),
- IPW2100_ORD(STAT_RX_PROBE, "probe Rx's"),
- IPW2100_ORD(STAT_RX_PROBE_RESP, "probe response Rx's"),
- IPW2100_ORD(STAT_RX_BEACON, "Rx beacon"),
- IPW2100_ORD(STAT_RX_ATIM, "Rx ATIM"),
- IPW2100_ORD(STAT_RX_DISASSN, "disassociation Rx"),
- IPW2100_ORD(STAT_RX_AUTH, "authentication Rx"),
- IPW2100_ORD(STAT_RX_DEAUTH, "deauthentication Rx"),
- IPW2100_ORD(STAT_RX_TOTAL_BYTES,"Total rx data bytes received"),
- IPW2100_ORD(STAT_RX_ERR_CRC, "packets with Rx CRC error"),
- IPW2100_ORD(STAT_RX_ERR_CRC1, "Rx CRC errors at 1MB"),
- IPW2100_ORD(STAT_RX_ERR_CRC2, "Rx CRC errors at 2MB"),
- IPW2100_ORD(STAT_RX_ERR_CRC5_5, "Rx CRC errors at 5.5MB"),
- IPW2100_ORD(STAT_RX_ERR_CRC11, "Rx CRC errors at 11MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE1, "duplicate rx packets at 1MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE2, "duplicate rx packets at 2MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE5_5, "duplicate rx packets at 5.5MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE11, "duplicate rx packets at 11MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"),
- IPW2100_ORD(PERS_DB_LOCK, "locking fw permanent db"),
- IPW2100_ORD(PERS_DB_SIZE, "size of fw permanent db"),
- IPW2100_ORD(PERS_DB_ADDR, "address of fw permanent db"),
- IPW2100_ORD(STAT_RX_INVALID_PROTOCOL, "rx frames with invalid protocol"),
- IPW2100_ORD(SYS_BOOT_TIME, "Boot time"),
- IPW2100_ORD(STAT_RX_NO_BUFFER, "rx frames rejected due to no buffer"),
- IPW2100_ORD(STAT_RX_MISSING_FRAG, "rx frames dropped due to missing fragment"),
- IPW2100_ORD(STAT_RX_ORPHAN_FRAG, "rx frames dropped due to non-sequential fragment"),
- IPW2100_ORD(STAT_RX_ORPHAN_FRAME, "rx frames dropped due to unmatched 1st frame"),
- IPW2100_ORD(STAT_RX_FRAG_AGEOUT, "rx frames dropped due to uncompleted frame"),
- IPW2100_ORD(STAT_RX_ICV_ERRORS, "ICV errors during decryption"),
- IPW2100_ORD(STAT_PSP_SUSPENSION,"times adapter suspended"),
- IPW2100_ORD(STAT_PSP_BCN_TIMEOUT, "beacon timeout"),
- IPW2100_ORD(STAT_PSP_POLL_TIMEOUT, "poll response timeouts"),
- IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT, "timeouts waiting for last {broad,multi}cast pkt"),
- IPW2100_ORD(STAT_PSP_RX_DTIMS, "PSP DTIMs received"),
- IPW2100_ORD(STAT_PSP_RX_TIMS, "PSP TIMs received"),
- IPW2100_ORD(STAT_PSP_STATION_ID,"PSP Station ID"),
- IPW2100_ORD(LAST_ASSN_TIME, "RTC time of last association"),
- IPW2100_ORD(STAT_PERCENT_MISSED_BCNS,"current calculation of % missed beacons"),
- IPW2100_ORD(STAT_PERCENT_RETRIES,"current calculation of % missed tx retries"),
- IPW2100_ORD(ASSOCIATED_AP_PTR, "0 if not associated, else pointer to AP table entry"),
- IPW2100_ORD(AVAILABLE_AP_CNT, "AP's decsribed in the AP table"),
- IPW2100_ORD(AP_LIST_PTR, "Ptr to list of available APs"),
- IPW2100_ORD(STAT_AP_ASSNS, "associations"),
- IPW2100_ORD(STAT_ASSN_FAIL, "association failures"),
- IPW2100_ORD(STAT_ASSN_RESP_FAIL,"failures due to response fail"),
- IPW2100_ORD(STAT_FULL_SCANS, "full scans"),
- IPW2100_ORD(CARD_DISABLED, "Card Disabled"),
- IPW2100_ORD(STAT_ROAM_INHIBIT, "times roaming was inhibited due to activity"),
- IPW2100_ORD(RSSI_AT_ASSN, "RSSI of associated AP at time of association"),
- IPW2100_ORD(STAT_ASSN_CAUSE1, "reassociation: no probe response or TX on hop"),
- IPW2100_ORD(STAT_ASSN_CAUSE2, "reassociation: poor tx/rx quality"),
- IPW2100_ORD(STAT_ASSN_CAUSE3, "reassociation: tx/rx quality (excessive AP load"),
- IPW2100_ORD(STAT_ASSN_CAUSE4, "reassociation: AP RSSI level"),
- IPW2100_ORD(STAT_ASSN_CAUSE5, "reassociations due to load leveling"),
- IPW2100_ORD(STAT_AUTH_FAIL, "times authentication failed"),
- IPW2100_ORD(STAT_AUTH_RESP_FAIL,"times authentication response failed"),
- IPW2100_ORD(STATION_TABLE_CNT, "entries in association table"),
- IPW2100_ORD(RSSI_AVG_CURR, "Current avg RSSI"),
- IPW2100_ORD(POWER_MGMT_MODE, "Power mode - 0=CAM, 1=PSP"),
- IPW2100_ORD(COUNTRY_CODE, "IEEE country code as recv'd from beacon"),
- IPW2100_ORD(COUNTRY_CHANNELS, "channels suported by country"),
- IPW2100_ORD(RESET_CNT, "adapter resets (warm)"),
- IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"),
- IPW2100_ORD(ANTENNA_DIVERSITY, "TRUE if antenna diversity is disabled"),
- IPW2100_ORD(DTIM_PERIOD, "beacon intervals between DTIMs"),
- IPW2100_ORD(OUR_FREQ, "current radio freq lower digits - channel ID"),
- IPW2100_ORD(RTC_TIME, "current RTC time"),
- IPW2100_ORD(PORT_TYPE, "operating mode"),
- IPW2100_ORD(CURRENT_TX_RATE, "current tx rate"),
- IPW2100_ORD(SUPPORTED_RATES, "supported tx rates"),
- IPW2100_ORD(ATIM_WINDOW, "current ATIM Window"),
- IPW2100_ORD(BASIC_RATES, "basic tx rates"),
- IPW2100_ORD(NIC_HIGHEST_RATE, "NIC highest tx rate"),
- IPW2100_ORD(AP_HIGHEST_RATE, "AP highest tx rate"),
- IPW2100_ORD(CAPABILITIES, "Management frame capability field"),
- IPW2100_ORD(AUTH_TYPE, "Type of authentication"),
- IPW2100_ORD(RADIO_TYPE, "Adapter card platform type"),
- IPW2100_ORD(RTS_THRESHOLD, "Min packet length for RTS handshaking"),
- IPW2100_ORD(INT_MODE, "International mode"),
- IPW2100_ORD(FRAGMENTATION_THRESHOLD, "protocol frag threshold"),
- IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS, "EEPROM offset in SRAM"),
- IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE, "EEPROM size in SRAM"),
- IPW2100_ORD(EEPROM_SKU_CAPABILITY, "EEPROM SKU Capability"),
- IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS, "EEPROM IBSS 11b channel set"),
- IPW2100_ORD(MAC_VERSION, "MAC Version"),
- IPW2100_ORD(MAC_REVISION, "MAC Revision"),
- IPW2100_ORD(RADIO_VERSION, "Radio Version"),
- IPW2100_ORD(NIC_MANF_DATE_TIME, "MANF Date/Time STAMP"),
- IPW2100_ORD(UCODE_VERSION, "Ucode Version"),
-};
-
+IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"),
+ IPW2100_ORD(STAT_TX_HOST_COMPLETE,
+ "successful Host Tx's (MSDU)"),
+ IPW2100_ORD(STAT_TX_DIR_DATA,
+ "successful Directed Tx's (MSDU)"),
+ IPW2100_ORD(STAT_TX_DIR_DATA1,
+ "successful Directed Tx's (MSDU) @ 1MB"),
+ IPW2100_ORD(STAT_TX_DIR_DATA2,
+ "successful Directed Tx's (MSDU) @ 2MB"),
+ IPW2100_ORD(STAT_TX_DIR_DATA5_5,
+ "successful Directed Tx's (MSDU) @ 5_5MB"),
+ IPW2100_ORD(STAT_TX_DIR_DATA11,
+ "successful Directed Tx's (MSDU) @ 11MB"),
+ IPW2100_ORD(STAT_TX_NODIR_DATA1,
+ "successful Non_Directed Tx's (MSDU) @ 1MB"),
+ IPW2100_ORD(STAT_TX_NODIR_DATA2,
+ "successful Non_Directed Tx's (MSDU) @ 2MB"),
+ IPW2100_ORD(STAT_TX_NODIR_DATA5_5,
+ "successful Non_Directed Tx's (MSDU) @ 5.5MB"),
+ IPW2100_ORD(STAT_TX_NODIR_DATA11,
+ "successful Non_Directed Tx's (MSDU) @ 11MB"),
+ IPW2100_ORD(STAT_NULL_DATA, "successful NULL data Tx's"),
+ IPW2100_ORD(STAT_TX_RTS, "successful Tx RTS"),
+ IPW2100_ORD(STAT_TX_CTS, "successful Tx CTS"),
+ IPW2100_ORD(STAT_TX_ACK, "successful Tx ACK"),
+ IPW2100_ORD(STAT_TX_ASSN, "successful Association Tx's"),
+ IPW2100_ORD(STAT_TX_ASSN_RESP,
+ "successful Association response Tx's"),
+ IPW2100_ORD(STAT_TX_REASSN,
+ "successful Reassociation Tx's"),
+ IPW2100_ORD(STAT_TX_REASSN_RESP,
+ "successful Reassociation response Tx's"),
+ IPW2100_ORD(STAT_TX_PROBE,
+ "probes successfully transmitted"),
+ IPW2100_ORD(STAT_TX_PROBE_RESP,
+ "probe responses successfully transmitted"),
+ IPW2100_ORD(STAT_TX_BEACON, "tx beacon"),
+ IPW2100_ORD(STAT_TX_ATIM, "Tx ATIM"),
+ IPW2100_ORD(STAT_TX_DISASSN,
+ "successful Disassociation TX"),
+ IPW2100_ORD(STAT_TX_AUTH, "successful Authentication Tx"),
+ IPW2100_ORD(STAT_TX_DEAUTH,
+ "successful Deauthentication TX"),
+ IPW2100_ORD(STAT_TX_TOTAL_BYTES,
+ "Total successful Tx data bytes"),
+ IPW2100_ORD(STAT_TX_RETRIES, "Tx retries"),
+ IPW2100_ORD(STAT_TX_RETRY1, "Tx retries at 1MBPS"),
+ IPW2100_ORD(STAT_TX_RETRY2, "Tx retries at 2MBPS"),
+ IPW2100_ORD(STAT_TX_RETRY5_5, "Tx retries at 5.5MBPS"),
+ IPW2100_ORD(STAT_TX_RETRY11, "Tx retries at 11MBPS"),
+ IPW2100_ORD(STAT_TX_FAILURES, "Tx Failures"),
+ IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP,
+ "times max tries in a hop failed"),
+ IPW2100_ORD(STAT_TX_DISASSN_FAIL,
+ "times disassociation failed"),
+ IPW2100_ORD(STAT_TX_ERR_CTS, "missed/bad CTS frames"),
+ IPW2100_ORD(STAT_TX_ERR_ACK, "tx err due to acks"),
+ IPW2100_ORD(STAT_RX_HOST, "packets passed to host"),
+ IPW2100_ORD(STAT_RX_DIR_DATA, "directed packets"),
+ IPW2100_ORD(STAT_RX_DIR_DATA1, "directed packets at 1MB"),
+ IPW2100_ORD(STAT_RX_DIR_DATA2, "directed packets at 2MB"),
+ IPW2100_ORD(STAT_RX_DIR_DATA5_5,
+ "directed packets at 5.5MB"),
+ IPW2100_ORD(STAT_RX_DIR_DATA11, "directed packets at 11MB"),
+ IPW2100_ORD(STAT_RX_NODIR_DATA, "nondirected packets"),
+ IPW2100_ORD(STAT_RX_NODIR_DATA1,
+ "nondirected packets at 1MB"),
+ IPW2100_ORD(STAT_RX_NODIR_DATA2,
+ "nondirected packets at 2MB"),
+ IPW2100_ORD(STAT_RX_NODIR_DATA5_5,
+ "nondirected packets at 5.5MB"),
+ IPW2100_ORD(STAT_RX_NODIR_DATA11,
+ "nondirected packets at 11MB"),
+ IPW2100_ORD(STAT_RX_NULL_DATA, "null data rx's"),
+ IPW2100_ORD(STAT_RX_RTS, "Rx RTS"), IPW2100_ORD(STAT_RX_CTS,
+ "Rx CTS"),
+ IPW2100_ORD(STAT_RX_ACK, "Rx ACK"),
+ IPW2100_ORD(STAT_RX_CFEND, "Rx CF End"),
+ IPW2100_ORD(STAT_RX_CFEND_ACK, "Rx CF End + CF Ack"),
+ IPW2100_ORD(STAT_RX_ASSN, "Association Rx's"),
+ IPW2100_ORD(STAT_RX_ASSN_RESP, "Association response Rx's"),
+ IPW2100_ORD(STAT_RX_REASSN, "Reassociation Rx's"),
+ IPW2100_ORD(STAT_RX_REASSN_RESP,
+ "Reassociation response Rx's"),
+ IPW2100_ORD(STAT_RX_PROBE, "probe Rx's"),
+ IPW2100_ORD(STAT_RX_PROBE_RESP, "probe response Rx's"),
+ IPW2100_ORD(STAT_RX_BEACON, "Rx beacon"),
+ IPW2100_ORD(STAT_RX_ATIM, "Rx ATIM"),
+ IPW2100_ORD(STAT_RX_DISASSN, "disassociation Rx"),
+ IPW2100_ORD(STAT_RX_AUTH, "authentication Rx"),
+ IPW2100_ORD(STAT_RX_DEAUTH, "deauthentication Rx"),
+ IPW2100_ORD(STAT_RX_TOTAL_BYTES,
+ "Total rx data bytes received"),
+ IPW2100_ORD(STAT_RX_ERR_CRC, "packets with Rx CRC error"),
+ IPW2100_ORD(STAT_RX_ERR_CRC1, "Rx CRC errors at 1MB"),
+ IPW2100_ORD(STAT_RX_ERR_CRC2, "Rx CRC errors at 2MB"),
+ IPW2100_ORD(STAT_RX_ERR_CRC5_5, "Rx CRC errors at 5.5MB"),
+ IPW2100_ORD(STAT_RX_ERR_CRC11, "Rx CRC errors at 11MB"),
+ IPW2100_ORD(STAT_RX_DUPLICATE1,
+ "duplicate rx packets at 1MB"),
+ IPW2100_ORD(STAT_RX_DUPLICATE2,
+ "duplicate rx packets at 2MB"),
+ IPW2100_ORD(STAT_RX_DUPLICATE5_5,
+ "duplicate rx packets at 5.5MB"),
+ IPW2100_ORD(STAT_RX_DUPLICATE11,
+ "duplicate rx packets at 11MB"),
+ IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"),
+ IPW2100_ORD(PERS_DB_LOCK, "locking fw permanent db"),
+ IPW2100_ORD(PERS_DB_SIZE, "size of fw permanent db"),
+ IPW2100_ORD(PERS_DB_ADDR, "address of fw permanent db"),
+ IPW2100_ORD(STAT_RX_INVALID_PROTOCOL,
+ "rx frames with invalid protocol"),
+ IPW2100_ORD(SYS_BOOT_TIME, "Boot time"),
+ IPW2100_ORD(STAT_RX_NO_BUFFER,
+ "rx frames rejected due to no buffer"),
+ IPW2100_ORD(STAT_RX_MISSING_FRAG,
+ "rx frames dropped due to missing fragment"),
+ IPW2100_ORD(STAT_RX_ORPHAN_FRAG,
+ "rx frames dropped due to non-sequential fragment"),
+ IPW2100_ORD(STAT_RX_ORPHAN_FRAME,
+ "rx frames dropped due to unmatched 1st frame"),
+ IPW2100_ORD(STAT_RX_FRAG_AGEOUT,
+ "rx frames dropped due to uncompleted frame"),
+ IPW2100_ORD(STAT_RX_ICV_ERRORS,
+ "ICV errors during decryption"),
+ IPW2100_ORD(STAT_PSP_SUSPENSION, "times adapter suspended"),
+ IPW2100_ORD(STAT_PSP_BCN_TIMEOUT, "beacon timeout"),
+ IPW2100_ORD(STAT_PSP_POLL_TIMEOUT,
+ "poll response timeouts"),
+ IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT,
+ "timeouts waiting for last {broad,multi}cast pkt"),
+ IPW2100_ORD(STAT_PSP_RX_DTIMS, "PSP DTIMs received"),
+ IPW2100_ORD(STAT_PSP_RX_TIMS, "PSP TIMs received"),
+ IPW2100_ORD(STAT_PSP_STATION_ID, "PSP Station ID"),
+ IPW2100_ORD(LAST_ASSN_TIME, "RTC time of last association"),
+ IPW2100_ORD(STAT_PERCENT_MISSED_BCNS,
+ "current calculation of % missed beacons"),
+ IPW2100_ORD(STAT_PERCENT_RETRIES,
+ "current calculation of % missed tx retries"),
+ IPW2100_ORD(ASSOCIATED_AP_PTR,
+ "0 if not associated, else pointer to AP table entry"),
+ IPW2100_ORD(AVAILABLE_AP_CNT,
+ "AP's decsribed in the AP table"),
+ IPW2100_ORD(AP_LIST_PTR, "Ptr to list of available APs"),
+ IPW2100_ORD(STAT_AP_ASSNS, "associations"),
+ IPW2100_ORD(STAT_ASSN_FAIL, "association failures"),
+ IPW2100_ORD(STAT_ASSN_RESP_FAIL,
+ "failures due to response fail"),
+ IPW2100_ORD(STAT_FULL_SCANS, "full scans"),
+ IPW2100_ORD(CARD_DISABLED, "Card Disabled"),
+ IPW2100_ORD(STAT_ROAM_INHIBIT,
+ "times roaming was inhibited due to activity"),
+ IPW2100_ORD(RSSI_AT_ASSN,
+ "RSSI of associated AP at time of association"),
+ IPW2100_ORD(STAT_ASSN_CAUSE1,
+ "reassociation: no probe response or TX on hop"),
+ IPW2100_ORD(STAT_ASSN_CAUSE2,
+ "reassociation: poor tx/rx quality"),
+ IPW2100_ORD(STAT_ASSN_CAUSE3,
+ "reassociation: tx/rx quality (excessive AP load"),
+ IPW2100_ORD(STAT_ASSN_CAUSE4,
+ "reassociation: AP RSSI level"),
+ IPW2100_ORD(STAT_ASSN_CAUSE5,
+ "reassociations due to load leveling"),
+ IPW2100_ORD(STAT_AUTH_FAIL, "times authentication failed"),
+ IPW2100_ORD(STAT_AUTH_RESP_FAIL,
+ "times authentication response failed"),
+ IPW2100_ORD(STATION_TABLE_CNT,
+ "entries in association table"),
+ IPW2100_ORD(RSSI_AVG_CURR, "Current avg RSSI"),
+ IPW2100_ORD(POWER_MGMT_MODE, "Power mode - 0=CAM, 1=PSP"),
+ IPW2100_ORD(COUNTRY_CODE,
+ "IEEE country code as recv'd from beacon"),
+ IPW2100_ORD(COUNTRY_CHANNELS,
+ "channels suported by country"),
+ IPW2100_ORD(RESET_CNT, "adapter resets (warm)"),
+ IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"),
+ IPW2100_ORD(ANTENNA_DIVERSITY,
+ "TRUE if antenna diversity is disabled"),
+ IPW2100_ORD(DTIM_PERIOD, "beacon intervals between DTIMs"),
+ IPW2100_ORD(OUR_FREQ,
+ "current radio freq lower digits - channel ID"),
+ IPW2100_ORD(RTC_TIME, "current RTC time"),
+ IPW2100_ORD(PORT_TYPE, "operating mode"),
+ IPW2100_ORD(CURRENT_TX_RATE, "current tx rate"),
+ IPW2100_ORD(SUPPORTED_RATES, "supported tx rates"),
+ IPW2100_ORD(ATIM_WINDOW, "current ATIM Window"),
+ IPW2100_ORD(BASIC_RATES, "basic tx rates"),
+ IPW2100_ORD(NIC_HIGHEST_RATE, "NIC highest tx rate"),
+ IPW2100_ORD(AP_HIGHEST_RATE, "AP highest tx rate"),
+ IPW2100_ORD(CAPABILITIES,
+ "Management frame capability field"),
+ IPW2100_ORD(AUTH_TYPE, "Type of authentication"),
+ IPW2100_ORD(RADIO_TYPE, "Adapter card platform type"),
+ IPW2100_ORD(RTS_THRESHOLD,
+ "Min packet length for RTS handshaking"),
+ IPW2100_ORD(INT_MODE, "International mode"),
+ IPW2100_ORD(FRAGMENTATION_THRESHOLD,
+ "protocol frag threshold"),
+ IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS,
+ "EEPROM offset in SRAM"),
+ IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE,
+ "EEPROM size in SRAM"),
+ IPW2100_ORD(EEPROM_SKU_CAPABILITY, "EEPROM SKU Capability"),
+ IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS,
+ "EEPROM IBSS 11b channel set"),
+ IPW2100_ORD(MAC_VERSION, "MAC Version"),
+ IPW2100_ORD(MAC_REVISION, "MAC Revision"),
+ IPW2100_ORD(RADIO_VERSION, "Radio Version"),
+ IPW2100_ORD(NIC_MANF_DATE_TIME, "MANF Date/Time STAMP"),
+ IPW2100_ORD(UCODE_VERSION, "Ucode Version"),};
static ssize_t show_registers(struct device *d, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
int i;
struct ipw2100_priv *priv = dev_get_drvdata(d);
struct net_device *dev = priv->net_dev;
- char * out = buf;
+ char *out = buf;
u32 val = 0;
out += sprintf(out, "%30s [Address ] : Hex\n", "Register");
@@ -3647,15 +3640,15 @@ static ssize_t show_registers(struct device *d, struct device_attribute *attr,
return out - buf;
}
-static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL);
+static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL);
static ssize_t show_hardware(struct device *d, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
struct ipw2100_priv *priv = dev_get_drvdata(d);
struct net_device *dev = priv->net_dev;
- char * out = buf;
+ char *out = buf;
int i;
out += sprintf(out, "%30s [Address ] : Hex\n", "NIC entry");
@@ -3688,11 +3681,11 @@ static ssize_t show_hardware(struct device *d, struct device_attribute *attr,
}
return out - buf;
}
-static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL);
+static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL);
static ssize_t show_memory(struct device *d, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
struct ipw2100_priv *priv = dev_get_drvdata(d);
struct net_device *dev = priv->net_dev;
@@ -3708,10 +3701,13 @@ static ssize_t show_memory(struct device *d, struct device_attribute *attr,
/* sysfs provides us PAGE_SIZE buffer */
while (len < PAGE_SIZE - 128 && loop < 0x30000) {
- if (priv->snapshot[0]) for (i = 0; i < 4; i++)
- buffer[i] = *(u32 *)SNAPSHOT_ADDR(loop + i * 4);
- else for (i = 0; i < 4; i++)
- read_nic_dword(dev, loop + i * 4, &buffer[i]);
+ if (priv->snapshot[0])
+ for (i = 0; i < 4; i++)
+ buffer[i] =
+ *(u32 *) SNAPSHOT_ADDR(loop + i * 4);
+ else
+ for (i = 0; i < 4; i++)
+ read_nic_dword(dev, loop + i * 4, &buffer[i]);
if (priv->dump_raw)
len += sprintf(buf + len,
@@ -3719,26 +3715,26 @@ static ssize_t show_memory(struct device *d, struct device_attribute *attr,
"%c%c%c%c"
"%c%c%c%c"
"%c%c%c%c",
- ((u8*)buffer)[0x0],
- ((u8*)buffer)[0x1],
- ((u8*)buffer)[0x2],
- ((u8*)buffer)[0x3],
- ((u8*)buffer)[0x4],
- ((u8*)buffer)[0x5],
- ((u8*)buffer)[0x6],
- ((u8*)buffer)[0x7],
- ((u8*)buffer)[0x8],
- ((u8*)buffer)[0x9],
- ((u8*)buffer)[0xa],
- ((u8*)buffer)[0xb],
- ((u8*)buffer)[0xc],
- ((u8*)buffer)[0xd],
- ((u8*)buffer)[0xe],
- ((u8*)buffer)[0xf]);
+ ((u8 *) buffer)[0x0],
+ ((u8 *) buffer)[0x1],
+ ((u8 *) buffer)[0x2],
+ ((u8 *) buffer)[0x3],
+ ((u8 *) buffer)[0x4],
+ ((u8 *) buffer)[0x5],
+ ((u8 *) buffer)[0x6],
+ ((u8 *) buffer)[0x7],
+ ((u8 *) buffer)[0x8],
+ ((u8 *) buffer)[0x9],
+ ((u8 *) buffer)[0xa],
+ ((u8 *) buffer)[0xb],
+ ((u8 *) buffer)[0xc],
+ ((u8 *) buffer)[0xd],
+ ((u8 *) buffer)[0xe],
+ ((u8 *) buffer)[0xf]);
else
len += sprintf(buf + len, "%s\n",
snprint_line(line, sizeof(line),
- (u8*)buffer, 16, loop));
+ (u8 *) buffer, 16, loop));
loop += 16;
}
@@ -3746,44 +3742,44 @@ static ssize_t show_memory(struct device *d, struct device_attribute *attr,
}
static ssize_t store_memory(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
+ const char *buf, size_t count)
{
struct ipw2100_priv *priv = dev_get_drvdata(d);
struct net_device *dev = priv->net_dev;
const char *p = buf;
+ (void) dev; /* kill unused-var warning for debug-only code */
+
if (count < 1)
return count;
if (p[0] == '1' ||
(count >= 2 && tolower(p[0]) == 'o' && tolower(p[1]) == 'n')) {
IPW_DEBUG_INFO("%s: Setting memory dump to RAW mode.\n",
- dev->name);
+ dev->name);
priv->dump_raw = 1;
} else if (p[0] == '0' || (count >= 2 && tolower(p[0]) == 'o' &&
- tolower(p[1]) == 'f')) {
+ tolower(p[1]) == 'f')) {
IPW_DEBUG_INFO("%s: Setting memory dump to HEX mode.\n",
- dev->name);
+ dev->name);
priv->dump_raw = 0;
} else if (tolower(p[0]) == 'r') {
- IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n",
- dev->name);
+ IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n", dev->name);
ipw2100_snapshot_free(priv);
} else
IPW_DEBUG_INFO("%s: Usage: 0|on = HEX, 1|off = RAW, "
- "reset = clear memory snapshot\n",
- dev->name);
+ "reset = clear memory snapshot\n", dev->name);
return count;
}
-static DEVICE_ATTR(memory, S_IWUSR|S_IRUGO, show_memory, store_memory);
+static DEVICE_ATTR(memory, S_IWUSR | S_IRUGO, show_memory, store_memory);
static ssize_t show_ordinals(struct device *d, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
struct ipw2100_priv *priv = dev_get_drvdata(d);
u32 val = 0;
@@ -3791,6 +3787,9 @@ static ssize_t show_ordinals(struct device *d, struct device_attribute *attr,
u32 val_len;
static int loop = 0;
+ if (priv->status & STATUS_RF_KILL_MASK)
+ return 0;
+
if (loop >= sizeof(ord_data) / sizeof(*ord_data))
loop = 0;
@@ -3814,14 +3813,14 @@ static ssize_t show_ordinals(struct device *d, struct device_attribute *attr,
return len;
}
-static DEVICE_ATTR(ordinals, S_IRUGO, show_ordinals, NULL);
+static DEVICE_ATTR(ordinals, S_IRUGO, show_ordinals, NULL);
static ssize_t show_stats(struct device *d, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
struct ipw2100_priv *priv = dev_get_drvdata(d);
- char * out = buf;
+ char *out = buf;
out += sprintf(out, "interrupts: %d {tx: %d, rx: %d, other: %d}\n",
priv->interrupts, priv->tx_interrupts,
@@ -3835,8 +3834,8 @@ static ssize_t show_stats(struct device *d, struct device_attribute *attr,
return out - buf;
}
-static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL);
+static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL);
static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode)
{
@@ -3864,19 +3863,18 @@ static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode)
priv->last_mode = priv->ieee->iw_mode;
priv->net_dev->type = ARPHRD_IEEE80211;
break;
-#endif /* CONFIG_IPW2100_MONITOR */
+#endif /* CONFIG_IPW2100_MONITOR */
}
priv->ieee->iw_mode = mode;
#ifdef CONFIG_PM
- /* Indicate ipw2100_download_firmware download firmware
+ /* Indicate ipw2100_download_firmware download firmware
* from disk instead of memory. */
ipw2100_firmware.version = 0;
#endif
- printk(KERN_INFO "%s: Reseting on mode change.\n",
- priv->net_dev->name);
+ printk(KERN_INFO "%s: Reseting on mode change.\n", priv->net_dev->name);
priv->reset_backoff = 0;
schedule_reset(priv);
@@ -3884,12 +3882,12 @@ static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode)
}
static ssize_t show_internals(struct device *d, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
struct ipw2100_priv *priv = dev_get_drvdata(d);
int len = 0;
-#define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" # y "\n", priv-> x)
+#define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" y "\n", priv-> x)
if (priv->status & STATUS_ASSOCIATED)
len += sprintf(buf + len, "connected: %lu\n",
@@ -3897,55 +3895,60 @@ static ssize_t show_internals(struct device *d, struct device_attribute *attr,
else
len += sprintf(buf + len, "not connected\n");
- DUMP_VAR(ieee->crypt[priv->ieee->tx_keyidx], p);
- DUMP_VAR(status, 08lx);
- DUMP_VAR(config, 08lx);
- DUMP_VAR(capability, 08lx);
+ DUMP_VAR(ieee->crypt[priv->ieee->tx_keyidx], "p");
+ DUMP_VAR(status, "08lx");
+ DUMP_VAR(config, "08lx");
+ DUMP_VAR(capability, "08lx");
- len += sprintf(buf + len, "last_rtc: %lu\n", (unsigned long)priv->last_rtc);
+ len +=
+ sprintf(buf + len, "last_rtc: %lu\n",
+ (unsigned long)priv->last_rtc);
- DUMP_VAR(fatal_error, d);
- DUMP_VAR(stop_hang_check, d);
- DUMP_VAR(stop_rf_kill, d);
- DUMP_VAR(messages_sent, d);
+ DUMP_VAR(fatal_error, "d");
+ DUMP_VAR(stop_hang_check, "d");
+ DUMP_VAR(stop_rf_kill, "d");
+ DUMP_VAR(messages_sent, "d");
- DUMP_VAR(tx_pend_stat.value, d);
- DUMP_VAR(tx_pend_stat.hi, d);
+ DUMP_VAR(tx_pend_stat.value, "d");
+ DUMP_VAR(tx_pend_stat.hi, "d");
- DUMP_VAR(tx_free_stat.value, d);
- DUMP_VAR(tx_free_stat.lo, d);
+ DUMP_VAR(tx_free_stat.value, "d");
+ DUMP_VAR(tx_free_stat.lo, "d");
- DUMP_VAR(msg_free_stat.value, d);
- DUMP_VAR(msg_free_stat.lo, d);
+ DUMP_VAR(msg_free_stat.value, "d");
+ DUMP_VAR(msg_free_stat.lo, "d");
- DUMP_VAR(msg_pend_stat.value, d);
- DUMP_VAR(msg_pend_stat.hi, d);
+ DUMP_VAR(msg_pend_stat.value, "d");
+ DUMP_VAR(msg_pend_stat.hi, "d");
- DUMP_VAR(fw_pend_stat.value, d);
- DUMP_VAR(fw_pend_stat.hi, d);
+ DUMP_VAR(fw_pend_stat.value, "d");
+ DUMP_VAR(fw_pend_stat.hi, "d");
- DUMP_VAR(txq_stat.value, d);
- DUMP_VAR(txq_stat.lo, d);
+ DUMP_VAR(txq_stat.value, "d");
+ DUMP_VAR(txq_stat.lo, "d");
- DUMP_VAR(ieee->scans, d);
- DUMP_VAR(reset_backoff, d);
+ DUMP_VAR(ieee->scans, "d");
+ DUMP_VAR(reset_backoff, "d");
return len;
}
-static DEVICE_ATTR(internals, S_IRUGO, show_internals, NULL);
+static DEVICE_ATTR(internals, S_IRUGO, show_internals, NULL);
static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
struct ipw2100_priv *priv = dev_get_drvdata(d);
char essid[IW_ESSID_MAX_SIZE + 1];
u8 bssid[ETH_ALEN];
u32 chan = 0;
- char * out = buf;
+ char *out = buf;
int length;
int ret;
+ if (priv->status & STATUS_RF_KILL_MASK)
+ return 0;
+
memset(essid, 0, sizeof(essid));
memset(bssid, 0, sizeof(bssid));
@@ -3976,8 +3979,8 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
return out - buf;
}
-static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL);
+static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL);
#ifdef CONFIG_IPW_DEBUG
static ssize_t show_debug_level(struct device_driver *d, char *buf)
@@ -3985,8 +3988,8 @@ static ssize_t show_debug_level(struct device_driver *d, char *buf)
return sprintf(buf, "0x%08X\n", ipw2100_debug_level);
}
-static ssize_t store_debug_level(struct device_driver *d, const char *buf,
- size_t count)
+static ssize_t store_debug_level(struct device_driver *d,
+ const char *buf, size_t count)
{
char *p = (char *)buf;
u32 val;
@@ -3999,28 +4002,26 @@ static ssize_t store_debug_level(struct device_driver *d, const char *buf,
} else
val = simple_strtoul(p, &p, 10);
if (p == buf)
- IPW_DEBUG_INFO(DRV_NAME
- ": %s is not in hex or decimal form.\n", buf);
+ IPW_DEBUG_INFO(": %s is not in hex or decimal form.\n", buf);
else
ipw2100_debug_level = val;
return strnlen(buf, count);
}
+
static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level,
store_debug_level);
-#endif /* CONFIG_IPW_DEBUG */
-
+#endif /* CONFIG_IPW_DEBUG */
static ssize_t show_fatal_error(struct device *d,
- struct device_attribute *attr, char *buf)
+ struct device_attribute *attr, char *buf)
{
struct ipw2100_priv *priv = dev_get_drvdata(d);
char *out = buf;
int i;
if (priv->fatal_error)
- out += sprintf(out, "0x%08X\n",
- priv->fatal_error);
+ out += sprintf(out, "0x%08X\n", priv->fatal_error);
else
out += sprintf(out, "0\n");
@@ -4038,24 +4039,26 @@ static ssize_t show_fatal_error(struct device *d,
}
static ssize_t store_fatal_error(struct device *d,
- struct device_attribute *attr, const char *buf, size_t count)
+ struct device_attribute *attr, const char *buf,
+ size_t count)
{
struct ipw2100_priv *priv = dev_get_drvdata(d);
schedule_reset(priv);
return count;
}
-static DEVICE_ATTR(fatal_error, S_IWUSR|S_IRUGO, show_fatal_error, store_fatal_error);
+static DEVICE_ATTR(fatal_error, S_IWUSR | S_IRUGO, show_fatal_error,
+ store_fatal_error);
static ssize_t show_scan_age(struct device *d, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
struct ipw2100_priv *priv = dev_get_drvdata(d);
return sprintf(buf, "%d\n", priv->ieee->scan_age);
}
static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
+ const char *buf, size_t count)
{
struct ipw2100_priv *priv = dev_get_drvdata(d);
struct net_device *dev = priv->net_dev;
@@ -4065,6 +4068,8 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
unsigned long val;
char *p = buffer;
+ (void) dev; /* kill unused-var warning for debug-only code */
+
IPW_DEBUG_INFO("enter\n");
strncpy(buffer, buf, len);
@@ -4078,8 +4083,7 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
} else
val = simple_strtoul(p, &p, 10);
if (p == buffer) {
- IPW_DEBUG_INFO("%s: user supplied invalid value.\n",
- dev->name);
+ IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name);
} else {
priv->ieee->scan_age = val;
IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age);
@@ -4088,11 +4092,11 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
IPW_DEBUG_INFO("exit\n");
return len;
}
-static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age);
+static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age);
static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr,
- char *buf)
+ char *buf)
{
/* 0 - RF kill not enabled
1 - SW based RF kill active (sysfs)
@@ -4100,7 +4104,7 @@ static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr,
3 - Both HW and SW baed RF kill active */
struct ipw2100_priv *priv = (struct ipw2100_priv *)d->driver_data;
int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) |
- (rf_kill_active(priv) ? 0x2 : 0x0);
+ (rf_kill_active(priv) ? 0x2 : 0x0);
return sprintf(buf, "%i\n", val);
}
@@ -4108,7 +4112,7 @@ static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
{
if ((disable_radio ? 1 : 0) ==
(priv->status & STATUS_RF_KILL_SW ? 1 : 0))
- return 0 ;
+ return 0;
IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n",
disable_radio ? "OFF" : "ON");
@@ -4126,8 +4130,7 @@ static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
/* Make sure the RF_KILL check timer is running */
priv->stop_rf_kill = 0;
cancel_delayed_work(&priv->rf_kill);
- queue_delayed_work(priv->workqueue, &priv->rf_kill,
- HZ);
+ queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ);
} else
schedule_reset(priv);
}
@@ -4137,14 +4140,14 @@ static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
}
static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
+ const char *buf, size_t count)
{
struct ipw2100_priv *priv = dev_get_drvdata(d);
ipw_radio_kill_sw(priv, buf[0] == '1');
return count;
}
-static DEVICE_ATTR(rf_kill, S_IWUSR|S_IRUGO, show_rf_kill, store_rf_kill);
+static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
static struct attribute *ipw2100_sysfs_entries[] = {
&dev_attr_hardware.attr,
@@ -4168,7 +4171,6 @@ static struct attribute_group ipw2100_attribute_group = {
.attrs = ipw2100_sysfs_entries,
};
-
static int status_queue_allocate(struct ipw2100_priv *priv, int entries)
{
struct ipw2100_status_queue *q = &priv->status_queue;
@@ -4176,11 +4178,11 @@ static int status_queue_allocate(struct ipw2100_priv *priv, int entries)
IPW_DEBUG_INFO("enter\n");
q->size = entries * sizeof(struct ipw2100_status);
- q->drv = (struct ipw2100_status *)pci_alloc_consistent(
- priv->pci_dev, q->size, &q->nic);
+ q->drv =
+ (struct ipw2100_status *)pci_alloc_consistent(priv->pci_dev,
+ q->size, &q->nic);
if (!q->drv) {
- IPW_DEBUG_WARNING(
- "Can not allocate status queue.\n");
+ IPW_DEBUG_WARNING("Can not allocate status queue.\n");
return -ENOMEM;
}
@@ -4196,9 +4198,9 @@ static void status_queue_free(struct ipw2100_priv *priv)
IPW_DEBUG_INFO("enter\n");
if (priv->status_queue.drv) {
- pci_free_consistent(
- priv->pci_dev, priv->status_queue.size,
- priv->status_queue.drv, priv->status_queue.nic);
+ pci_free_consistent(priv->pci_dev, priv->status_queue.size,
+ priv->status_queue.drv,
+ priv->status_queue.nic);
priv->status_queue.drv = NULL;
}
@@ -4216,7 +4218,8 @@ static int bd_queue_allocate(struct ipw2100_priv *priv,
q->size = entries * sizeof(struct ipw2100_bd);
q->drv = pci_alloc_consistent(priv->pci_dev, q->size, &q->nic);
if (!q->drv) {
- IPW_DEBUG_INFO("can't allocate shared memory for buffer descriptors\n");
+ IPW_DEBUG_INFO
+ ("can't allocate shared memory for buffer descriptors\n");
return -ENOMEM;
}
memset(q->drv, 0, q->size);
@@ -4226,8 +4229,7 @@ static int bd_queue_allocate(struct ipw2100_priv *priv,
return 0;
}
-static void bd_queue_free(struct ipw2100_priv *priv,
- struct ipw2100_bd_queue *q)
+static void bd_queue_free(struct ipw2100_priv *priv, struct ipw2100_bd_queue *q)
{
IPW_DEBUG_INFO("enter\n");
@@ -4235,21 +4237,21 @@ static void bd_queue_free(struct ipw2100_priv *priv,
return;
if (q->drv) {
- pci_free_consistent(priv->pci_dev,
- q->size, q->drv, q->nic);
+ pci_free_consistent(priv->pci_dev, q->size, q->drv, q->nic);
q->drv = NULL;
}
IPW_DEBUG_INFO("exit\n");
}
-static void bd_queue_initialize(
- struct ipw2100_priv *priv, struct ipw2100_bd_queue * q,
- u32 base, u32 size, u32 r, u32 w)
+static void bd_queue_initialize(struct ipw2100_priv *priv,
+ struct ipw2100_bd_queue *q, u32 base, u32 size,
+ u32 r, u32 w)
{
IPW_DEBUG_INFO("enter\n");
- IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv, (u32)q->nic);
+ IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv,
+ (u32) q->nic);
write_register(priv->net_dev, base, q->nic);
write_register(priv->net_dev, size, q->entries);
@@ -4285,32 +4287,38 @@ static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
err = bd_queue_allocate(priv, &priv->tx_queue, TX_QUEUE_LENGTH);
if (err) {
IPW_DEBUG_ERROR("%s: failed bd_queue_allocate\n",
- priv->net_dev->name);
+ priv->net_dev->name);
return err;
}
- priv->tx_buffers = (struct ipw2100_tx_packet *)kmalloc(
- TX_PENDED_QUEUE_LENGTH * sizeof(struct ipw2100_tx_packet),
- GFP_ATOMIC);
+ priv->tx_buffers =
+ (struct ipw2100_tx_packet *)kmalloc(TX_PENDED_QUEUE_LENGTH *
+ sizeof(struct
+ ipw2100_tx_packet),
+ GFP_ATOMIC);
if (!priv->tx_buffers) {
- printk(KERN_ERR DRV_NAME ": %s: alloc failed form tx buffers.\n",
+ printk(KERN_ERR DRV_NAME
+ ": %s: alloc failed form tx buffers.\n",
priv->net_dev->name);
bd_queue_free(priv, &priv->tx_queue);
return -ENOMEM;
}
for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
- v = pci_alloc_consistent(
- priv->pci_dev, sizeof(struct ipw2100_data_header), &p);
+ v = pci_alloc_consistent(priv->pci_dev,
+ sizeof(struct ipw2100_data_header),
+ &p);
if (!v) {
- printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for tx "
- "buffers.\n", priv->net_dev->name);
+ printk(KERN_ERR DRV_NAME
+ ": %s: PCI alloc failed for tx " "buffers.\n",
+ priv->net_dev->name);
err = -ENOMEM;
break;
}
priv->tx_buffers[i].type = DATA;
- priv->tx_buffers[i].info.d_struct.data = (struct ipw2100_data_header*)v;
+ priv->tx_buffers[i].info.d_struct.data =
+ (struct ipw2100_data_header *)v;
priv->tx_buffers[i].info.d_struct.data_phys = p;
priv->tx_buffers[i].info.d_struct.txb = NULL;
}
@@ -4319,11 +4327,11 @@ static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
return 0;
for (j = 0; j < i; j++) {
- pci_free_consistent(
- priv->pci_dev,
- sizeof(struct ipw2100_data_header),
- priv->tx_buffers[j].info.d_struct.data,
- priv->tx_buffers[j].info.d_struct.data_phys);
+ pci_free_consistent(priv->pci_dev,
+ sizeof(struct ipw2100_data_header),
+ priv->tx_buffers[j].info.d_struct.data,
+ priv->tx_buffers[j].info.d_struct.
+ data_phys);
}
kfree(priv->tx_buffers);
@@ -4356,7 +4364,8 @@ static void ipw2100_tx_initialize(struct ipw2100_priv *priv)
/* We simply drop any SKBs that have been queued for
* transmit */
if (priv->tx_buffers[i].info.d_struct.txb) {
- ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.txb);
+ ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.
+ txb);
priv->tx_buffers[i].info.d_struct.txb = NULL;
}
@@ -4394,15 +4403,17 @@ static void ipw2100_tx_free(struct ipw2100_priv *priv)
for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
if (priv->tx_buffers[i].info.d_struct.txb) {
- ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.txb);
+ ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.
+ txb);
priv->tx_buffers[i].info.d_struct.txb = NULL;
}
if (priv->tx_buffers[i].info.d_struct.data)
- pci_free_consistent(
- priv->pci_dev,
- sizeof(struct ipw2100_data_header),
- priv->tx_buffers[i].info.d_struct.data,
- priv->tx_buffers[i].info.d_struct.data_phys);
+ pci_free_consistent(priv->pci_dev,
+ sizeof(struct ipw2100_data_header),
+ priv->tx_buffers[i].info.d_struct.
+ data,
+ priv->tx_buffers[i].info.d_struct.
+ data_phys);
}
kfree(priv->tx_buffers);
@@ -4411,8 +4422,6 @@ static void ipw2100_tx_free(struct ipw2100_priv *priv)
IPW_DEBUG_INFO("exit\n");
}
-
-
static int ipw2100_rx_allocate(struct ipw2100_priv *priv)
{
int i, j, err = -EINVAL;
@@ -4542,14 +4551,13 @@ static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
int err;
- err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC,
- mac, &length);
+ err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, mac, &length);
if (err) {
IPW_DEBUG_INFO("MAC address read failed\n");
return -EIO;
}
IPW_DEBUG_INFO("card MAC is %02X:%02X:%02X:%02X:%02X:%02X\n",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
memcpy(priv->net_dev->dev_addr, mac, ETH_ALEN);
@@ -4576,8 +4584,7 @@ static int ipw2100_set_mac_address(struct ipw2100_priv *priv, int batch_mode)
IPW_DEBUG_INFO("enter\n");
if (priv->config & CFG_CUSTOM_MAC) {
- memcpy(cmd.host_command_parameters, priv->mac_addr,
- ETH_ALEN);
+ memcpy(cmd.host_command_parameters, priv->mac_addr, ETH_ALEN);
memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
} else
memcpy(cmd.host_command_parameters, priv->net_dev->dev_addr,
@@ -4614,7 +4621,8 @@ static int ipw2100_set_port_type(struct ipw2100_priv *priv, u32 port_type,
if (!batch_mode) {
err = ipw2100_disable_adapter(priv);
if (err) {
- printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+ printk(KERN_ERR DRV_NAME
+ ": %s: Could not disable adapter %d\n",
priv->net_dev->name, err);
return err;
}
@@ -4629,7 +4637,6 @@ static int ipw2100_set_port_type(struct ipw2100_priv *priv, u32 port_type,
return err;
}
-
static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel,
int batch_mode)
{
@@ -4660,8 +4667,7 @@ static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel,
err = ipw2100_hw_send_command(priv, &cmd);
if (err) {
- IPW_DEBUG_INFO("Failed to set channel to %d",
- channel);
+ IPW_DEBUG_INFO("Failed to set channel to %d", channel);
return err;
}
@@ -4703,15 +4709,14 @@ static int ipw2100_system_config(struct ipw2100_priv *priv, int batch_mode)
cmd.host_command_parameters[0] |= IPW_CFG_IBSS_AUTO_START;
cmd.host_command_parameters[0] |= IPW_CFG_IBSS_MASK |
- IPW_CFG_BSS_MASK |
- IPW_CFG_802_1x_ENABLE;
+ IPW_CFG_BSS_MASK | IPW_CFG_802_1x_ENABLE;
if (!(priv->config & CFG_LONG_PREAMBLE))
cmd.host_command_parameters[0] |= IPW_CFG_PREAMBLE_AUTO;
err = ipw2100_get_ordinal(priv,
IPW_ORD_EEPROM_IBSS_11B_CHANNELS,
- &ibss_mask, &len);
+ &ibss_mask, &len);
if (err)
ibss_mask = IPW_IBSS_11B_DEFAULT_MASK;
@@ -4719,7 +4724,7 @@ static int ipw2100_system_config(struct ipw2100_priv *priv, int batch_mode)
cmd.host_command_parameters[2] = REG_CHANNEL_MASK & ibss_mask;
/* 11b only */
- /*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A;*/
+ /*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A; */
err = ipw2100_hw_send_command(priv, &cmd);
if (err)
@@ -4783,8 +4788,7 @@ static int ipw2100_set_tx_rates(struct ipw2100_priv *priv, u32 rate,
return 0;
}
-static int ipw2100_set_power_mode(struct ipw2100_priv *priv,
- int power_level)
+static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level)
{
struct host_command cmd = {
.host_command = POWER_MODE,
@@ -4805,11 +4809,10 @@ static int ipw2100_set_power_mode(struct ipw2100_priv *priv,
priv->power_mode = IPW_POWER_ENABLED | power_level;
#ifdef CONFIG_IPW2100_TX_POWER
- if (priv->port_type == IBSS &&
- priv->adhoc_power != DFTL_IBSS_TX_POWER) {
+ if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) {
/* Set beacon interval */
cmd.host_command = TX_POWER_INDEX;
- cmd.host_command_parameters[0] = (u32)priv->adhoc_power;
+ cmd.host_command_parameters[0] = (u32) priv->adhoc_power;
err = ipw2100_hw_send_command(priv, &cmd);
if (err)
@@ -4820,7 +4823,6 @@ static int ipw2100_set_power_mode(struct ipw2100_priv *priv,
return 0;
}
-
static int ipw2100_set_rts_threshold(struct ipw2100_priv *priv, u32 threshold)
{
struct host_command cmd = {
@@ -4925,8 +4927,7 @@ static int ipw2100_set_long_retry(struct ipw2100_priv *priv, u32 retry)
return 0;
}
-
-static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 *bssid,
+static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid,
int batch_mode)
{
struct host_command cmd = {
@@ -4938,16 +4939,15 @@ static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 *bssid,
#ifdef CONFIG_IPW_DEBUG
if (bssid != NULL)
- IPW_DEBUG_HC(
- "MANDATORY_BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n",
- bssid[0], bssid[1], bssid[2], bssid[3], bssid[4],
- bssid[5]);
+ IPW_DEBUG_HC("MANDATORY_BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n",
+ bssid[0], bssid[1], bssid[2], bssid[3], bssid[4],
+ bssid[5]);
else
IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
#endif
/* if BSSID is empty then we disable mandatory bssid mode */
if (bssid != NULL)
- memcpy((u8 *)cmd.host_command_parameters, bssid, ETH_ALEN);
+ memcpy(cmd.host_command_parameters, bssid, ETH_ALEN);
if (!batch_mode) {
err = ipw2100_disable_adapter(priv);
@@ -4963,7 +4963,6 @@ static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 *bssid,
return err;
}
-#ifdef CONFIG_IEEE80211_WPA
static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv)
{
struct host_command cmd = {
@@ -4987,42 +4986,10 @@ static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv)
return err;
}
-#endif
-
-/*
- * Pseudo code for setting up wpa_frame:
- */
-#if 0
-void x(struct ieee80211_assoc_frame *wpa_assoc)
-{
- struct ipw2100_wpa_assoc_frame frame;
- frame->fixed_ie_mask = IPW_WPA_CAPABILTIES |
- IPW_WPA_LISTENINTERVAL |
- IPW_WPA_AP_ADDRESS;
- frame->capab_info = wpa_assoc->capab_info;
- frame->lisen_interval = wpa_assoc->listent_interval;
- memcpy(frame->current_ap, wpa_assoc->current_ap, ETH_ALEN);
-
- /* UNKNOWN -- I'm not postivive about this part; don't have any WPA
- * setup here to test it with.
- *
- * Walk the IEs in the wpa_assoc and figure out the total size of all
- * that data. Stick that into frame->var_ie_len. Then memcpy() all of
- * the IEs from wpa_frame into frame.
- */
- frame->var_ie_len = calculate_ie_len(wpa_assoc);
- memcpy(frame->var_ie, wpa_assoc->variable, frame->var_ie_len);
-
- ipw2100_set_wpa_ie(priv, &frame, 0);
-}
-#endif
-
-
-
static int ipw2100_set_wpa_ie(struct ipw2100_priv *,
struct ipw2100_wpa_assoc_frame *, int)
-__attribute__ ((unused));
+ __attribute__ ((unused));
static int ipw2100_set_wpa_ie(struct ipw2100_priv *priv,
struct ipw2100_wpa_assoc_frame *wpa_frame,
@@ -5076,7 +5043,7 @@ static int ipw2100_set_security_information(struct ipw2100_priv *priv,
.host_command_length = sizeof(struct security_info_params)
};
struct security_info_params *security =
- (struct security_info_params *)&cmd.host_command_parameters;
+ (struct security_info_params *)&cmd.host_command_parameters;
int err;
memset(security, 0, sizeof(*security));
@@ -5094,25 +5061,25 @@ static int ipw2100_set_security_information(struct ipw2100_priv *priv,
break;
case SEC_LEVEL_1:
security->allowed_ciphers = IPW_WEP40_CIPHER |
- IPW_WEP104_CIPHER;
+ IPW_WEP104_CIPHER;
break;
case SEC_LEVEL_2:
security->allowed_ciphers = IPW_WEP40_CIPHER |
- IPW_WEP104_CIPHER | IPW_TKIP_CIPHER;
+ IPW_WEP104_CIPHER | IPW_TKIP_CIPHER;
break;
case SEC_LEVEL_2_CKIP:
security->allowed_ciphers = IPW_WEP40_CIPHER |
- IPW_WEP104_CIPHER | IPW_CKIP_CIPHER;
+ IPW_WEP104_CIPHER | IPW_CKIP_CIPHER;
break;
case SEC_LEVEL_3:
security->allowed_ciphers = IPW_WEP40_CIPHER |
- IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER;
+ IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER;
break;
}
- IPW_DEBUG_HC(
- "SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n",
- security->auth_mode, security->allowed_ciphers, security_level);
+ IPW_DEBUG_HC
+ ("SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n",
+ security->auth_mode, security->allowed_ciphers, security_level);
security->replay_counters_number = 0;
@@ -5130,8 +5097,7 @@ static int ipw2100_set_security_information(struct ipw2100_priv *priv,
return err;
}
-static int ipw2100_set_tx_power(struct ipw2100_priv *priv,
- u32 tx_power)
+static int ipw2100_set_tx_power(struct ipw2100_priv *priv, u32 tx_power)
{
struct host_command cmd = {
.host_command = TX_POWER_INDEX,
@@ -5140,6 +5106,10 @@ static int ipw2100_set_tx_power(struct ipw2100_priv *priv,
};
int err = 0;
+ if (tx_power != IPW_TX_POWER_DEFAULT)
+ tx_power = (tx_power - IPW_TX_POWER_MIN_DBM) * 16 /
+ (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM);
+
cmd.host_command_parameters[0] = tx_power;
if (priv->ieee->iw_mode == IW_MODE_ADHOC)
@@ -5185,7 +5155,6 @@ static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv,
return 0;
}
-
void ipw2100_queues_initialize(struct ipw2100_priv *priv)
{
ipw2100_tx_initialize(priv);
@@ -5203,13 +5172,12 @@ void ipw2100_queues_free(struct ipw2100_priv *priv)
int ipw2100_queues_allocate(struct ipw2100_priv *priv)
{
if (ipw2100_tx_allocate(priv) ||
- ipw2100_rx_allocate(priv) ||
- ipw2100_msg_allocate(priv))
+ ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv))
goto fail;
return 0;
- fail:
+ fail:
ipw2100_tx_free(priv);
ipw2100_rx_free(priv);
ipw2100_msg_free(priv);
@@ -5235,7 +5203,8 @@ static int ipw2100_set_wep_flags(struct ipw2100_priv *priv, u32 flags,
if (!batch_mode) {
err = ipw2100_disable_adapter(priv);
if (err) {
- printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+ printk(KERN_ERR DRV_NAME
+ ": %s: Could not disable adapter %d\n",
priv->net_dev->name, err);
return err;
}
@@ -5262,7 +5231,6 @@ struct ipw2100_wep_key {
#define WEP_STR_64(x) x[0],x[1],x[2],x[3],x[4]
#define WEP_STR_128(x) x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10]
-
/**
* Set a the wep key
*
@@ -5287,11 +5255,11 @@ static int ipw2100_set_key(struct ipw2100_priv *priv,
.host_command_sequence = 0,
.host_command_length = sizeof(struct ipw2100_wep_key),
};
- struct ipw2100_wep_key *wep_key = (void*)cmd.host_command_parameters;
+ struct ipw2100_wep_key *wep_key = (void *)cmd.host_command_parameters;
int err;
IPW_DEBUG_HC("WEP_KEY_INFO: index = %d, len = %d/%d\n",
- idx, keylen, len);
+ idx, keylen, len);
/* NOTE: We don't check cached values in case the firmware was reset
* or some other problem is occuring. If the user is setting the key,
@@ -5308,22 +5276,23 @@ static int ipw2100_set_key(struct ipw2100_priv *priv,
/* Will be optimized out on debug not being configured in */
if (keylen == 0)
IPW_DEBUG_WEP("%s: Clearing key %d\n",
- priv->net_dev->name, wep_key->idx);
+ priv->net_dev->name, wep_key->idx);
else if (keylen == 5)
IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_64 "\n",
- priv->net_dev->name, wep_key->idx, wep_key->len,
- WEP_STR_64(wep_key->key));
+ priv->net_dev->name, wep_key->idx, wep_key->len,
+ WEP_STR_64(wep_key->key));
else
IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_128
- "\n",
- priv->net_dev->name, wep_key->idx, wep_key->len,
- WEP_STR_128(wep_key->key));
+ "\n",
+ priv->net_dev->name, wep_key->idx, wep_key->len,
+ WEP_STR_128(wep_key->key));
if (!batch_mode) {
err = ipw2100_disable_adapter(priv);
/* FIXME: IPG: shouldn't this prink be in _disable_adapter()? */
if (err) {
- printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+ printk(KERN_ERR DRV_NAME
+ ": %s: Could not disable adapter %d\n",
priv->net_dev->name, err);
return err;
}
@@ -5347,7 +5316,7 @@ static int ipw2100_set_key_index(struct ipw2100_priv *priv,
.host_command = WEP_KEY_INDEX,
.host_command_sequence = 0,
.host_command_length = 4,
- .host_command_parameters = { idx },
+ .host_command_parameters = {idx},
};
int err;
@@ -5359,7 +5328,8 @@ static int ipw2100_set_key_index(struct ipw2100_priv *priv,
if (!batch_mode) {
err = ipw2100_disable_adapter(priv);
if (err) {
- printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
+ printk(KERN_ERR DRV_NAME
+ ": %s: Could not disable adapter %d\n",
priv->net_dev->name, err);
return err;
}
@@ -5374,9 +5344,7 @@ static int ipw2100_set_key_index(struct ipw2100_priv *priv,
return err;
}
-
-static int ipw2100_configure_security(struct ipw2100_priv *priv,
- int batch_mode)
+static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode)
{
int i, err, auth_mode, sec_level, use_group;
@@ -5389,40 +5357,42 @@ static int ipw2100_configure_security(struct ipw2100_priv *priv,
return err;
}
- if (!priv->sec.enabled) {
- err = ipw2100_set_security_information(
- priv, IPW_AUTH_OPEN, SEC_LEVEL_0, 0, 1);
+ if (!priv->ieee->sec.enabled) {
+ err =
+ ipw2100_set_security_information(priv, IPW_AUTH_OPEN,
+ SEC_LEVEL_0, 0, 1);
} else {
auth_mode = IPW_AUTH_OPEN;
- if ((priv->sec.flags & SEC_AUTH_MODE) &&
- (priv->sec.auth_mode == WLAN_AUTH_SHARED_KEY))
+ if ((priv->ieee->sec.flags & SEC_AUTH_MODE) &&
+ (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY))
auth_mode = IPW_AUTH_SHARED;
sec_level = SEC_LEVEL_0;
- if (priv->sec.flags & SEC_LEVEL)
- sec_level = priv->sec.level;
+ if (priv->ieee->sec.flags & SEC_LEVEL)
+ sec_level = priv->ieee->sec.level;
use_group = 0;
- if (priv->sec.flags & SEC_UNICAST_GROUP)
- use_group = priv->sec.unicast_uses_group;
+ if (priv->ieee->sec.flags & SEC_UNICAST_GROUP)
+ use_group = priv->ieee->sec.unicast_uses_group;
- err = ipw2100_set_security_information(
- priv, auth_mode, sec_level, use_group, 1);
+ err =
+ ipw2100_set_security_information(priv, auth_mode, sec_level,
+ use_group, 1);
}
if (err)
goto exit;
- if (priv->sec.enabled) {
+ if (priv->ieee->sec.enabled) {
for (i = 0; i < 4; i++) {
- if (!(priv->sec.flags & (1 << i))) {
- memset(priv->sec.keys[i], 0, WEP_KEY_LEN);
- priv->sec.key_sizes[i] = 0;
+ if (!(priv->ieee->sec.flags & (1 << i))) {
+ memset(priv->ieee->sec.keys[i], 0, WEP_KEY_LEN);
+ priv->ieee->sec.key_sizes[i] = 0;
} else {
err = ipw2100_set_key(priv, i,
- priv->sec.keys[i],
- priv->sec.key_sizes[i],
- 1);
+ priv->ieee->sec.keys[i],
+ priv->ieee->sec.
+ key_sizes[i], 1);
if (err)
goto exit;
}
@@ -5433,14 +5403,16 @@ static int ipw2100_configure_security(struct ipw2100_priv *priv,
/* Always enable privacy so the Host can filter WEP packets if
* encrypted data is sent up */
- err = ipw2100_set_wep_flags(
- priv, priv->sec.enabled ? IPW_PRIVACY_CAPABLE : 0, 1);
+ err =
+ ipw2100_set_wep_flags(priv,
+ priv->ieee->sec.
+ enabled ? IPW_PRIVACY_CAPABLE : 0, 1);
if (err)
goto exit;
priv->status &= ~STATUS_SECURITY_UPDATED;
- exit:
+ exit:
if (!batch_mode)
ipw2100_enable_adapter(priv);
@@ -5469,60 +5441,64 @@ static void shim__set_security(struct net_device *dev,
for (i = 0; i < 4; i++) {
if (sec->flags & (1 << i)) {
- priv->sec.key_sizes[i] = sec->key_sizes[i];
+ priv->ieee->sec.key_sizes[i] = sec->key_sizes[i];
if (sec->key_sizes[i] == 0)
- priv->sec.flags &= ~(1 << i);
+ priv->ieee->sec.flags &= ~(1 << i);
else
- memcpy(priv->sec.keys[i], sec->keys[i],
+ memcpy(priv->ieee->sec.keys[i], sec->keys[i],
sec->key_sizes[i]);
- priv->sec.flags |= (1 << i);
- priv->status |= STATUS_SECURITY_UPDATED;
+ if (sec->level == SEC_LEVEL_1) {
+ priv->ieee->sec.flags |= (1 << i);
+ priv->status |= STATUS_SECURITY_UPDATED;
+ } else
+ priv->ieee->sec.flags &= ~(1 << i);
}
}
if ((sec->flags & SEC_ACTIVE_KEY) &&
- priv->sec.active_key != sec->active_key) {
+ priv->ieee->sec.active_key != sec->active_key) {
if (sec->active_key <= 3) {
- priv->sec.active_key = sec->active_key;
- priv->sec.flags |= SEC_ACTIVE_KEY;
+ priv->ieee->sec.active_key = sec->active_key;
+ priv->ieee->sec.flags |= SEC_ACTIVE_KEY;
} else
- priv->sec.flags &= ~SEC_ACTIVE_KEY;
+ priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY;
priv->status |= STATUS_SECURITY_UPDATED;
}
if ((sec->flags & SEC_AUTH_MODE) &&
- (priv->sec.auth_mode != sec->auth_mode)) {
- priv->sec.auth_mode = sec->auth_mode;
- priv->sec.flags |= SEC_AUTH_MODE;
+ (priv->ieee->sec.auth_mode != sec->auth_mode)) {
+ priv->ieee->sec.auth_mode = sec->auth_mode;
+ priv->ieee->sec.flags |= SEC_AUTH_MODE;
priv->status |= STATUS_SECURITY_UPDATED;
}
- if (sec->flags & SEC_ENABLED &&
- priv->sec.enabled != sec->enabled) {
- priv->sec.flags |= SEC_ENABLED;
- priv->sec.enabled = sec->enabled;
+ if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) {
+ priv->ieee->sec.flags |= SEC_ENABLED;
+ priv->ieee->sec.enabled = sec->enabled;
priv->status |= STATUS_SECURITY_UPDATED;
force_update = 1;
}
- if (sec->flags & SEC_LEVEL &&
- priv->sec.level != sec->level) {
- priv->sec.level = sec->level;
- priv->sec.flags |= SEC_LEVEL;
+ if (sec->flags & SEC_ENCRYPT)
+ priv->ieee->sec.encrypt = sec->encrypt;
+
+ if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) {
+ priv->ieee->sec.level = sec->level;
+ priv->ieee->sec.flags |= SEC_LEVEL;
priv->status |= STATUS_SECURITY_UPDATED;
}
IPW_DEBUG_WEP("Security flags: %c %c%c%c%c %c%c%c%c\n",
- priv->sec.flags & (1<<8) ? '1' : '0',
- priv->sec.flags & (1<<7) ? '1' : '0',
- priv->sec.flags & (1<<6) ? '1' : '0',
- priv->sec.flags & (1<<5) ? '1' : '0',
- priv->sec.flags & (1<<4) ? '1' : '0',
- priv->sec.flags & (1<<3) ? '1' : '0',
- priv->sec.flags & (1<<2) ? '1' : '0',
- priv->sec.flags & (1<<1) ? '1' : '0',
- priv->sec.flags & (1<<0) ? '1' : '0');
+ priv->ieee->sec.flags & (1 << 8) ? '1' : '0',
+ priv->ieee->sec.flags & (1 << 7) ? '1' : '0',
+ priv->ieee->sec.flags & (1 << 6) ? '1' : '0',
+ priv->ieee->sec.flags & (1 << 5) ? '1' : '0',
+ priv->ieee->sec.flags & (1 << 4) ? '1' : '0',
+ priv->ieee->sec.flags & (1 << 3) ? '1' : '0',
+ priv->ieee->sec.flags & (1 << 2) ? '1' : '0',
+ priv->ieee->sec.flags & (1 << 1) ? '1' : '0',
+ priv->ieee->sec.flags & (1 << 0) ? '1' : '0');
/* As a temporary work around to enable WPA until we figure out why
* wpa_supplicant toggles the security capability of the driver, which
@@ -5531,7 +5507,7 @@ static void shim__set_security(struct net_device *dev,
* if (force_update || !(priv->status & STATUS_ASSOCIATED))*/
if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
ipw2100_configure_security(priv, 0);
-done:
+ done:
up(&priv->action_sem);
}
@@ -5556,7 +5532,7 @@ static int ipw2100_adapter_setup(struct ipw2100_priv *priv)
return 0;
}
-#endif /* CONFIG_IPW2100_MONITOR */
+#endif /* CONFIG_IPW2100_MONITOR */
err = ipw2100_read_mac_address(priv);
if (err)
@@ -5576,7 +5552,7 @@ static int ipw2100_adapter_setup(struct ipw2100_priv *priv)
return err;
}
- err = ipw2100_system_config(priv, batch_mode);
+ err = ipw2100_system_config(priv, batch_mode);
if (err)
return err;
@@ -5614,8 +5590,10 @@ static int ipw2100_adapter_setup(struct ipw2100_priv *priv)
return err;
if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- err = ipw2100_set_ibss_beacon_interval(
- priv, priv->beacon_interval, batch_mode);
+ err =
+ ipw2100_set_ibss_beacon_interval(priv,
+ priv->beacon_interval,
+ batch_mode);
if (err)
return err;
@@ -5625,18 +5603,17 @@ static int ipw2100_adapter_setup(struct ipw2100_priv *priv)
}
/*
- err = ipw2100_set_fragmentation_threshold(
- priv, priv->frag_threshold, batch_mode);
- if (err)
- return err;
- */
+ err = ipw2100_set_fragmentation_threshold(
+ priv, priv->frag_threshold, batch_mode);
+ if (err)
+ return err;
+ */
IPW_DEBUG_INFO("exit\n");
return 0;
}
-
/*************************************************************************
*
* EXTERNALLY CALLED METHODS
@@ -5669,7 +5646,7 @@ static int ipw2100_set_address(struct net_device *dev, void *p)
ipw2100_reset_adapter(priv);
return 0;
- done:
+ done:
up(&priv->action_sem);
return err;
}
@@ -5708,7 +5685,7 @@ static int ipw2100_close(struct net_device *dev)
/* Flush the TX queue ... */
while (!list_empty(&priv->tx_pend_list)) {
element = priv->tx_pend_list.next;
- packet = list_entry(element, struct ipw2100_tx_packet, list);
+ packet = list_entry(element, struct ipw2100_tx_packet, list);
list_del(element);
DEC_STAT(&priv->tx_pend_stat);
@@ -5726,8 +5703,6 @@ static int ipw2100_close(struct net_device *dev)
return 0;
}
-
-
/*
* TODO: Fix this function... its just wrong
*/
@@ -5747,7 +5722,6 @@ static void ipw2100_tx_timeout(struct net_device *dev)
schedule_reset(priv);
}
-
/*
* TODO: reimplement it so that it reads statistics
* from the adapter using ordinal tables
@@ -5761,11 +5735,10 @@ static struct net_device_stats *ipw2100_stats(struct net_device *dev)
return &priv->ieee->stats;
}
-/* Support for wpa_supplicant. Will be replaced with WEXT once
- * they get WPA support. */
-#ifdef CONFIG_IEEE80211_WPA
+#if WIRELESS_EXT < 18
+/* Support for wpa_supplicant before WE-18, deprecated. */
-/* following definitions must match definitions in driver_ipw2100.c */
+/* following definitions must match definitions in driver_ipw.c */
#define IPW2100_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30
@@ -5796,25 +5769,26 @@ static struct net_device_stats *ipw2100_stats(struct net_device *dev)
struct ipw2100_param {
u32 cmd;
u8 sta_addr[ETH_ALEN];
- union {
+ union {
struct {
u8 name;
u32 value;
} wpa_param;
struct {
u32 len;
- u8 *data;
+ u8 reserved[32];
+ u8 data[0];
} wpa_ie;
- struct{
- int command;
- int reason_code;
+ struct {
+ u32 command;
+ u32 reason_code;
} mlme;
struct {
u8 alg[IPW2100_CRYPT_ALG_NAME_LEN];
u8 set_tx;
u32 err;
u8 idx;
- u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+ u8 seq[8]; /* sequence counter (set: RX, get: TX) */
u16 key_len;
u8 key[0];
} crypt;
@@ -5822,38 +5796,24 @@ struct ipw2100_param {
} u;
};
-/* end of driver_ipw2100.c code */
-
-static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value){
+/* end of driver_ipw.c code */
+#endif /* WIRELESS_EXT < 18 */
- struct ieee80211_device *ieee = priv->ieee;
- struct ieee80211_security sec = {
- .flags = SEC_LEVEL | SEC_ENABLED,
- };
- int ret = 0;
-
- ieee->wpa_enabled = value;
-
- if (value){
- sec.level = SEC_LEVEL_3;
- sec.enabled = 1;
- } else {
- sec.level = SEC_LEVEL_0;
- sec.enabled = 0;
- }
-
- if (ieee->set_security)
- ieee->set_security(ieee->dev, &sec);
- else
- ret = -EOPNOTSUPP;
-
- return ret;
+static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value)
+{
+ /* This is called when wpa_supplicant loads and closes the driver
+ * interface. */
+ priv->ieee->wpa_enabled = value;
+ return 0;
}
-#define AUTH_ALG_OPEN_SYSTEM 0x1
-#define AUTH_ALG_SHARED_KEY 0x2
+#if WIRELESS_EXT < 18
+#define IW_AUTH_ALG_OPEN_SYSTEM 0x1
+#define IW_AUTH_ALG_SHARED_KEY 0x2
+#endif
-static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value){
+static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value)
+{
struct ieee80211_device *ieee = priv->ieee;
struct ieee80211_security sec = {
@@ -5861,13 +5821,14 @@ static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value){
};
int ret = 0;
- if (value & AUTH_ALG_SHARED_KEY){
+ if (value & IW_AUTH_ALG_SHARED_KEY) {
sec.auth_mode = WLAN_AUTH_SHARED_KEY;
ieee->open_wep = 0;
- } else {
+ } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
sec.auth_mode = WLAN_AUTH_OPEN;
ieee->open_wep = 1;
- }
+ } else
+ return -EINVAL;
if (ieee->set_security)
ieee->set_security(ieee->dev, &sec);
@@ -5877,103 +5838,135 @@ static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value){
return ret;
}
+void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv,
+ char *wpa_ie, int wpa_ie_len)
+{
-static int ipw2100_wpa_set_param(struct net_device *dev, u8 name, u32 value){
-
- struct ipw2100_priv *priv = ieee80211_priv(dev);
- int ret=0;
+ struct ipw2100_wpa_assoc_frame frame;
- switch(name){
- case IPW2100_PARAM_WPA_ENABLED:
- ret = ipw2100_wpa_enable(priv, value);
- break;
+ frame.fixed_ie_mask = 0;
- case IPW2100_PARAM_TKIP_COUNTERMEASURES:
- priv->ieee->tkip_countermeasures=value;
- break;
+ /* copy WPA IE */
+ memcpy(frame.var_ie, wpa_ie, wpa_ie_len);
+ frame.var_ie_len = wpa_ie_len;
- case IPW2100_PARAM_DROP_UNENCRYPTED:
- priv->ieee->drop_unencrypted=value;
- break;
+ /* make sure WPA is enabled */
+ ipw2100_wpa_enable(priv, 1);
+ ipw2100_set_wpa_ie(priv, &frame, 0);
+}
- case IPW2100_PARAM_PRIVACY_INVOKED:
- priv->ieee->privacy_invoked=value;
- break;
+#if WIRELESS_EXT < 18
+static int ipw2100_wpa_set_param(struct net_device *dev, u8 name, u32 value)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ieee80211_crypt_data *crypt;
+ unsigned long flags;
+ int ret = 0;
- case IPW2100_PARAM_AUTH_ALGS:
- ret = ipw2100_wpa_set_auth_algs(priv, value);
- break;
+ switch (name) {
+ case IPW2100_PARAM_WPA_ENABLED:
+ ret = ipw2100_wpa_enable(priv, value);
+ break;
- case IPW2100_PARAM_IEEE_802_1X:
- priv->ieee->ieee802_1x=value;
+ case IPW2100_PARAM_TKIP_COUNTERMEASURES:
+ crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+ if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
break;
- default:
- printk(KERN_ERR DRV_NAME ": %s: Unknown WPA param: %d\n",
- dev->name, name);
- ret = -EOPNOTSUPP;
- }
+ flags = crypt->ops->get_flags(crypt->priv);
- return ret;
-}
+ if (value)
+ flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
+ else
+ flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
-static int ipw2100_wpa_mlme(struct net_device *dev, int command, int reason){
+ crypt->ops->set_flags(flags, crypt->priv);
- struct ipw2100_priv *priv = ieee80211_priv(dev);
- int ret=0;
+ break;
- switch(command){
- case IPW2100_MLME_STA_DEAUTH:
- // silently ignore
+ case IPW2100_PARAM_DROP_UNENCRYPTED:{
+ /* See IW_AUTH_DROP_UNENCRYPTED handling for details */
+ struct ieee80211_security sec = {
+ .flags = SEC_ENABLED,
+ .enabled = value,
+ };
+ priv->ieee->drop_unencrypted = value;
+ /* We only change SEC_LEVEL for open mode. Others
+ * are set by ipw_wpa_set_encryption.
+ */
+ if (!value) {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_0;
+ } else {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_1;
+ }
+ if (priv->ieee->set_security)
+ priv->ieee->set_security(priv->ieee->dev, &sec);
break;
+ }
- case IPW2100_MLME_STA_DISASSOC:
- ipw2100_disassociate_bssid(priv);
- break;
+ case IPW2100_PARAM_PRIVACY_INVOKED:
+ priv->ieee->privacy_invoked = value;
+ break;
- default:
- printk(KERN_ERR DRV_NAME ": %s: Unknown MLME request: %d\n",
- dev->name, command);
- ret = -EOPNOTSUPP;
+ case IPW2100_PARAM_AUTH_ALGS:
+ ret = ipw2100_wpa_set_auth_algs(priv, value);
+ break;
+
+ case IPW2100_PARAM_IEEE_802_1X:
+ priv->ieee->ieee802_1x = value;
+ break;
+
+ default:
+ printk(KERN_ERR DRV_NAME ": %s: Unknown WPA param: %d\n",
+ dev->name, name);
+ ret = -EOPNOTSUPP;
}
return ret;
}
+static int ipw2100_wpa_mlme(struct net_device *dev, int command, int reason)
+{
-void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv,
- char *wpa_ie, int wpa_ie_len){
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ int ret = 0;
- struct ipw2100_wpa_assoc_frame frame;
+ switch (command) {
+ case IPW2100_MLME_STA_DEAUTH:
+ // silently ignore
+ break;
- frame.fixed_ie_mask = 0;
+ case IPW2100_MLME_STA_DISASSOC:
+ ipw2100_disassociate_bssid(priv);
+ break;
- /* copy WPA IE */
- memcpy(frame.var_ie, wpa_ie, wpa_ie_len);
- frame.var_ie_len = wpa_ie_len;
+ default:
+ printk(KERN_ERR DRV_NAME ": %s: Unknown MLME request: %d\n",
+ dev->name, command);
+ ret = -EOPNOTSUPP;
+ }
- /* make sure WPA is enabled */
- ipw2100_wpa_enable(priv, 1);
- ipw2100_set_wpa_ie(priv, &frame, 0);
+ return ret;
}
-
static int ipw2100_wpa_set_wpa_ie(struct net_device *dev,
- struct ipw2100_param *param, int plen){
+ struct ipw2100_param *param, int plen)
+{
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ieee80211_device *ieee = priv->ieee;
u8 *buf;
- if (! ieee->wpa_enabled)
- return -EOPNOTSUPP;
+ if (!ieee->wpa_enabled)
+ return -EOPNOTSUPP;
if (param->u.wpa_ie.len > MAX_WPA_IE_LEN ||
- (param->u.wpa_ie.len &&
- param->u.wpa_ie.data==NULL))
+ (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL))
return -EINVAL;
- if (param->u.wpa_ie.len){
+ if (param->u.wpa_ie.len) {
buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
@@ -5998,8 +5991,9 @@ static int ipw2100_wpa_set_wpa_ie(struct net_device *dev,
/* implementation borrowed from hostap driver */
static int ipw2100_wpa_set_encryption(struct net_device *dev,
- struct ipw2100_param *param, int param_len){
-
+ struct ipw2100_param *param,
+ int param_len)
+{
int ret = 0;
struct ipw2100_priv *priv = ieee80211_priv(dev);
struct ieee80211_device *ieee = priv->ieee;
@@ -6014,9 +6008,10 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev,
param->u.crypt.alg[IPW2100_CRYPT_ALG_NAME_LEN - 1] = '\0';
if (param_len !=
- (int) ((char *) param->u.crypt.key - (char *) param) +
- param->u.crypt.key_len){
- IPW_DEBUG_INFO("Len mismatch %d, %d\n", param_len, param->u.crypt.key_len);
+ (int)((char *)param->u.crypt.key - (char *)param) +
+ param->u.crypt.key_len) {
+ IPW_DEBUG_INFO("Len mismatch %d, %d\n", param_len,
+ param->u.crypt.key_len);
return -EINVAL;
}
if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
@@ -6029,17 +6024,19 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev,
return -EINVAL;
}
+ sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
if (strcmp(param->u.crypt.alg, "none") == 0) {
- if (crypt){
+ if (crypt) {
sec.enabled = 0;
+ sec.encrypt = 0;
sec.level = SEC_LEVEL_0;
- sec.flags |= SEC_ENABLED | SEC_LEVEL;
+ sec.flags |= SEC_LEVEL;
ieee80211_crypt_delayed_deinit(ieee, crypt);
}
goto done;
}
sec.enabled = 1;
- sec.flags |= SEC_ENABLED;
+ sec.encrypt = 1;
ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) {
@@ -6054,7 +6051,7 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev,
}
if (ops == NULL) {
IPW_DEBUG_INFO("%s: unknown crypto alg '%s'\n",
- dev->name, param->u.crypt.alg);
+ dev->name, param->u.crypt.alg);
param->u.crypt.err = IPW2100_CRYPT_ERR_UNKNOWN_ALG;
ret = -EINVAL;
goto done;
@@ -6065,21 +6062,20 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev,
ieee80211_crypt_delayed_deinit(ieee, crypt);
- new_crypt = (struct ieee80211_crypt_data *)
- kmalloc(sizeof(struct ieee80211_crypt_data), GFP_KERNEL);
+ new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data), GFP_KERNEL);
if (new_crypt == NULL) {
ret = -ENOMEM;
goto done;
}
- memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
new_crypt->ops = ops;
if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
- new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx);
+ new_crypt->priv =
+ new_crypt->ops->init(param->u.crypt.idx);
if (new_crypt->priv == NULL) {
kfree(new_crypt);
param->u.crypt.err =
- IPW2100_CRYPT_ERR_CRYPT_INIT_FAILED;
+ IPW2100_CRYPT_ERR_CRYPT_INIT_FAILED;
ret = -EINVAL;
goto done;
}
@@ -6091,24 +6087,25 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev,
(*crypt)->ops->set_key(param->u.crypt.key,
param->u.crypt.key_len, param->u.crypt.seq,
(*crypt)->priv) < 0) {
- IPW_DEBUG_INFO("%s: key setting failed\n",
- dev->name);
+ IPW_DEBUG_INFO("%s: key setting failed\n", dev->name);
param->u.crypt.err = IPW2100_CRYPT_ERR_KEY_SET_FAILED;
ret = -EINVAL;
goto done;
}
- if (param->u.crypt.set_tx){
+ if (param->u.crypt.set_tx) {
ieee->tx_keyidx = param->u.crypt.idx;
sec.active_key = param->u.crypt.idx;
sec.flags |= SEC_ACTIVE_KEY;
}
- if (ops->name != NULL){
+ if (ops->name != NULL) {
if (strcmp(ops->name, "WEP") == 0) {
- memcpy(sec.keys[param->u.crypt.idx], param->u.crypt.key, param->u.crypt.key_len);
- sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len;
+ memcpy(sec.keys[param->u.crypt.idx],
+ param->u.crypt.key, param->u.crypt.key_len);
+ sec.key_sizes[param->u.crypt.idx] =
+ param->u.crypt.key_len;
sec.flags |= (1 << param->u.crypt.idx);
sec.flags |= SEC_LEVEL;
sec.level = SEC_LEVEL_1;
@@ -6120,7 +6117,7 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev,
sec.level = SEC_LEVEL_3;
}
}
- done:
+ done:
if (ieee->set_security)
ieee->set_security(ieee->dev, &sec);
@@ -6131,8 +6128,7 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev,
* the callbacks structures used to initialize the 802.11 stack. */
if (ieee->reset_on_keychange &&
ieee->iw_mode != IW_MODE_INFRA &&
- ieee->reset_port &&
- ieee->reset_port(dev)) {
+ ieee->reset_port && ieee->reset_port(dev)) {
IPW_DEBUG_INFO("%s: reset_port failed\n", dev->name);
param->u.crypt.err = IPW2100_CRYPT_ERR_CARD_CONF_FAILED;
return -EINVAL;
@@ -6141,11 +6137,11 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev,
return ret;
}
-
-static int ipw2100_wpa_supplicant(struct net_device *dev, struct iw_point *p){
+static int ipw2100_wpa_supplicant(struct net_device *dev, struct iw_point *p)
+{
struct ipw2100_param *param;
- int ret=0;
+ int ret = 0;
IPW_DEBUG_IOCTL("wpa_supplicant: len=%d\n", p->length);
@@ -6156,12 +6152,12 @@ static int ipw2100_wpa_supplicant(struct net_device *dev, struct iw_point *p){
if (param == NULL)
return -ENOMEM;
- if (copy_from_user(param, p->pointer, p->length)){
+ if (copy_from_user(param, p->pointer, p->length)) {
kfree(param);
return -EFAULT;
}
- switch (param->cmd){
+ switch (param->cmd) {
case IPW2100_CMD_SET_WPA_PARAM:
ret = ipw2100_wpa_set_param(dev, param->u.wpa_param.name,
@@ -6182,8 +6178,9 @@ static int ipw2100_wpa_supplicant(struct net_device *dev, struct iw_point *p){
break;
default:
- printk(KERN_ERR DRV_NAME ": %s: Unknown WPA supplicant request: %d\n",
- dev->name, param->cmd);
+ printk(KERN_ERR DRV_NAME
+ ": %s: Unknown WPA supplicant request: %d\n", dev->name,
+ param->cmd);
ret = -EOPNOTSUPP;
}
@@ -6194,27 +6191,23 @@ static int ipw2100_wpa_supplicant(struct net_device *dev, struct iw_point *p){
kfree(param);
return ret;
}
-#endif /* CONFIG_IEEE80211_WPA */
static int ipw2100_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
-#ifdef CONFIG_IEEE80211_WPA
- struct iwreq *wrq = (struct iwreq *) rq;
- int ret=-1;
- switch (cmd){
- case IPW2100_IOCTL_WPA_SUPPLICANT:
+ struct iwreq *wrq = (struct iwreq *)rq;
+ int ret = -1;
+ switch (cmd) {
+ case IPW2100_IOCTL_WPA_SUPPLICANT:
ret = ipw2100_wpa_supplicant(dev, &wrq->u.data);
return ret;
- default:
+ default:
return -EOPNOTSUPP;
}
-#endif /* CONFIG_IEEE80211_WPA */
-
return -EOPNOTSUPP;
}
-
+#endif /* WIRELESS_EXT < 18 */
static void ipw_ethtool_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
@@ -6236,14 +6229,13 @@ static void ipw_ethtool_get_drvinfo(struct net_device *dev,
static u32 ipw2100_ethtool_get_link(struct net_device *dev)
{
- struct ipw2100_priv *priv = ieee80211_priv(dev);
- return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
}
-
static struct ethtool_ops ipw2100_ethtool_ops = {
- .get_link = ipw2100_ethtool_get_link,
- .get_drvinfo = ipw_ethtool_get_drvinfo,
+ .get_link = ipw2100_ethtool_get_link,
+ .get_drvinfo = ipw_ethtool_get_drvinfo,
};
static void ipw2100_hang_check(void *adapter)
@@ -6288,7 +6280,6 @@ static void ipw2100_hang_check(void *adapter)
spin_unlock_irqrestore(&priv->low_lock, flags);
}
-
static void ipw2100_rf_kill(void *adapter)
{
struct ipw2100_priv *priv = adapter;
@@ -6313,7 +6304,7 @@ static void ipw2100_rf_kill(void *adapter)
IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still "
"enabled\n");
- exit_unlock:
+ exit_unlock:
spin_unlock_irqrestore(&priv->low_lock, flags);
}
@@ -6321,11 +6312,10 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv);
/* Look into using netdev destructor to shutdown ieee80211? */
-static struct net_device *ipw2100_alloc_device(
- struct pci_dev *pci_dev,
- void __iomem *base_addr,
- unsigned long mem_start,
- unsigned long mem_len)
+static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
+ void __iomem * base_addr,
+ unsigned long mem_start,
+ unsigned long mem_len)
{
struct ipw2100_priv *priv;
struct net_device *dev;
@@ -6341,17 +6331,22 @@ static struct net_device *ipw2100_alloc_device(
priv->ieee->hard_start_xmit = ipw2100_tx;
priv->ieee->set_security = shim__set_security;
+ priv->ieee->perfect_rssi = -20;
+ priv->ieee->worst_rssi = -85;
+
dev->open = ipw2100_open;
dev->stop = ipw2100_close;
dev->init = ipw2100_net_init;
+#if WIRELESS_EXT < 18
dev->do_ioctl = ipw2100_ioctl;
+#endif
dev->get_stats = ipw2100_stats;
dev->ethtool_ops = &ipw2100_ethtool_ops;
dev->tx_timeout = ipw2100_tx_timeout;
dev->wireless_handlers = &ipw2100_wx_handler_def;
dev->get_wireless_stats = ipw2100_wx_wireless_stats;
dev->set_mac_address = ipw2100_set_address;
- dev->watchdog_timeo = 3*HZ;
+ dev->watchdog_timeo = 3 * HZ;
dev->irq = 0;
dev->base_addr = (unsigned long)base_addr;
@@ -6364,22 +6359,19 @@ static struct net_device *ipw2100_alloc_device(
* ends up causing problems. So, we just handle
* the WX extensions through the ipw2100_ioctl interface */
-
/* memset() puts everything to 0, so we only have explicitely set
* those values that need to be something else */
/* If power management is turned on, default to AUTO mode */
priv->power_mode = IPW_POWER_AUTO;
-
-
-#ifdef CONFIG_IEEE80211_WPA
+#ifdef CONFIG_IPW2100_MONITOR
+ priv->config |= CFG_CRC_CHECK;
+#endif
priv->ieee->wpa_enabled = 0;
- priv->ieee->tkip_countermeasures = 0;
priv->ieee->drop_unencrypted = 0;
priv->ieee->privacy_invoked = 0;
priv->ieee->ieee802_1x = 1;
-#endif /* CONFIG_IEEE80211_WPA */
/* Set module parameters */
switch (mode) {
@@ -6401,8 +6393,7 @@ static struct net_device *ipw2100_alloc_device(
priv->status |= STATUS_RF_KILL_SW;
if (channel != 0 &&
- ((channel >= REG_MIN_CHANNEL) &&
- (channel <= REG_MAX_CHANNEL))) {
+ ((channel >= REG_MIN_CHANNEL) && (channel <= REG_MAX_CHANNEL))) {
priv->config |= CFG_STATIC_CHANNEL;
priv->channel = channel;
}
@@ -6441,12 +6432,8 @@ static struct net_device *ipw2100_alloc_device(
INIT_LIST_HEAD(&priv->fw_pend_list);
INIT_STAT(&priv->fw_pend_stat);
-
-#ifdef CONFIG_SOFTWARE_SUSPEND2
- priv->workqueue = create_workqueue(DRV_NAME, 0);
-#else
priv->workqueue = create_workqueue(DRV_NAME);
-#endif
+
INIT_WORK(&priv->reset_work,
(void (*)(void *))ipw2100_reset_adapter, priv);
INIT_WORK(&priv->security_work,
@@ -6535,7 +6522,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
return err;
}
- /* We disable the RETRY_TIMEOUT register (0x41) to keep
+ /* We disable the RETRY_TIMEOUT register (0x41) to keep
* PCI Tx retries from interfering with C3 CPU state */
pci_read_config_dword(pci_dev, 0x40, &val);
if ((val & 0x0000ff00) != 0)
@@ -6566,12 +6553,10 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
ipw2100_queues_initialize(priv);
err = request_irq(pci_dev->irq,
- ipw2100_interrupt, SA_SHIRQ,
- dev->name, priv);
+ ipw2100_interrupt, SA_SHIRQ, dev->name, priv);
if (err) {
printk(KERN_WARNING DRV_NAME
- "Error calling request_irq: %d.\n",
- pci_dev->irq);
+ "Error calling request_irq: %d.\n", pci_dev->irq);
goto fail;
}
dev->irq = pci_dev->irq;
@@ -6606,7 +6591,6 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
/* perform this after register_netdev so that dev->name is set */
sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
- netif_carrier_off(dev);
/* If the RF Kill switch is disabled, go ahead and complete the
* startup sequence */
@@ -6634,10 +6618,10 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
return 0;
- fail_unlock:
+ fail_unlock:
up(&priv->action_sem);
- fail:
+ fail:
if (dev) {
if (registered)
unregister_netdev(dev);
@@ -6653,7 +6637,8 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
/* These are safe to call even if they weren't allocated */
ipw2100_queues_free(priv);
- sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
+ sysfs_remove_group(&pci_dev->dev.kobj,
+ &ipw2100_attribute_group);
free_ieee80211(dev);
pci_set_drvdata(pci_dev, NULL);
@@ -6679,7 +6664,8 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
priv->status &= ~STATUS_INITIALIZED;
dev = priv->net_dev;
- sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
+ sysfs_remove_group(&pci_dev->dev.kobj,
+ &ipw2100_attribute_group);
#ifdef CONFIG_PM
if (ipw2100_firmware.version)
@@ -6721,19 +6707,13 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
IPW_DEBUG_INFO("exit\n");
}
-
#ifdef CONFIG_PM
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
-static int ipw2100_suspend(struct pci_dev *pci_dev, u32 state)
-#else
static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state)
-#endif
{
struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
struct net_device *dev = priv->net_dev;
- IPW_DEBUG_INFO("%s: Going into suspend...\n",
- dev->name);
+ IPW_DEBUG_INFO("%s: Going into suspend...\n", dev->name);
down(&priv->action_sem);
if (priv->status & STATUS_INITIALIZED) {
@@ -6745,7 +6725,7 @@ static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state)
netif_device_detach(dev);
pci_save_state(pci_dev);
- pci_disable_device (pci_dev);
+ pci_disable_device(pci_dev);
pci_set_power_state(pci_dev, PCI_D3hot);
up(&priv->action_sem);
@@ -6764,8 +6744,7 @@ static int ipw2100_resume(struct pci_dev *pci_dev)
down(&priv->action_sem);
- IPW_DEBUG_INFO("%s: Coming out of suspend...\n",
- dev->name);
+ IPW_DEBUG_INFO("%s: Coming out of suspend...\n", dev->name);
pci_set_power_state(pci_dev, PCI_D0);
pci_enable_device(pci_dev);
@@ -6785,9 +6764,9 @@ static int ipw2100_resume(struct pci_dev *pci_dev)
* the queue of needed */
netif_device_attach(dev);
- /* Bring the device back up */
- if (!(priv->status & STATUS_RF_KILL_SW))
- ipw2100_up(priv, 0);
+ /* Bring the device back up */
+ if (!(priv->status & STATUS_RF_KILL_SW))
+ ipw2100_up(priv, 0);
up(&priv->action_sem);
@@ -6795,56 +6774,55 @@ static int ipw2100_resume(struct pci_dev *pci_dev)
}
#endif
-
#define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x }
static struct pci_device_id ipw2100_pci_id_table[] __devinitdata = {
- IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */
- IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */
- IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */
- IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */
- IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */
- IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */
- IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */
-
- IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */
-
- IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */
- IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */
- IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */
- IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */
- IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */
- IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */
- IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */
-
- IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */
-
- IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */
-
- IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */
-
- IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */
+ IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */
+ IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */
+ IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */
+ IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */
+ IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */
+
+ IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */
+
+ IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */
+ IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */
+ IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */
+ IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */
+ IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */
+ IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */
+ IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */
+
+ IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */
+
+ IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */
+
+ IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */
+ IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */
+ IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */
+
+ IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */
{0,},
};
@@ -6861,7 +6839,6 @@ static struct pci_driver ipw2100_pci_driver = {
#endif
};
-
/**
* Initialize the ipw2100 driver/module
*
@@ -6878,10 +6855,6 @@ static int __init ipw2100_init(void)
printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
-#ifdef CONFIG_IEEE80211_NOWEP
- IPW_DEBUG_INFO(DRV_NAME ": Compiled with WEP disabled.\n");
-#endif
-
ret = pci_module_init(&ipw2100_pci_driver);
#ifdef CONFIG_IPW_DEBUG
@@ -6893,7 +6866,6 @@ static int __init ipw2100_init(void)
return ret;
}
-
/**
* Cleanup ipw2100 driver registration
*/
@@ -6949,7 +6921,6 @@ static int ipw2100_wx_get_name(struct net_device *dev,
return 0;
}
-
static int ipw2100_wx_set_freq(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
@@ -6969,8 +6940,7 @@ static int ipw2100_wx_set_freq(struct net_device *dev,
/* if setting by freq convert to channel */
if (fwrq->e == 1) {
- if ((fwrq->m >= (int) 2.412e8 &&
- fwrq->m <= (int) 2.487e8)) {
+ if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) {
int f = fwrq->m / 100000;
int c = 0;
@@ -6984,19 +6954,19 @@ static int ipw2100_wx_set_freq(struct net_device *dev,
}
}
- if (fwrq->e > 0 || fwrq->m > 1000)
- return -EOPNOTSUPP;
- else { /* Set the channel */
+ if (fwrq->e > 0 || fwrq->m > 1000) {
+ err = -EOPNOTSUPP;
+ goto done;
+ } else { /* Set the channel */
IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m);
err = ipw2100_set_channel(priv, fwrq->m, 0);
}
- done:
+ done:
up(&priv->action_sem);
return err;
}
-
static int ipw2100_wx_get_freq(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
@@ -7045,7 +7015,7 @@ static int ipw2100_wx_set_mode(struct net_device *dev,
case IW_MODE_MONITOR:
err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
break;
-#endif /* CONFIG_IPW2100_MONITOR */
+#endif /* CONFIG_IPW2100_MONITOR */
case IW_MODE_ADHOC:
err = ipw2100_switch_mode(priv, IW_MODE_ADHOC);
break;
@@ -7056,9 +7026,9 @@ static int ipw2100_wx_set_mode(struct net_device *dev,
break;
}
-done:
+ done:
up(&priv->action_sem);
- return err;
+ return err;
}
static int ipw2100_wx_get_mode(struct net_device *dev,
@@ -7077,7 +7047,6 @@ static int ipw2100_wx_get_mode(struct net_device *dev,
return 0;
}
-
#define POWER_MODES 5
/* Values are in microsecond */
@@ -7124,19 +7093,19 @@ static int ipw2100_wx_get_range(struct net_device *dev,
/* ~5 Mb/s real (802.11b) */
range->throughput = 5 * 1000 * 1000;
-// range->sensitivity; /* signal level threshold range */
+// range->sensitivity; /* signal level threshold range */
range->max_qual.qual = 100;
/* TODO: Find real max RSSI and stick here */
range->max_qual.level = 0;
range->max_qual.noise = 0;
- range->max_qual.updated = 7; /* Updated all three */
+ range->max_qual.updated = 7; /* Updated all three */
- range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */
+ range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */
/* TODO: Find real 'good' to 'bad' threshol value for RSSI */
range->avg_qual.level = 20 + IPW2100_RSSI_TO_DBM;
range->avg_qual.noise = 0;
- range->avg_qual.updated = 7; /* Updated all three */
+ range->avg_qual.updated = 7; /* Updated all three */
range->num_bitrates = RATE_COUNT;
@@ -7150,61 +7119,62 @@ static int ipw2100_wx_get_range(struct net_device *dev,
range->max_frag = MAX_FRAG_THRESHOLD;
range->min_pmp = period_duration[0]; /* Minimal PM period */
- range->max_pmp = period_duration[POWER_MODES-1];/* Maximal PM period */
- range->min_pmt = timeout_duration[POWER_MODES-1]; /* Minimal PM timeout */
- range->max_pmt = timeout_duration[0];/* Maximal PM timeout */
+ range->max_pmp = period_duration[POWER_MODES - 1]; /* Maximal PM period */
+ range->min_pmt = timeout_duration[POWER_MODES - 1]; /* Minimal PM timeout */
+ range->max_pmt = timeout_duration[0]; /* Maximal PM timeout */
- /* How to decode max/min PM period */
+ /* How to decode max/min PM period */
range->pmp_flags = IW_POWER_PERIOD;
- /* How to decode max/min PM period */
+ /* How to decode max/min PM period */
range->pmt_flags = IW_POWER_TIMEOUT;
/* What PM options are supported */
range->pm_capa = IW_POWER_TIMEOUT | IW_POWER_PERIOD;
range->encoding_size[0] = 5;
- range->encoding_size[1] = 13; /* Different token sizes */
- range->num_encoding_sizes = 2; /* Number of entry in the list */
- range->max_encoding_tokens = WEP_KEYS; /* Max number of tokens */
-// range->encoding_login_index; /* token index for login token */
+ range->encoding_size[1] = 13; /* Different token sizes */
+ range->num_encoding_sizes = 2; /* Number of entry in the list */
+ range->max_encoding_tokens = WEP_KEYS; /* Max number of tokens */
+// range->encoding_login_index; /* token index for login token */
if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
range->txpower_capa = IW_TXPOW_DBM;
range->num_txpower = IW_MAX_TXPOWER;
- for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16); i < IW_MAX_TXPOWER;
- i++, level -= ((IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM) * 16) /
- (IW_MAX_TXPOWER - 1))
+ for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16);
+ i < IW_MAX_TXPOWER;
+ i++, level -=
+ ((IPW_TX_POWER_MAX_DBM -
+ IPW_TX_POWER_MIN_DBM) * 16) / (IW_MAX_TXPOWER - 1))
range->txpower[i] = level / 16;
} else {
range->txpower_capa = 0;
range->num_txpower = 0;
}
-
/* Set the Wireless Extension versions */
range->we_version_compiled = WIRELESS_EXT;
range->we_version_source = 16;
-// range->retry_capa; /* What retry options are supported */
-// range->retry_flags; /* How to decode max/min retry limit */
-// range->r_time_flags; /* How to decode max/min retry life */
-// range->min_retry; /* Minimal number of retries */
-// range->max_retry; /* Maximal number of retries */
-// range->min_r_time; /* Minimal retry lifetime */
-// range->max_r_time; /* Maximal retry lifetime */
+// range->retry_capa; /* What retry options are supported */
+// range->retry_flags; /* How to decode max/min retry limit */
+// range->r_time_flags; /* How to decode max/min retry life */
+// range->min_retry; /* Minimal number of retries */
+// range->max_retry; /* Maximal number of retries */
+// range->min_r_time; /* Minimal retry lifetime */
+// range->max_r_time; /* Maximal retry lifetime */
- range->num_channels = FREQ_COUNT;
+ range->num_channels = FREQ_COUNT;
val = 0;
for (i = 0; i < FREQ_COUNT; i++) {
// TODO: Include only legal frequencies for some countries
-// if (local->channel_mask & (1 << i)) {
- range->freq[val].i = i + 1;
- range->freq[val].m = ipw2100_frequencies[i] * 100000;
- range->freq[val].e = 1;
- val++;
-// }
+// if (local->channel_mask & (1 << i)) {
+ range->freq[val].i = i + 1;
+ range->freq[val].m = ipw2100_frequencies[i] * 100000;
+ range->freq[val].e = 1;
+ val++;
+// }
if (val == IW_MAX_FREQUENCIES)
- break;
+ break;
}
range->num_frequency = val;
@@ -7259,7 +7229,7 @@ static int ipw2100_wx_set_wap(struct net_device *dev,
wrqu->ap_addr.sa_data[4] & 0xff,
wrqu->ap_addr.sa_data[5] & 0xff);
- done:
+ done:
up(&priv->action_sem);
return err;
}
@@ -7276,10 +7246,9 @@ static int ipw2100_wx_get_wap(struct net_device *dev,
/* If we are associated, trying to associate, or have a statically
* configured BSSID then return that; otherwise return ANY */
- if (priv->config & CFG_STATIC_BSSID ||
- priv->status & STATUS_ASSOCIATED) {
+ if (priv->config & CFG_STATIC_BSSID || priv->status & STATUS_ASSOCIATED) {
wrqu->ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(wrqu->ap_addr.sa_data, &priv->bssid, ETH_ALEN);
+ memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN);
} else
memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
@@ -7293,7 +7262,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
- char *essid = ""; /* ANY */
+ char *essid = ""; /* ANY */
int length = 0;
int err = 0;
@@ -7333,7 +7302,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev,
err = ipw2100_set_essid(priv, essid, length, 0);
- done:
+ done:
up(&priv->action_sem);
return err;
}
@@ -7350,17 +7319,16 @@ static int ipw2100_wx_get_essid(struct net_device *dev,
/* If we are associated, trying to associate, or have a statically
* configured ESSID then return that; otherwise return ANY */
- if (priv->config & CFG_STATIC_ESSID ||
- priv->status & STATUS_ASSOCIATED) {
+ if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) {
IPW_DEBUG_WX("Getting essid: '%s'\n",
escape_essid(priv->essid, priv->essid_len));
memcpy(extra, priv->essid, priv->essid_len);
wrqu->essid.length = priv->essid_len;
- wrqu->essid.flags = 1; /* active */
+ wrqu->essid.flags = 1; /* active */
} else {
IPW_DEBUG_WX("Getting essid: ANY\n");
wrqu->essid.length = 0;
- wrqu->essid.flags = 0; /* active */
+ wrqu->essid.flags = 0; /* active */
}
return 0;
@@ -7379,9 +7347,9 @@ static int ipw2100_wx_set_nick(struct net_device *dev,
if (wrqu->data.length > IW_ESSID_MAX_SIZE)
return -E2BIG;
- wrqu->data.length = min((size_t)wrqu->data.length, sizeof(priv->nick));
+ wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
memset(priv->nick, 0, sizeof(priv->nick));
- memcpy(priv->nick, extra, wrqu->data.length);
+ memcpy(priv->nick, extra, wrqu->data.length);
IPW_DEBUG_WX("SET Nickname -> %s \n", priv->nick);
@@ -7400,7 +7368,7 @@ static int ipw2100_wx_get_nick(struct net_device *dev,
wrqu->data.length = strlen(priv->nick) + 1;
memcpy(extra, priv->nick, wrqu->data.length);
- wrqu->data.flags = 1; /* active */
+ wrqu->data.flags = 1; /* active */
IPW_DEBUG_WX("GET Nickname -> %s \n", extra);
@@ -7442,12 +7410,11 @@ static int ipw2100_wx_set_rate(struct net_device *dev,
err = ipw2100_set_tx_rates(priv, rate, 0);
IPW_DEBUG_WX("SET Rate -> %04X \n", rate);
- done:
+ done:
up(&priv->action_sem);
return err;
}
-
static int ipw2100_wx_get_rate(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
@@ -7495,7 +7462,7 @@ static int ipw2100_wx_get_rate(struct net_device *dev,
IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value);
- done:
+ done:
up(&priv->action_sem);
return err;
}
@@ -7520,8 +7487,7 @@ static int ipw2100_wx_set_rts(struct net_device *dev,
if (wrqu->rts.disabled)
value = priv->rts_threshold | RTS_DISABLED;
else {
- if (wrqu->rts.value < 1 ||
- wrqu->rts.value > 2304) {
+ if (wrqu->rts.value < 1 || wrqu->rts.value > 2304) {
err = -EINVAL;
goto done;
}
@@ -7531,7 +7497,7 @@ static int ipw2100_wx_set_rts(struct net_device *dev,
err = ipw2100_set_rts_threshold(priv, value);
IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X \n", value);
- done:
+ done:
up(&priv->action_sem);
return err;
}
@@ -7547,7 +7513,7 @@ static int ipw2100_wx_get_rts(struct net_device *dev,
struct ipw2100_priv *priv = ieee80211_priv(dev);
wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED;
- wrqu->rts.fixed = 1; /* no auto select */
+ wrqu->rts.fixed = 1; /* no auto select */
/* If RTS is set to the default value, then it is disabled */
wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0;
@@ -7574,8 +7540,7 @@ static int ipw2100_wx_set_txpow(struct net_device *dev,
wrqu->txpower.value > IPW_TX_POWER_MAX_DBM)
return -EINVAL;
- value = (wrqu->txpower.value - IPW_TX_POWER_MIN_DBM) * 16 /
- (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM);
+ value = wrqu->txpower.value;
}
down(&priv->action_sem);
@@ -7588,7 +7553,7 @@ static int ipw2100_wx_set_txpow(struct net_device *dev,
IPW_DEBUG_WX("SET TX Power -> %d \n", value);
- done:
+ done:
up(&priv->action_sem);
return err;
}
@@ -7615,11 +7580,7 @@ static int ipw2100_wx_get_txpow(struct net_device *dev,
} else {
wrqu->power.disabled = 0;
wrqu->power.fixed = 1;
- wrqu->power.value =
- (priv->tx_power *
- (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM)) /
- (IPW_TX_POWER_MAX - IPW_TX_POWER_MIN) +
- IPW_TX_POWER_MIN_DBM;
+ wrqu->power.value = priv->tx_power;
}
wrqu->power.flags = IW_TXPOW_DBM;
@@ -7684,8 +7645,7 @@ static int ipw2100_wx_set_retry(struct net_device *dev,
struct ipw2100_priv *priv = ieee80211_priv(dev);
int err = 0;
- if (wrqu->retry.flags & IW_RETRY_LIFETIME ||
- wrqu->retry.disabled)
+ if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
return -EINVAL;
if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
@@ -7700,14 +7660,14 @@ static int ipw2100_wx_set_retry(struct net_device *dev,
if (wrqu->retry.flags & IW_RETRY_MIN) {
err = ipw2100_set_short_retry(priv, wrqu->retry.value);
IPW_DEBUG_WX("SET Short Retry Limit -> %d \n",
- wrqu->retry.value);
+ wrqu->retry.value);
goto done;
}
if (wrqu->retry.flags & IW_RETRY_MAX) {
err = ipw2100_set_long_retry(priv, wrqu->retry.value);
IPW_DEBUG_WX("SET Long Retry Limit -> %d \n",
- wrqu->retry.value);
+ wrqu->retry.value);
goto done;
}
@@ -7717,7 +7677,7 @@ static int ipw2100_wx_set_retry(struct net_device *dev,
IPW_DEBUG_WX("SET Both Retry Limits -> %d \n", wrqu->retry.value);
- done:
+ done:
up(&priv->action_sem);
return err;
}
@@ -7732,20 +7692,19 @@ static int ipw2100_wx_get_retry(struct net_device *dev,
struct ipw2100_priv *priv = ieee80211_priv(dev);
- wrqu->retry.disabled = 0; /* can't be disabled */
+ wrqu->retry.disabled = 0; /* can't be disabled */
- if ((wrqu->retry.flags & IW_RETRY_TYPE) ==
- IW_RETRY_LIFETIME)
+ if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
return -EINVAL;
if (wrqu->retry.flags & IW_RETRY_MAX) {
- wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MAX;
+ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
wrqu->retry.value = priv->long_retry_limit;
} else {
wrqu->retry.flags =
(priv->short_retry_limit !=
priv->long_retry_limit) ?
- IW_RETRY_LIMIT & IW_RETRY_MIN : IW_RETRY_LIMIT;
+ IW_RETRY_LIMIT | IW_RETRY_MIN : IW_RETRY_LIMIT;
wrqu->retry.value = priv->short_retry_limit;
}
@@ -7769,15 +7728,14 @@ static int ipw2100_wx_set_scan(struct net_device *dev,
}
IPW_DEBUG_WX("Initiating scan...\n");
- if (ipw2100_set_scan_options(priv) ||
- ipw2100_start_scan(priv)) {
+ if (ipw2100_set_scan_options(priv) || ipw2100_start_scan(priv)) {
IPW_DEBUG_WX("Start scan failed.\n");
/* TODO: Mark a scan as pending so when hardware initialized
* a scan starts */
}
- done:
+ done:
up(&priv->action_sem);
return err;
}
@@ -7794,7 +7752,6 @@ static int ipw2100_wx_get_scan(struct net_device *dev,
return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra);
}
-
/*
* Implementation based on code in hostap-driver v0.1.3 hostap_ioctl.c
*/
@@ -7823,8 +7780,8 @@ static int ipw2100_wx_get_encode(struct net_device *dev,
}
static int ipw2100_wx_set_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
{
struct ipw2100_priv *priv = ieee80211_priv(dev);
int err = 0;
@@ -7843,11 +7800,11 @@ static int ipw2100_wx_set_power(struct net_device *dev,
}
switch (wrqu->power.flags & IW_POWER_MODE) {
- case IW_POWER_ON: /* If not specified */
- case IW_POWER_MODE: /* If set all mask */
- case IW_POWER_ALL_R: /* If explicitely state all */
+ case IW_POWER_ON: /* If not specified */
+ case IW_POWER_MODE: /* If set all mask */
+ case IW_POWER_ALL_R: /* If explicitely state all */
break;
- default: /* Otherwise we don't support it */
+ default: /* Otherwise we don't support it */
IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
wrqu->power.flags);
err = -EOPNOTSUPP;
@@ -7859,18 +7816,17 @@ static int ipw2100_wx_set_power(struct net_device *dev,
priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
err = ipw2100_set_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
- IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n",
- priv->power_mode);
+ IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
- done:
+ done:
up(&priv->action_sem);
return err;
}
static int ipw2100_wx_get_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
{
/*
* This can be called at any time. No action lock required
@@ -7878,9 +7834,9 @@ static int ipw2100_wx_get_power(struct net_device *dev,
struct ipw2100_priv *priv = ieee80211_priv(dev);
- if (!(priv->power_mode & IPW_POWER_ENABLED)) {
+ if (!(priv->power_mode & IPW_POWER_ENABLED))
wrqu->power.disabled = 1;
- } else {
+ else {
wrqu->power.disabled = 0;
wrqu->power.flags = 0;
}
@@ -7890,6 +7846,269 @@ static int ipw2100_wx_get_power(struct net_device *dev,
return 0;
}
+#if WIRELESS_EXT > 17
+/*
+ * WE-18 WPA support
+ */
+
+/* SIOCSIWGENIE */
+static int ipw2100_wx_set_genie(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ieee80211_device *ieee = priv->ieee;
+ u8 *buf;
+
+ if (!ieee->wpa_enabled)
+ return -EOPNOTSUPP;
+
+ if (wrqu->data.length > MAX_WPA_IE_LEN ||
+ (wrqu->data.length && extra == NULL))
+ return -EINVAL;
+
+ if (wrqu->data.length) {
+ buf = kmalloc(wrqu->data.length, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ memcpy(buf, extra, wrqu->data.length);
+ kfree(ieee->wpa_ie);
+ ieee->wpa_ie = buf;
+ ieee->wpa_ie_len = wrqu->data.length;
+ } else {
+ kfree(ieee->wpa_ie);
+ ieee->wpa_ie = NULL;
+ ieee->wpa_ie_len = 0;
+ }
+
+ ipw2100_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
+
+ return 0;
+}
+
+/* SIOCGIWGENIE */
+static int ipw2100_wx_get_genie(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ieee80211_device *ieee = priv->ieee;
+
+ if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
+ wrqu->data.length = 0;
+ return 0;
+ }
+
+ if (wrqu->data.length < ieee->wpa_ie_len)
+ return -E2BIG;
+
+ wrqu->data.length = ieee->wpa_ie_len;
+ memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
+
+ return 0;
+}
+
+/* SIOCSIWAUTH */
+static int ipw2100_wx_set_auth(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ieee80211_device *ieee = priv->ieee;
+ struct iw_param *param = &wrqu->param;
+ struct ieee80211_crypt_data *crypt;
+ unsigned long flags;
+ int ret = 0;
+
+ switch (param->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_WPA_VERSION:
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ case IW_AUTH_KEY_MGMT:
+ /*
+ * ipw2200 does not use these parameters
+ */
+ break;
+
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+ if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
+ break;
+
+ flags = crypt->ops->get_flags(crypt->priv);
+
+ if (param->value)
+ flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
+ else
+ flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
+
+ crypt->ops->set_flags(flags, crypt->priv);
+
+ break;
+
+ case IW_AUTH_DROP_UNENCRYPTED:{
+ /* HACK:
+ *
+ * wpa_supplicant calls set_wpa_enabled when the driver
+ * is loaded and unloaded, regardless of if WPA is being
+ * used. No other calls are made which can be used to
+ * determine if encryption will be used or not prior to
+ * association being expected. If encryption is not being
+ * used, drop_unencrypted is set to false, else true -- we
+ * can use this to determine if the CAP_PRIVACY_ON bit should
+ * be set.
+ */
+ struct ieee80211_security sec = {
+ .flags = SEC_ENABLED,
+ .enabled = param->value,
+ };
+ priv->ieee->drop_unencrypted = param->value;
+ /* We only change SEC_LEVEL for open mode. Others
+ * are set by ipw_wpa_set_encryption.
+ */
+ if (!param->value) {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_0;
+ } else {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_1;
+ }
+ if (priv->ieee->set_security)
+ priv->ieee->set_security(priv->ieee->dev, &sec);
+ break;
+ }
+
+ case IW_AUTH_80211_AUTH_ALG:
+ ret = ipw2100_wpa_set_auth_algs(priv, param->value);
+ break;
+
+ case IW_AUTH_WPA_ENABLED:
+ ret = ipw2100_wpa_enable(priv, param->value);
+ break;
+
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ ieee->ieee802_1x = param->value;
+ break;
+
+ //case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ ieee->privacy_invoked = param->value;
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+ return ret;
+}
+
+/* SIOCGIWAUTH */
+static int ipw2100_wx_get_auth(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct ieee80211_device *ieee = priv->ieee;
+ struct ieee80211_crypt_data *crypt;
+ struct iw_param *param = &wrqu->param;
+ int ret = 0;
+
+ switch (param->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_WPA_VERSION:
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ case IW_AUTH_KEY_MGMT:
+ /*
+ * wpa_supplicant will control these internally
+ */
+ ret = -EOPNOTSUPP;
+ break;
+
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+ if (!crypt || !crypt->ops->get_flags) {
+ IPW_DEBUG_WARNING("Can't get TKIP countermeasures: "
+ "crypt not set!\n");
+ break;
+ }
+
+ param->value = (crypt->ops->get_flags(crypt->priv) &
+ IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0;
+
+ break;
+
+ case IW_AUTH_DROP_UNENCRYPTED:
+ param->value = ieee->drop_unencrypted;
+ break;
+
+ case IW_AUTH_80211_AUTH_ALG:
+ param->value = priv->ieee->sec.auth_mode;
+ break;
+
+ case IW_AUTH_WPA_ENABLED:
+ param->value = ieee->wpa_enabled;
+ break;
+
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ param->value = ieee->ieee802_1x;
+ break;
+
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ param->value = ieee->privacy_invoked;
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+/* SIOCSIWENCODEEXT */
+static int ipw2100_wx_set_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra);
+}
+
+/* SIOCGIWENCODEEXT */
+static int ipw2100_wx_get_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra);
+}
+
+/* SIOCSIWMLME */
+static int ipw2100_wx_set_mlme(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ struct iw_mlme *mlme = (struct iw_mlme *)extra;
+ u16 reason;
+
+ reason = cpu_to_le16(mlme->reason_code);
+
+ switch (mlme->cmd) {
+ case IW_MLME_DEAUTH:
+ // silently ignore
+ break;
+
+ case IW_MLME_DISASSOC:
+ ipw2100_disassociate_bssid(priv);
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+#endif /* WIRELESS_EXT > 17 */
/*
*
@@ -7923,7 +8142,7 @@ static int ipw2100_wx_set_promisc(struct net_device *dev,
if (priv->ieee->iw_mode == IW_MODE_MONITOR)
err = ipw2100_switch_mode(priv, priv->last_mode);
}
- done:
+ done:
up(&priv->action_sem);
return err;
}
@@ -7958,7 +8177,7 @@ static int ipw2100_wx_set_powermode(struct net_device *dev,
if (priv->power_mode != mode)
err = ipw2100_set_power_mode(priv, mode);
- done:
+ done:
up(&priv->action_sem);
return err;
}
@@ -7986,8 +8205,8 @@ static int ipw2100_wx_get_powermode(struct net_device *dev,
"Power save level: %d (None)", level);
break;
case IPW_POWER_AUTO:
- snprintf(extra, MAX_POWER_STRING,
- "Power save level: %d (Auto)", 0);
+ snprintf(extra, MAX_POWER_STRING,
+ "Power save level: %d (Auto)", 0);
break;
default:
timeout = timeout_duration[level - 1] / 1000;
@@ -8004,7 +8223,6 @@ static int ipw2100_wx_get_powermode(struct net_device *dev,
return 0;
}
-
static int ipw2100_wx_set_preamble(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
@@ -8029,14 +8247,14 @@ static int ipw2100_wx_set_preamble(struct net_device *dev,
err = ipw2100_system_config(priv, 0);
-done:
+ done:
up(&priv->action_sem);
return err;
}
static int ipw2100_wx_get_preamble(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
{
/*
* This can be called at any time. No action lock required
@@ -8052,54 +8270,116 @@ static int ipw2100_wx_get_preamble(struct net_device *dev,
return 0;
}
-static iw_handler ipw2100_wx_handlers[] =
-{
- NULL, /* SIOCSIWCOMMIT */
- ipw2100_wx_get_name, /* SIOCGIWNAME */
- NULL, /* SIOCSIWNWID */
- NULL, /* SIOCGIWNWID */
- ipw2100_wx_set_freq, /* SIOCSIWFREQ */
- ipw2100_wx_get_freq, /* SIOCGIWFREQ */
- ipw2100_wx_set_mode, /* SIOCSIWMODE */
- ipw2100_wx_get_mode, /* SIOCGIWMODE */
- NULL, /* SIOCSIWSENS */
- NULL, /* SIOCGIWSENS */
- NULL, /* SIOCSIWRANGE */
- ipw2100_wx_get_range, /* SIOCGIWRANGE */
- NULL, /* SIOCSIWPRIV */
- NULL, /* SIOCGIWPRIV */
- NULL, /* SIOCSIWSTATS */
- NULL, /* SIOCGIWSTATS */
- NULL, /* SIOCSIWSPY */
- NULL, /* SIOCGIWSPY */
- NULL, /* SIOCGIWTHRSPY */
- NULL, /* SIOCWIWTHRSPY */
- ipw2100_wx_set_wap, /* SIOCSIWAP */
- ipw2100_wx_get_wap, /* SIOCGIWAP */
- NULL, /* -- hole -- */
- NULL, /* SIOCGIWAPLIST -- deprecated */
- ipw2100_wx_set_scan, /* SIOCSIWSCAN */
- ipw2100_wx_get_scan, /* SIOCGIWSCAN */
- ipw2100_wx_set_essid, /* SIOCSIWESSID */
- ipw2100_wx_get_essid, /* SIOCGIWESSID */
- ipw2100_wx_set_nick, /* SIOCSIWNICKN */
- ipw2100_wx_get_nick, /* SIOCGIWNICKN */
- NULL, /* -- hole -- */
- NULL, /* -- hole -- */
- ipw2100_wx_set_rate, /* SIOCSIWRATE */
- ipw2100_wx_get_rate, /* SIOCGIWRATE */
- ipw2100_wx_set_rts, /* SIOCSIWRTS */
- ipw2100_wx_get_rts, /* SIOCGIWRTS */
- ipw2100_wx_set_frag, /* SIOCSIWFRAG */
- ipw2100_wx_get_frag, /* SIOCGIWFRAG */
- ipw2100_wx_set_txpow, /* SIOCSIWTXPOW */
- ipw2100_wx_get_txpow, /* SIOCGIWTXPOW */
- ipw2100_wx_set_retry, /* SIOCSIWRETRY */
- ipw2100_wx_get_retry, /* SIOCGIWRETRY */
- ipw2100_wx_set_encode, /* SIOCSIWENCODE */
- ipw2100_wx_get_encode, /* SIOCGIWENCODE */
- ipw2100_wx_set_power, /* SIOCSIWPOWER */
- ipw2100_wx_get_power, /* SIOCGIWPOWER */
+#ifdef CONFIG_IPW2100_MONITOR
+static int ipw2100_wx_set_crc_check(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+ int err, mode = *(int *)extra;
+
+ down(&priv->action_sem);
+ if (!(priv->status & STATUS_INITIALIZED)) {
+ err = -EIO;
+ goto done;
+ }
+
+ if (mode == 1)
+ priv->config |= CFG_CRC_CHECK;
+ else if (mode == 0)
+ priv->config &= ~CFG_CRC_CHECK;
+ else {
+ err = -EINVAL;
+ goto done;
+ }
+ err = 0;
+
+ done:
+ up(&priv->action_sem);
+ return err;
+}
+
+static int ipw2100_wx_get_crc_check(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /*
+ * This can be called at any time. No action lock required
+ */
+
+ struct ipw2100_priv *priv = ieee80211_priv(dev);
+
+ if (priv->config & CFG_CRC_CHECK)
+ snprintf(wrqu->name, IFNAMSIZ, "CRC checked (1)");
+ else
+ snprintf(wrqu->name, IFNAMSIZ, "CRC ignored (0)");
+
+ return 0;
+}
+#endif /* CONFIG_IPW2100_MONITOR */
+
+static iw_handler ipw2100_wx_handlers[] = {
+ NULL, /* SIOCSIWCOMMIT */
+ ipw2100_wx_get_name, /* SIOCGIWNAME */
+ NULL, /* SIOCSIWNWID */
+ NULL, /* SIOCGIWNWID */
+ ipw2100_wx_set_freq, /* SIOCSIWFREQ */
+ ipw2100_wx_get_freq, /* SIOCGIWFREQ */
+ ipw2100_wx_set_mode, /* SIOCSIWMODE */
+ ipw2100_wx_get_mode, /* SIOCGIWMODE */
+ NULL, /* SIOCSIWSENS */
+ NULL, /* SIOCGIWSENS */
+ NULL, /* SIOCSIWRANGE */
+ ipw2100_wx_get_range, /* SIOCGIWRANGE */
+ NULL, /* SIOCSIWPRIV */
+ NULL, /* SIOCGIWPRIV */
+ NULL, /* SIOCSIWSTATS */
+ NULL, /* SIOCGIWSTATS */
+ NULL, /* SIOCSIWSPY */
+ NULL, /* SIOCGIWSPY */
+ NULL, /* SIOCGIWTHRSPY */
+ NULL, /* SIOCWIWTHRSPY */
+ ipw2100_wx_set_wap, /* SIOCSIWAP */
+ ipw2100_wx_get_wap, /* SIOCGIWAP */
+#if WIRELESS_EXT > 17
+ ipw2100_wx_set_mlme, /* SIOCSIWMLME */
+#else
+ NULL, /* -- hole -- */
+#endif
+ NULL, /* SIOCGIWAPLIST -- deprecated */
+ ipw2100_wx_set_scan, /* SIOCSIWSCAN */
+ ipw2100_wx_get_scan, /* SIOCGIWSCAN */
+ ipw2100_wx_set_essid, /* SIOCSIWESSID */
+ ipw2100_wx_get_essid, /* SIOCGIWESSID */
+ ipw2100_wx_set_nick, /* SIOCSIWNICKN */
+ ipw2100_wx_get_nick, /* SIOCGIWNICKN */
+ NULL, /* -- hole -- */
+ NULL, /* -- hole -- */
+ ipw2100_wx_set_rate, /* SIOCSIWRATE */
+ ipw2100_wx_get_rate, /* SIOCGIWRATE */
+ ipw2100_wx_set_rts, /* SIOCSIWRTS */
+ ipw2100_wx_get_rts, /* SIOCGIWRTS */
+ ipw2100_wx_set_frag, /* SIOCSIWFRAG */
+ ipw2100_wx_get_frag, /* SIOCGIWFRAG */
+ ipw2100_wx_set_txpow, /* SIOCSIWTXPOW */
+ ipw2100_wx_get_txpow, /* SIOCGIWTXPOW */
+ ipw2100_wx_set_retry, /* SIOCSIWRETRY */
+ ipw2100_wx_get_retry, /* SIOCGIWRETRY */
+ ipw2100_wx_set_encode, /* SIOCSIWENCODE */
+ ipw2100_wx_get_encode, /* SIOCGIWENCODE */
+ ipw2100_wx_set_power, /* SIOCSIWPOWER */
+ ipw2100_wx_get_power, /* SIOCGIWPOWER */
+#if WIRELESS_EXT > 17
+ NULL, /* -- hole -- */
+ NULL, /* -- hole -- */
+ ipw2100_wx_set_genie, /* SIOCSIWGENIE */
+ ipw2100_wx_get_genie, /* SIOCGIWGENIE */
+ ipw2100_wx_set_auth, /* SIOCSIWAUTH */
+ ipw2100_wx_get_auth, /* SIOCGIWAUTH */
+ ipw2100_wx_set_encodeext, /* SIOCSIWENCODEEXT */
+ ipw2100_wx_get_encodeext, /* SIOCGIWENCODEEXT */
+ NULL, /* SIOCSIWPMKSA */
+#endif
};
#define IPW2100_PRIV_SET_MONITOR SIOCIWFIRSTPRIV
@@ -8108,60 +8388,71 @@ static iw_handler ipw2100_wx_handlers[] =
#define IPW2100_PRIV_GET_POWER SIOCIWFIRSTPRIV+3
#define IPW2100_PRIV_SET_LONGPREAMBLE SIOCIWFIRSTPRIV+4
#define IPW2100_PRIV_GET_LONGPREAMBLE SIOCIWFIRSTPRIV+5
+#define IPW2100_PRIV_SET_CRC_CHECK SIOCIWFIRSTPRIV+6
+#define IPW2100_PRIV_GET_CRC_CHECK SIOCIWFIRSTPRIV+7
static const struct iw_priv_args ipw2100_private_args[] = {
#ifdef CONFIG_IPW2100_MONITOR
{
- IPW2100_PRIV_SET_MONITOR,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"
- },
+ IPW2100_PRIV_SET_MONITOR,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
{
- IPW2100_PRIV_RESET,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"
- },
-#endif /* CONFIG_IPW2100_MONITOR */
+ IPW2100_PRIV_RESET,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"},
+#endif /* CONFIG_IPW2100_MONITOR */
{
- IPW2100_PRIV_SET_POWER,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power"
- },
+ IPW2100_PRIV_SET_POWER,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power"},
{
- IPW2100_PRIV_GET_POWER,
- 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING, "get_power"
- },
+ IPW2100_PRIV_GET_POWER,
+ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING,
+ "get_power"},
{
- IPW2100_PRIV_SET_LONGPREAMBLE,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"
- },
+ IPW2100_PRIV_SET_LONGPREAMBLE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"},
{
- IPW2100_PRIV_GET_LONGPREAMBLE,
- 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"
- },
+ IPW2100_PRIV_GET_LONGPREAMBLE,
+ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"},
+#ifdef CONFIG_IPW2100_MONITOR
+ {
+ IPW2100_PRIV_SET_CRC_CHECK,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_crc_check"},
+ {
+ IPW2100_PRIV_GET_CRC_CHECK,
+ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_crc_check"},
+#endif /* CONFIG_IPW2100_MONITOR */
};
static iw_handler ipw2100_private_handler[] = {
#ifdef CONFIG_IPW2100_MONITOR
ipw2100_wx_set_promisc,
ipw2100_wx_reset,
-#else /* CONFIG_IPW2100_MONITOR */
+#else /* CONFIG_IPW2100_MONITOR */
NULL,
NULL,
-#endif /* CONFIG_IPW2100_MONITOR */
+#endif /* CONFIG_IPW2100_MONITOR */
ipw2100_wx_set_powermode,
ipw2100_wx_get_powermode,
ipw2100_wx_set_preamble,
ipw2100_wx_get_preamble,
+#ifdef CONFIG_IPW2100_MONITOR
+ ipw2100_wx_set_crc_check,
+ ipw2100_wx_get_crc_check,
+#else /* CONFIG_IPW2100_MONITOR */
+ NULL,
+ NULL,
+#endif /* CONFIG_IPW2100_MONITOR */
};
-static struct iw_handler_def ipw2100_wx_handler_def =
-{
+static struct iw_handler_def ipw2100_wx_handler_def = {
.standard = ipw2100_wx_handlers,
.num_standard = sizeof(ipw2100_wx_handlers) / sizeof(iw_handler),
.num_private = sizeof(ipw2100_private_handler) / sizeof(iw_handler),
- .num_private_args = sizeof(ipw2100_private_args) /
- sizeof(struct iw_priv_args),
- .private = (iw_handler *)ipw2100_private_handler,
+ .num_private_args = sizeof(ipw2100_private_args) /
+ sizeof(struct iw_priv_args),
+ .private = (iw_handler *) ipw2100_private_handler,
.private_args = (struct iw_priv_args *)ipw2100_private_args,
};
@@ -8170,7 +8461,7 @@ static struct iw_handler_def ipw2100_wx_handler_def =
* Called by /proc/net/wireless
* Also called by SIOCGIWSTATS
*/
-static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev)
+static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
{
enum {
POOR = 30,
@@ -8190,7 +8481,7 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev)
u32 ord_len = sizeof(u32);
if (!priv)
- return (struct iw_statistics *) NULL;
+ return (struct iw_statistics *)NULL;
wstats = &priv->wstats;
@@ -8207,7 +8498,7 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev)
wstats->qual.noise = 0;
wstats->qual.updated = 7;
wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
- IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
+ IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
return wstats;
}
@@ -8215,7 +8506,7 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev)
&missed_beacons, &ord_len))
goto fail_get_ordinal;
- /* If we don't have a connection the quality and level is 0*/
+ /* If we don't have a connection the quality and level is 0 */
if (!(priv->status & STATUS_ASSOCIATED)) {
wstats->qual.qual = 0;
wstats->qual.level = 0;
@@ -8232,10 +8523,10 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev)
rssi_qual = (rssi - 15) * (GOOD - FAIR) / 5 + FAIR;
else if (rssi < 30)
rssi_qual = (rssi - 20) * (VERY_GOOD - GOOD) /
- 10 + GOOD;
+ 10 + GOOD;
else
rssi_qual = (rssi - 30) * (PERFECT - VERY_GOOD) /
- 10 + VERY_GOOD;
+ 10 + VERY_GOOD;
if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_RETRIES,
&tx_retries, &ord_len))
@@ -8249,25 +8540,25 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev)
tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
else if (tx_retries > 50)
tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
- 15 + GOOD;
+ 15 + GOOD;
else
tx_qual = (50 - tx_retries) *
- (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
+ (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
if (missed_beacons > 50)
beacon_qual = (60 - missed_beacons) * POOR / 10;
else if (missed_beacons > 40)
beacon_qual = (50 - missed_beacons) * (FAIR - POOR) /
- 10 + POOR;
+ 10 + POOR;
else if (missed_beacons > 32)
beacon_qual = (40 - missed_beacons) * (GOOD - FAIR) /
- 18 + FAIR;
+ 18 + FAIR;
else if (missed_beacons > 20)
beacon_qual = (32 - missed_beacons) *
- (VERY_GOOD - GOOD) / 20 + GOOD;
+ (VERY_GOOD - GOOD) / 20 + GOOD;
else
beacon_qual = (20 - missed_beacons) *
- (PERFECT - VERY_GOOD) / 20 + VERY_GOOD;
+ (PERFECT - VERY_GOOD) / 20 + VERY_GOOD;
quality = min(beacon_qual, min(tx_qual, rssi_qual));
@@ -8290,7 +8581,7 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev)
wstats->qual.updated = 7;
wstats->qual.updated |= IW_QUAL_NOISE_INVALID;
- /* FIXME: this is percent and not a # */
+ /* FIXME: this is percent and not a # */
wstats->miss.beacon = missed_beacons;
if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURES,
@@ -8300,10 +8591,10 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev)
return wstats;
- fail_get_ordinal:
+ fail_get_ordinal:
IPW_DEBUG_WX("failed querying ordinals.\n");
- return (struct iw_statistics *) NULL;
+ return (struct iw_statistics *)NULL;
}
static void ipw2100_wx_event_work(struct ipw2100_priv *priv)
@@ -8326,23 +8617,17 @@ static void ipw2100_wx_event_work(struct ipw2100_priv *priv)
if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) ||
priv->status & STATUS_RF_KILL_MASK ||
ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
- &priv->bssid, &len)) {
+ &priv->bssid, &len)) {
memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
} else {
/* We now have the BSSID, so can finish setting to the full
* associated state */
memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
- memcpy(&priv->ieee->bssid, priv->bssid, ETH_ALEN);
+ memcpy(priv->ieee->bssid, priv->bssid, ETH_ALEN);
priv->status &= ~STATUS_ASSOCIATING;
priv->status |= STATUS_ASSOCIATED;
netif_carrier_on(priv->net_dev);
- if (netif_queue_stopped(priv->net_dev)) {
- IPW_DEBUG_INFO("Waking net queue.\n");
- netif_wake_queue(priv->net_dev);
- } else {
- IPW_DEBUG_INFO("Starting net queue.\n");
- netif_start_queue(priv->net_dev);
- }
+ netif_wake_queue(priv->net_dev);
}
if (!(priv->status & STATUS_ASSOCIATED)) {
@@ -8351,7 +8636,8 @@ static void ipw2100_wx_event_work(struct ipw2100_priv *priv)
/* This is a disassociation event, so kick the firmware to
* look for another AP */
if (priv->config & CFG_STATIC_ESSID)
- ipw2100_set_essid(priv, priv->essid, priv->essid_len, 0);
+ ipw2100_set_essid(priv, priv->essid, priv->essid_len,
+ 0);
else
ipw2100_set_essid(priv, NULL, 0, 0);
up(&priv->action_sem);
@@ -8374,7 +8660,6 @@ static void ipw2100_wx_event_work(struct ipw2100_priv *priv)
#define IPW2100_FW_NAME(x) IPW2100_FW_PREFIX "" x ".fw"
-
/*
BINARY FIRMWARE HEADER FORMAT
@@ -8396,12 +8681,10 @@ struct ipw2100_fw_header {
unsigned int uc_size;
} __attribute__ ((packed));
-
-
static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw)
{
struct ipw2100_fw_header *h =
- (struct ipw2100_fw_header *)fw->fw_entry->data;
+ (struct ipw2100_fw_header *)fw->fw_entry->data;
if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) {
printk(KERN_WARNING DRV_NAME ": Firmware image not compatible "
@@ -8420,7 +8703,6 @@ static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw)
return 0;
}
-
static int ipw2100_get_firmware(struct ipw2100_priv *priv,
struct ipw2100_fw *fw)
{
@@ -8428,7 +8710,7 @@ static int ipw2100_get_firmware(struct ipw2100_priv *priv,
int rc;
IPW_DEBUG_INFO("%s: Using hotplug firmware load.\n",
- priv->net_dev->name);
+ priv->net_dev->name);
switch (priv->ieee->iw_mode) {
case IW_MODE_ADHOC:
@@ -8454,7 +8736,7 @@ static int ipw2100_get_firmware(struct ipw2100_priv *priv,
return rc;
}
IPW_DEBUG_INFO("firmware data %p size %zd\n", fw->fw_entry->data,
- fw->fw_entry->size);
+ fw->fw_entry->size);
ipw2100_mod_firmware_load(fw);
@@ -8470,7 +8752,6 @@ static void ipw2100_release_firmware(struct ipw2100_priv *priv,
fw->fw_entry = NULL;
}
-
static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
size_t max)
{
@@ -8479,8 +8760,7 @@ static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
u32 tmp;
int i;
/* firmware version is an ascii string (max len of 14) */
- if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM,
- ver, &len))
+ if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM, ver, &len))
return -EIO;
tmp = max;
if (len >= max)
@@ -8497,8 +8777,7 @@ static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
u32 ver;
u32 len = sizeof(ver);
/* microcode version is a 32 bit integer */
- if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION,
- &ver, &len))
+ if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION, &ver, &len))
return -EIO;
return snprintf(buf, max, "%08X", ver);
}
@@ -8506,8 +8785,7 @@ static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
/*
* On exit, the firmware will have been freed from the fw list
*/
-static int ipw2100_fw_download(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw)
+static int ipw2100_fw_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw)
{
/* firmware is constructed of N contiguous entries, each entry is
* structured as:
@@ -8515,7 +8793,7 @@ static int ipw2100_fw_download(struct ipw2100_priv *priv,
* offset sie desc
* 0 4 address to write to
* 4 2 length of data run
- * 6 length data
+ * 6 length data
*/
unsigned int addr;
unsigned short len;
@@ -8524,12 +8802,12 @@ static int ipw2100_fw_download(struct ipw2100_priv *priv,
unsigned int firmware_data_left = fw->fw.size;
while (firmware_data_left > 0) {
- addr = *(u32 *)(firmware_data);
- firmware_data += 4;
+ addr = *(u32 *) (firmware_data);
+ firmware_data += 4;
firmware_data_left -= 4;
- len = *(u16 *)(firmware_data);
- firmware_data += 2;
+ len = *(u16 *) (firmware_data);
+ firmware_data += 2;
firmware_data_left -= 2;
if (len > 32) {
@@ -8540,7 +8818,7 @@ static int ipw2100_fw_download(struct ipw2100_priv *priv,
}
write_nic_memory(priv->net_dev, addr, len, firmware_data);
- firmware_data += len;
+ firmware_data += len;
firmware_data_left -= len;
}
@@ -8654,21 +8932,19 @@ static int ipw2100_ucode_download(struct ipw2100_priv *priv,
for (i = 0; i < 30; i++) {
/* Read alive response structure */
for (j = 0;
- j < (sizeof(struct symbol_alive_response) >> 1);
- j++)
- read_nic_word(dev, 0x210004,
- ((u16 *)&response) + j);
+ j < (sizeof(struct symbol_alive_response) >> 1); j++)
+ read_nic_word(dev, 0x210004, ((u16 *) & response) + j);
- if ((response.cmd_id == 1) &&
- (response.ucode_valid == 0x1))
+ if ((response.cmd_id == 1) && (response.ucode_valid == 0x1))
break;
udelay(10);
}
if (i == 30) {
- printk(KERN_ERR DRV_NAME ": %s: No response from Symbol - hw not alive\n",
+ printk(KERN_ERR DRV_NAME
+ ": %s: No response from Symbol - hw not alive\n",
dev->name);
- printk_buf(IPW_DL_ERROR, (u8*)&response, sizeof(response));
+ printk_buf(IPW_DL_ERROR, (u8 *) & response, sizeof(response));
return -EIO;
}
diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h
index c9e99ce15d6..140fdf2a0a0 100644
--- a/drivers/net/wireless/ipw2100.h
+++ b/drivers/net/wireless/ipw2100.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
This program is free software; you can redistribute it and/or modify it
under the terms of version 2 of the GNU General Public License as
@@ -37,7 +37,6 @@
#include <linux/socket.h>
#include <linux/if_arp.h>
#include <linux/wireless.h>
-#include <linux/version.h>
#include <net/iw_handler.h> // new driver API
#include <net/ieee80211.h>
@@ -93,7 +92,6 @@ struct ipw2100_rx_packet;
#define IPW_DL_IOCTL (1<<14)
#define IPW_DL_RF_KILL (1<<17)
-
#define IPW_DL_MANAGE (1<<15)
#define IPW_DL_FW (1<<16)
@@ -156,7 +154,9 @@ extern const char *band_str[];
struct bd_status {
union {
- struct { u8 nlf:1, txType:2, intEnabled:1, reserved:4;} fields;
+ struct {
+ u8 nlf:1, txType:2, intEnabled:1, reserved:4;
+ } fields;
u8 field;
} info;
} __attribute__ ((packed));
@@ -165,7 +165,7 @@ struct ipw2100_bd {
u32 host_addr;
u32 buf_length;
struct bd_status status;
- /* number of fragments for frame (should be set only for
+ /* number of fragments for frame (should be set only for
* 1st TBD) */
u8 num_fragments;
u8 reserved[6];
@@ -293,10 +293,10 @@ struct ipw2100_cmd_header {
struct ipw2100_data_header {
u32 host_command_reg;
u32 host_command_reg1;
- u8 encrypted; // BOOLEAN in win! TRUE if frame is enc by driver
+ u8 encrypted; // BOOLEAN in win! TRUE if frame is enc by driver
u8 needs_encryption; // BOOLEAN in win! TRUE if frma need to be enc in NIC
u8 wep_index; // 0 no key, 1-4 key index, 0xff immediate key
- u8 key_size; // 0 no imm key, 0x5 64bit encr, 0xd 128bit encr, 0x10 128bit encr and 128bit IV
+ u8 key_size; // 0 no imm key, 0x5 64bit encr, 0xd 128bit encr, 0x10 128bit encr and 128bit IV
u8 key[16];
u8 reserved[10]; // f/w reserved
u8 src_addr[ETH_ALEN];
@@ -306,14 +306,13 @@ struct ipw2100_data_header {
/* Host command data structure */
struct host_command {
- u32 host_command; // COMMAND ID
- u32 host_command1; // COMMAND ID
+ u32 host_command; // COMMAND ID
+ u32 host_command1; // COMMAND ID
u32 host_command_sequence; // UNIQUE COMMAND NUMBER (ID)
u32 host_command_length; // LENGTH
u32 host_command_parameters[HOST_COMMAND_PARAMS_REG_LEN]; // COMMAND PARAMETERS
} __attribute__ ((packed));
-
typedef enum {
POWER_ON_RESET,
EXIT_POWER_DOWN_RESET,
@@ -328,17 +327,16 @@ enum {
RX
};
-
struct ipw2100_tx_packet {
int type;
int index;
union {
- struct { /* COMMAND */
- struct ipw2100_cmd_header* cmd;
+ struct { /* COMMAND */
+ struct ipw2100_cmd_header *cmd;
dma_addr_t cmd_phys;
} c_struct;
- struct { /* DATA */
- struct ipw2100_data_header* data;
+ struct { /* DATA */
+ struct ipw2100_data_header *data;
dma_addr_t data_phys;
struct ieee80211_txb *txb;
} d_struct;
@@ -348,7 +346,6 @@ struct ipw2100_tx_packet {
struct list_head list;
};
-
struct ipw2100_rx_packet {
struct ipw2100_rx *rxp;
dma_addr_t dma_addr;
@@ -432,13 +429,13 @@ enum {
};
#define STATUS_POWERED (1<<0)
-#define STATUS_CMD_ACTIVE (1<<1) /**< host command in progress */
-#define STATUS_RUNNING (1<<2) /* Card initialized, but not enabled */
-#define STATUS_ENABLED (1<<3) /* Card enabled -- can scan,Tx,Rx */
-#define STATUS_STOPPING (1<<4) /* Card is in shutdown phase */
-#define STATUS_INITIALIZED (1<<5) /* Card is ready for external calls */
-#define STATUS_ASSOCIATING (1<<9) /* Associated, but no BSSID yet */
-#define STATUS_ASSOCIATED (1<<10) /* Associated and BSSID valid */
+#define STATUS_CMD_ACTIVE (1<<1) /**< host command in progress */
+#define STATUS_RUNNING (1<<2) /* Card initialized, but not enabled */
+#define STATUS_ENABLED (1<<3) /* Card enabled -- can scan,Tx,Rx */
+#define STATUS_STOPPING (1<<4) /* Card is in shutdown phase */
+#define STATUS_INITIALIZED (1<<5) /* Card is ready for external calls */
+#define STATUS_ASSOCIATING (1<<9) /* Associated, but no BSSID yet */
+#define STATUS_ASSOCIATED (1<<10) /* Associated and BSSID valid */
#define STATUS_INT_ENABLED (1<<11)
#define STATUS_RF_KILL_HW (1<<12)
#define STATUS_RF_KILL_SW (1<<13)
@@ -451,9 +448,7 @@ enum {
#define STATUS_SCAN_COMPLETE (1<<26)
#define STATUS_WX_EVENT_PENDING (1<<27)
#define STATUS_RESET_PENDING (1<<29)
-#define STATUS_SECURITY_UPDATED (1<<30) /* Security sync needed */
-
-
+#define STATUS_SECURITY_UPDATED (1<<30) /* Security sync needed */
/* Internal NIC states */
#define IPW_STATE_INITIALIZED (1<<0)
@@ -469,11 +464,9 @@ enum {
#define IPW_STATE_POWER_DOWN (1<<10)
#define IPW_STATE_SCANNING (1<<11)
-
-
-#define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */
-#define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */
-#define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */
+#define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */
+#define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */
+#define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */
#define CFG_CUSTOM_MAC (1<<3)
#define CFG_LONG_PREAMBLE (1<<4)
#define CFG_ASSOCIATE (1<<6)
@@ -481,14 +474,17 @@ enum {
#define CFG_ADHOC_CREATE (1<<8)
#define CFG_C3_DISABLED (1<<9)
#define CFG_PASSIVE_SCAN (1<<10)
+#ifdef CONFIG_IPW2100_MONITOR
+#define CFG_CRC_CHECK (1<<11)
+#endif
-#define CAP_SHARED_KEY (1<<0) /* Off = OPEN */
-#define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */
+#define CAP_SHARED_KEY (1<<0) /* Off = OPEN */
+#define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */
struct ipw2100_priv {
- int stop_hang_check; /* Set 1 when shutting down to kill hang_check */
- int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */
+ int stop_hang_check; /* Set 1 when shutting down to kill hang_check */
+ int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */
struct ieee80211_device *ieee;
unsigned long status;
@@ -519,19 +515,16 @@ struct ipw2100_priv {
unsigned long hw_features;
int hangs;
u32 last_rtc;
- int dump_raw; /* 1 to dump raw bytes in /sys/.../memory */
- u8* snapshot[0x30];
+ int dump_raw; /* 1 to dump raw bytes in /sys/.../memory */
+ u8 *snapshot[0x30];
u8 mandatory_bssid_mac[ETH_ALEN];
u8 mac_addr[ETH_ALEN];
int power_mode;
- /* WEP data */
- struct ieee80211_security sec;
int messages_sent;
-
int short_retry_limit;
int long_retry_limit;
@@ -599,7 +592,6 @@ struct ipw2100_priv {
wait_queue_head_t wait_command_queue;
};
-
/*********************************************************
* Host Command -> From Driver to FW
*********************************************************/
@@ -646,7 +638,6 @@ struct ipw2100_priv {
#define CARD_DISABLE_PHY_OFF 61
#define MSDU_TX_RATES 62
-
/* Rogue AP Detection */
#define SET_STATION_STAT_BITS 64
#define CLEAR_STATIONS_STAT_BITS 65
@@ -655,8 +646,6 @@ struct ipw2100_priv {
#define DISASSOCIATION_BSSID 68
#define SET_WPA_IE 69
-
-
/* system configuration bit mask: */
#define IPW_CFG_MONITOR 0x00004
#define IPW_CFG_PREAMBLE_AUTO 0x00010
@@ -704,7 +693,7 @@ struct ipw2100_priv {
#define IPW2100_INTA_TX_TRANSFER (0x00000001) // Bit 0 (LSB)
#define IPW2100_INTA_RX_TRANSFER (0x00000002) // Bit 1
#define IPW2100_INTA_TX_COMPLETE (0x00000004) // Bit 2
-#define IPW2100_INTA_EVENT_INTERRUPT (0x00000008) // Bit 3
+#define IPW2100_INTA_EVENT_INTERRUPT (0x00000008) // Bit 3
#define IPW2100_INTA_STATUS_CHANGE (0x00000010) // Bit 4
#define IPW2100_INTA_BEACON_PERIOD_EXPIRED (0x00000020) // Bit 5
#define IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE (0x00010000) // Bit 16
@@ -784,9 +773,6 @@ struct ipw2100_priv {
#define IPW_CARD_DISABLE_PHY_OFF_COMPLETE_WAIT 100 // 100 milli
#define IPW_PREPARE_POWER_DOWN_COMPLETE_WAIT 100 // 100 milli
-
-
-
#define IPW_HEADER_802_11_SIZE sizeof(struct ieee80211_hdr_3addr)
#define IPW_MAX_80211_PAYLOAD_SIZE 2304U
#define IPW_MAX_802_11_PAYLOAD_LENGTH 2312
@@ -843,8 +829,8 @@ struct ipw2100_rx {
#define IPW_TX_POWER_MIN_DBM (-12)
#define IPW_TX_POWER_MAX_DBM 16
-#define FW_SCAN_DONOT_ASSOCIATE 0x0001 // Dont Attempt to Associate after Scan
-#define FW_SCAN_PASSIVE 0x0008 // Force PASSSIVE Scan
+#define FW_SCAN_DONOT_ASSOCIATE 0x0001 // Dont Attempt to Associate after Scan
+#define FW_SCAN_PASSIVE 0x0008 // Force PASSSIVE Scan
#define REG_MIN_CHANNEL 0
#define REG_MAX_CHANNEL 14
@@ -856,7 +842,6 @@ struct ipw2100_rx {
#define DIVERSITY_ANTENNA_A 1 // Use antenna A
#define DIVERSITY_ANTENNA_B 2 // Use antenna B
-
#define HOST_COMMAND_WAIT 0
#define HOST_COMMAND_NO_WAIT 1
@@ -873,10 +858,9 @@ struct ipw2100_rx {
#define TYPE_ASSOCIATION_REQUEST 0x0013
#define TYPE_REASSOCIATION_REQUEST 0x0014
-
-#define HW_FEATURE_RFKILL (0x0001)
-#define RF_KILLSWITCH_OFF (1)
-#define RF_KILLSWITCH_ON (0)
+#define HW_FEATURE_RFKILL 0x0001
+#define RF_KILLSWITCH_OFF 1
+#define RF_KILLSWITCH_ON 0
#define IPW_COMMAND_POOL_SIZE 40
@@ -895,7 +879,7 @@ struct ipw2100_rx {
// Fixed size data: Ordinal Table 1
typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW
// Transmit statistics
- IPW_ORD_STAT_TX_HOST_REQUESTS = 1,// # of requested Host Tx's (MSDU)
+ IPW_ORD_STAT_TX_HOST_REQUESTS = 1, // # of requested Host Tx's (MSDU)
IPW_ORD_STAT_TX_HOST_COMPLETE, // # of successful Host Tx's (MSDU)
IPW_ORD_STAT_TX_DIR_DATA, // # of successful Directed Tx's (MSDU)
@@ -905,42 +889,42 @@ typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW
IPW_ORD_STAT_TX_DIR_DATA11, // # of successful Directed Tx's (MSDU) @ 11MB
IPW_ORD_STAT_TX_DIR_DATA22, // # of successful Directed Tx's (MSDU) @ 22MB
- IPW_ORD_STAT_TX_NODIR_DATA1 = 13,// # of successful Non_Directed Tx's (MSDU) @ 1MB
+ IPW_ORD_STAT_TX_NODIR_DATA1 = 13, // # of successful Non_Directed Tx's (MSDU) @ 1MB
IPW_ORD_STAT_TX_NODIR_DATA2, // # of successful Non_Directed Tx's (MSDU) @ 2MB
IPW_ORD_STAT_TX_NODIR_DATA5_5, // # of successful Non_Directed Tx's (MSDU) @ 5.5MB
IPW_ORD_STAT_TX_NODIR_DATA11, // # of successful Non_Directed Tx's (MSDU) @ 11MB
IPW_ORD_STAT_NULL_DATA = 21, // # of successful NULL data Tx's
- IPW_ORD_STAT_TX_RTS, // # of successful Tx RTS
- IPW_ORD_STAT_TX_CTS, // # of successful Tx CTS
- IPW_ORD_STAT_TX_ACK, // # of successful Tx ACK
- IPW_ORD_STAT_TX_ASSN, // # of successful Association Tx's
+ IPW_ORD_STAT_TX_RTS, // # of successful Tx RTS
+ IPW_ORD_STAT_TX_CTS, // # of successful Tx CTS
+ IPW_ORD_STAT_TX_ACK, // # of successful Tx ACK
+ IPW_ORD_STAT_TX_ASSN, // # of successful Association Tx's
IPW_ORD_STAT_TX_ASSN_RESP, // # of successful Association response Tx's
- IPW_ORD_STAT_TX_REASSN, // # of successful Reassociation Tx's
+ IPW_ORD_STAT_TX_REASSN, // # of successful Reassociation Tx's
IPW_ORD_STAT_TX_REASSN_RESP, // # of successful Reassociation response Tx's
- IPW_ORD_STAT_TX_PROBE, // # of probes successfully transmitted
+ IPW_ORD_STAT_TX_PROBE, // # of probes successfully transmitted
IPW_ORD_STAT_TX_PROBE_RESP, // # of probe responses successfully transmitted
- IPW_ORD_STAT_TX_BEACON, // # of tx beacon
- IPW_ORD_STAT_TX_ATIM, // # of Tx ATIM
+ IPW_ORD_STAT_TX_BEACON, // # of tx beacon
+ IPW_ORD_STAT_TX_ATIM, // # of Tx ATIM
IPW_ORD_STAT_TX_DISASSN, // # of successful Disassociation TX
- IPW_ORD_STAT_TX_AUTH, // # of successful Authentication Tx
- IPW_ORD_STAT_TX_DEAUTH, // # of successful Deauthentication TX
+ IPW_ORD_STAT_TX_AUTH, // # of successful Authentication Tx
+ IPW_ORD_STAT_TX_DEAUTH, // # of successful Deauthentication TX
- IPW_ORD_STAT_TX_TOTAL_BYTES = 41,// Total successful Tx data bytes
- IPW_ORD_STAT_TX_RETRIES, // # of Tx retries
- IPW_ORD_STAT_TX_RETRY1, // # of Tx retries at 1MBPS
- IPW_ORD_STAT_TX_RETRY2, // # of Tx retries at 2MBPS
- IPW_ORD_STAT_TX_RETRY5_5, // # of Tx retries at 5.5MBPS
- IPW_ORD_STAT_TX_RETRY11, // # of Tx retries at 11MBPS
+ IPW_ORD_STAT_TX_TOTAL_BYTES = 41, // Total successful Tx data bytes
+ IPW_ORD_STAT_TX_RETRIES, // # of Tx retries
+ IPW_ORD_STAT_TX_RETRY1, // # of Tx retries at 1MBPS
+ IPW_ORD_STAT_TX_RETRY2, // # of Tx retries at 2MBPS
+ IPW_ORD_STAT_TX_RETRY5_5, // # of Tx retries at 5.5MBPS
+ IPW_ORD_STAT_TX_RETRY11, // # of Tx retries at 11MBPS
IPW_ORD_STAT_TX_FAILURES = 51, // # of Tx Failures
IPW_ORD_STAT_TX_ABORT_AT_HOP, //NS // # of Tx's aborted at hop time
- IPW_ORD_STAT_TX_MAX_TRIES_IN_HOP,// # of times max tries in a hop failed
+ IPW_ORD_STAT_TX_MAX_TRIES_IN_HOP, // # of times max tries in a hop failed
IPW_ORD_STAT_TX_ABORT_LATE_DMA, //NS // # of times tx aborted due to late dma setup
IPW_ORD_STAT_TX_ABORT_STX, //NS // # of times backoff aborted
IPW_ORD_STAT_TX_DISASSN_FAIL, // # of times disassociation failed
- IPW_ORD_STAT_TX_ERR_CTS, // # of missed/bad CTS frames
- IPW_ORD_STAT_TX_BPDU, //NS // # of spanning tree BPDUs sent
+ IPW_ORD_STAT_TX_ERR_CTS, // # of missed/bad CTS frames
+ IPW_ORD_STAT_TX_BPDU, //NS // # of spanning tree BPDUs sent
IPW_ORD_STAT_TX_ERR_ACK, // # of tx err due to acks
// Receive statistics
@@ -952,7 +936,7 @@ typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW
IPW_ORD_STAT_RX_DIR_DATA11, // # of directed packets at 11MB
IPW_ORD_STAT_RX_DIR_DATA22, // # of directed packets at 22MB
- IPW_ORD_STAT_RX_NODIR_DATA = 71,// # of nondirected packets
+ IPW_ORD_STAT_RX_NODIR_DATA = 71, // # of nondirected packets
IPW_ORD_STAT_RX_NODIR_DATA1, // # of nondirected packets at 1MB
IPW_ORD_STAT_RX_NODIR_DATA2, // # of nondirected packets at 2MB
IPW_ORD_STAT_RX_NODIR_DATA5_5, // # of nondirected packets at 5.5MB
@@ -977,18 +961,18 @@ typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW
IPW_ORD_STAT_RX_AUTH, // # of authentication Rx
IPW_ORD_STAT_RX_DEAUTH, // # of deauthentication Rx
- IPW_ORD_STAT_RX_TOTAL_BYTES = 101,// Total rx data bytes received
- IPW_ORD_STAT_RX_ERR_CRC, // # of packets with Rx CRC error
- IPW_ORD_STAT_RX_ERR_CRC1, // # of Rx CRC errors at 1MB
- IPW_ORD_STAT_RX_ERR_CRC2, // # of Rx CRC errors at 2MB
- IPW_ORD_STAT_RX_ERR_CRC5_5, // # of Rx CRC errors at 5.5MB
- IPW_ORD_STAT_RX_ERR_CRC11, // # of Rx CRC errors at 11MB
+ IPW_ORD_STAT_RX_TOTAL_BYTES = 101, // Total rx data bytes received
+ IPW_ORD_STAT_RX_ERR_CRC, // # of packets with Rx CRC error
+ IPW_ORD_STAT_RX_ERR_CRC1, // # of Rx CRC errors at 1MB
+ IPW_ORD_STAT_RX_ERR_CRC2, // # of Rx CRC errors at 2MB
+ IPW_ORD_STAT_RX_ERR_CRC5_5, // # of Rx CRC errors at 5.5MB
+ IPW_ORD_STAT_RX_ERR_CRC11, // # of Rx CRC errors at 11MB
- IPW_ORD_STAT_RX_DUPLICATE1 = 112, // # of duplicate rx packets at 1MB
- IPW_ORD_STAT_RX_DUPLICATE2, // # of duplicate rx packets at 2MB
- IPW_ORD_STAT_RX_DUPLICATE5_5, // # of duplicate rx packets at 5.5MB
- IPW_ORD_STAT_RX_DUPLICATE11, // # of duplicate rx packets at 11MB
- IPW_ORD_STAT_RX_DUPLICATE = 119, // # of duplicate rx packets
+ IPW_ORD_STAT_RX_DUPLICATE1 = 112, // # of duplicate rx packets at 1MB
+ IPW_ORD_STAT_RX_DUPLICATE2, // # of duplicate rx packets at 2MB
+ IPW_ORD_STAT_RX_DUPLICATE5_5, // # of duplicate rx packets at 5.5MB
+ IPW_ORD_STAT_RX_DUPLICATE11, // # of duplicate rx packets at 11MB
+ IPW_ORD_STAT_RX_DUPLICATE = 119, // # of duplicate rx packets
IPW_ORD_PERS_DB_LOCK = 120, // # locking fw permanent db
IPW_ORD_PERS_DB_SIZE, // # size of fw permanent db
@@ -1006,17 +990,17 @@ typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW
IPW_ORD_STAT_RX_ICV_ERRORS, // # of ICV errors during decryption
// PSP Statistics
- IPW_ORD_STAT_PSP_SUSPENSION = 137,// # of times adapter suspended
+ IPW_ORD_STAT_PSP_SUSPENSION = 137, // # of times adapter suspended
IPW_ORD_STAT_PSP_BCN_TIMEOUT, // # of beacon timeout
IPW_ORD_STAT_PSP_POLL_TIMEOUT, // # of poll response timeouts
- IPW_ORD_STAT_PSP_NONDIR_TIMEOUT,// # of timeouts waiting for last broadcast/muticast pkt
+ IPW_ORD_STAT_PSP_NONDIR_TIMEOUT, // # of timeouts waiting for last broadcast/muticast pkt
IPW_ORD_STAT_PSP_RX_DTIMS, // # of PSP DTIMs received
IPW_ORD_STAT_PSP_RX_TIMS, // # of PSP TIMs received
IPW_ORD_STAT_PSP_STATION_ID, // PSP Station ID
// Association and roaming
IPW_ORD_LAST_ASSN_TIME = 147, // RTC time of last association
- IPW_ORD_STAT_PERCENT_MISSED_BCNS,// current calculation of % missed beacons
+ IPW_ORD_STAT_PERCENT_MISSED_BCNS, // current calculation of % missed beacons
IPW_ORD_STAT_PERCENT_RETRIES, // current calculation of % missed tx retries
IPW_ORD_ASSOCIATED_AP_PTR, // If associated, this is ptr to the associated
// AP table entry. set to 0 if not associated
@@ -1151,7 +1135,7 @@ struct ipw2100_fw_chunk {
};
struct ipw2100_fw_chunk_set {
- const void *data;
+ const void *data;
unsigned long size;
};
@@ -1164,4 +1148,4 @@ struct ipw2100_fw {
#define MAX_FW_VERSION_LEN 14
-#endif /* _IPW2100_H */
+#endif /* _IPW2100_H */
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 3db0c32afe8..b0d195d1721 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
+ Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
802.11 status code portion of this file from ethereal-0.10.6:
Copyright 2000, Axis Communications AB
@@ -31,30 +31,103 @@
******************************************************************************/
#include "ipw2200.h"
+#include <linux/version.h>
-#define IPW2200_VERSION "1.0.0"
+#define IPW2200_VERSION "git-1.0.8"
#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver"
-#define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation"
+#define DRV_COPYRIGHT "Copyright(c) 2003-2005 Intel Corporation"
#define DRV_VERSION IPW2200_VERSION
+#define ETH_P_80211_STATS (ETH_P_80211_RAW + 1)
+
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");
+static int cmdlog = 0;
static int debug = 0;
static int channel = 0;
-static char *ifname;
static int mode = 0;
static u32 ipw_debug_level;
static int associate = 1;
static int auto_create = 1;
+static int led = 0;
static int disable = 0;
+static int hwcrypto = 1;
static const char ipw_modes[] = {
'a', 'b', 'g', '?'
};
+#ifdef CONFIG_IPW_QOS
+static int qos_enable = 0;
+static int qos_burst_enable = 0;
+static int qos_no_ack_mask = 0;
+static int burst_duration_CCK = 0;
+static int burst_duration_OFDM = 0;
+
+static struct ieee80211_qos_parameters def_qos_parameters_OFDM = {
+ {QOS_TX0_CW_MIN_OFDM, QOS_TX1_CW_MIN_OFDM, QOS_TX2_CW_MIN_OFDM,
+ QOS_TX3_CW_MIN_OFDM},
+ {QOS_TX0_CW_MAX_OFDM, QOS_TX1_CW_MAX_OFDM, QOS_TX2_CW_MAX_OFDM,
+ QOS_TX3_CW_MAX_OFDM},
+ {QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS},
+ {QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM},
+ {QOS_TX0_TXOP_LIMIT_OFDM, QOS_TX1_TXOP_LIMIT_OFDM,
+ QOS_TX2_TXOP_LIMIT_OFDM, QOS_TX3_TXOP_LIMIT_OFDM}
+};
+
+static struct ieee80211_qos_parameters def_qos_parameters_CCK = {
+ {QOS_TX0_CW_MIN_CCK, QOS_TX1_CW_MIN_CCK, QOS_TX2_CW_MIN_CCK,
+ QOS_TX3_CW_MIN_CCK},
+ {QOS_TX0_CW_MAX_CCK, QOS_TX1_CW_MAX_CCK, QOS_TX2_CW_MAX_CCK,
+ QOS_TX3_CW_MAX_CCK},
+ {QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS},
+ {QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM},
+ {QOS_TX0_TXOP_LIMIT_CCK, QOS_TX1_TXOP_LIMIT_CCK, QOS_TX2_TXOP_LIMIT_CCK,
+ QOS_TX3_TXOP_LIMIT_CCK}
+};
+
+static struct ieee80211_qos_parameters def_parameters_OFDM = {
+ {DEF_TX0_CW_MIN_OFDM, DEF_TX1_CW_MIN_OFDM, DEF_TX2_CW_MIN_OFDM,
+ DEF_TX3_CW_MIN_OFDM},
+ {DEF_TX0_CW_MAX_OFDM, DEF_TX1_CW_MAX_OFDM, DEF_TX2_CW_MAX_OFDM,
+ DEF_TX3_CW_MAX_OFDM},
+ {DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS},
+ {DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM},
+ {DEF_TX0_TXOP_LIMIT_OFDM, DEF_TX1_TXOP_LIMIT_OFDM,
+ DEF_TX2_TXOP_LIMIT_OFDM, DEF_TX3_TXOP_LIMIT_OFDM}
+};
+
+static struct ieee80211_qos_parameters def_parameters_CCK = {
+ {DEF_TX0_CW_MIN_CCK, DEF_TX1_CW_MIN_CCK, DEF_TX2_CW_MIN_CCK,
+ DEF_TX3_CW_MIN_CCK},
+ {DEF_TX0_CW_MAX_CCK, DEF_TX1_CW_MAX_CCK, DEF_TX2_CW_MAX_CCK,
+ DEF_TX3_CW_MAX_CCK},
+ {DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS},
+ {DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM},
+ {DEF_TX0_TXOP_LIMIT_CCK, DEF_TX1_TXOP_LIMIT_CCK, DEF_TX2_TXOP_LIMIT_CCK,
+ DEF_TX3_TXOP_LIMIT_CCK}
+};
+
+static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
+
+static int from_priority_to_tx_queue[] = {
+ IPW_TX_QUEUE_1, IPW_TX_QUEUE_2, IPW_TX_QUEUE_2, IPW_TX_QUEUE_1,
+ IPW_TX_QUEUE_3, IPW_TX_QUEUE_3, IPW_TX_QUEUE_4, IPW_TX_QUEUE_4
+};
+
+static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv);
+
+static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters
+ *qos_param);
+static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element
+ *qos_param);
+#endif /* CONFIG_IPW_QOS */
+
+static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev);
+static void ipw_remove_current_network(struct ipw_priv *priv);
static void ipw_rx(struct ipw_priv *priv);
static int ipw_queue_tx_reclaim(struct ipw_priv *priv,
struct clx2_tx_queue *txq, int qindex);
@@ -68,42 +141,24 @@ static void ipw_tx_queue_free(struct ipw_priv *);
static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *);
static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *);
static void ipw_rx_queue_replenish(void *);
-
static int ipw_up(struct ipw_priv *);
+static void ipw_bg_up(void *);
static void ipw_down(struct ipw_priv *);
+static void ipw_bg_down(void *);
static int ipw_config(struct ipw_priv *);
static int init_supported_rates(struct ipw_priv *priv,
struct ipw_supported_rates *prates);
+static void ipw_set_hwcrypto_keys(struct ipw_priv *);
+static void ipw_send_wep_keys(struct ipw_priv *, int);
-static u8 band_b_active_channel[MAX_B_CHANNELS] = {
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0
-};
-static u8 band_a_active_channel[MAX_A_CHANNELS] = {
- 36, 40, 44, 48, 149, 153, 157, 161, 165, 52, 56, 60, 64, 0
-};
+static int ipw_is_valid_channel(struct ieee80211_device *, u8);
+static int ipw_channel_to_index(struct ieee80211_device *, u8);
+static u8 ipw_freq_to_channel(struct ieee80211_device *, u32);
+static int ipw_set_geo(struct ieee80211_device *, const struct ieee80211_geo *);
+static const struct ieee80211_geo *ipw_get_geo(struct ieee80211_device *);
-static int is_valid_channel(int mode_mask, int channel)
-{
- int i;
-
- if (!channel)
- return 0;
-
- if (mode_mask & IEEE_A)
- for (i = 0; i < MAX_A_CHANNELS; i++)
- if (band_a_active_channel[i] == channel)
- return IEEE_A;
-
- if (mode_mask & (IEEE_B | IEEE_G))
- for (i = 0; i < MAX_B_CHANNELS; i++)
- if (band_b_active_channel[i] == channel)
- return mode_mask & (IEEE_B | IEEE_G);
-
- return 0;
-}
-
-static char *snprint_line(char *buf, size_t count,
- const u8 * data, u32 len, u32 ofs)
+static int snprint_line(char *buf, size_t count,
+ const u8 * data, u32 len, u32 ofs)
{
int out, i, j, l;
char c;
@@ -134,7 +189,7 @@ static char *snprint_line(char *buf, size_t count,
out += snprintf(buf + out, count - out, " ");
}
- return buf;
+ return out;
}
static void printk_buf(int level, const u8 * data, u32 len)
@@ -145,14 +200,33 @@ static void printk_buf(int level, const u8 * data, u32 len)
return;
while (len) {
- printk(KERN_DEBUG "%s\n",
- snprint_line(line, sizeof(line), &data[ofs],
- min(len, 16U), ofs));
+ snprint_line(line, sizeof(line), &data[ofs],
+ min(len, 16U), ofs);
+ printk(KERN_DEBUG "%s\n", line);
ofs += 16;
len -= min(len, 16U);
}
}
+static int snprintk_buf(u8 * output, size_t size, const u8 * data, size_t len)
+{
+ size_t out = size;
+ u32 ofs = 0;
+ int total = 0;
+
+ while (size && len) {
+ out = snprint_line(output, size, &data[ofs],
+ min_t(size_t, len, 16U), ofs);
+
+ ofs += 16;
+ output += out;
+ size -= out;
+ len -= min_t(size_t, len, 16U);
+ total += out;
+ }
+ return total;
+}
+
static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg);
#define ipw_read_reg32(a, b) _ipw_read_reg32(a, b)
@@ -226,38 +300,42 @@ static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs)
#define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs)
static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int);
-#define ipw_read_indirect(a, b, c, d) \
- IPW_DEBUG_IO("%s %d: read_inddirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \
- _ipw_read_indirect(a, b, c, d)
+static inline void __ipw_read_indirect(const char *f, int l,
+ struct ipw_priv *a, u32 b, u8 * c, int d)
+{
+ IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %d bytes\n", f, l, (u32) (b),
+ d);
+ _ipw_read_indirect(a, b, c, d);
+}
+
+#define ipw_read_indirect(a, b, c, d) __ipw_read_indirect(__FILE__, __LINE__, a, b, c, d)
static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data,
int num);
#define ipw_write_indirect(a, b, c, d) \
IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \
- _ipw_write_indirect(a, b, c, d)
+ _ipw_write_indirect(a, b, c, d)
/* indirect write s */
static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value)
{
IPW_DEBUG_IO(" %p : reg = 0x%8X : value = 0x%8X\n", priv, reg, value);
- _ipw_write32(priv, CX2_INDIRECT_ADDR, reg);
- _ipw_write32(priv, CX2_INDIRECT_DATA, value);
+ _ipw_write32(priv, IPW_INDIRECT_ADDR, reg);
+ _ipw_write32(priv, IPW_INDIRECT_DATA, value);
}
static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value)
{
IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value);
- _ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK);
- _ipw_write8(priv, CX2_INDIRECT_DATA, value);
- IPW_DEBUG_IO(" reg = 0x%8lX : value = 0x%8X\n",
- (unsigned long)(priv->hw_base + CX2_INDIRECT_DATA), value);
+ _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK);
+ _ipw_write8(priv, IPW_INDIRECT_DATA, value);
}
static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value)
{
IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value);
- _ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK);
- _ipw_write16(priv, CX2_INDIRECT_DATA, value);
+ _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK);
+ _ipw_write16(priv, IPW_INDIRECT_DATA, value);
}
/* indirect read s */
@@ -265,9 +343,9 @@ static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value)
static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg)
{
u32 word;
- _ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK);
+ _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK);
IPW_DEBUG_IO(" reg = 0x%8X : \n", reg);
- word = _ipw_read32(priv, CX2_INDIRECT_DATA);
+ word = _ipw_read32(priv, IPW_INDIRECT_DATA);
return (word >> ((reg & 0x3) * 8)) & 0xff;
}
@@ -277,8 +355,8 @@ static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg)
IPW_DEBUG_IO("%p : reg = 0x%08x\n", priv, reg);
- _ipw_write32(priv, CX2_INDIRECT_ADDR, reg);
- value = _ipw_read32(priv, CX2_INDIRECT_DATA);
+ _ipw_write32(priv, IPW_INDIRECT_ADDR, reg);
+ value = _ipw_read32(priv, IPW_INDIRECT_DATA);
IPW_DEBUG_IO(" reg = 0x%4X : value = 0x%4x \n", reg, value);
return value;
}
@@ -287,67 +365,69 @@ static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg)
static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf,
int num)
{
- u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK;
+ u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK;
u32 dif_len = addr - aligned_addr;
- u32 aligned_len;
u32 i;
IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num);
+ if (num <= 0) {
+ return;
+ }
+
/* Read the first nibble byte by byte */
if (unlikely(dif_len)) {
+ _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
/* Start reading at aligned_addr + dif_len */
- _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr);
- for (i = dif_len; i < 4; i++, buf++)
- *buf = _ipw_read8(priv, CX2_INDIRECT_DATA + i);
- num -= dif_len;
+ for (i = dif_len; ((i < 4) && (num > 0)); i++, num--)
+ *buf++ = _ipw_read8(priv, IPW_INDIRECT_DATA + i);
aligned_addr += 4;
}
- /* Read DWs through autoinc register */
- _ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr);
- aligned_len = num & CX2_INDIRECT_ADDR_MASK;
- for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
- *(u32 *) buf = ipw_read32(priv, CX2_AUTOINC_DATA);
+ _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr);
+ for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4)
+ *(u32 *) buf = _ipw_read32(priv, IPW_AUTOINC_DATA);
/* Copy the last nibble */
- dif_len = num - aligned_len;
- _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr);
- for (i = 0; i < dif_len; i++, buf++)
- *buf = ipw_read8(priv, CX2_INDIRECT_DATA + i);
+ if (unlikely(num)) {
+ _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
+ for (i = 0; num > 0; i++, num--)
+ *buf++ = ipw_read8(priv, IPW_INDIRECT_DATA + i);
+ }
}
static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf,
int num)
{
- u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK;
+ u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK;
u32 dif_len = addr - aligned_addr;
- u32 aligned_len;
u32 i;
IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num);
+ if (num <= 0) {
+ return;
+ }
+
/* Write the first nibble byte by byte */
if (unlikely(dif_len)) {
- /* Start writing at aligned_addr + dif_len */
- _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr);
- for (i = dif_len; i < 4; i++, buf++)
- _ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf);
- num -= dif_len;
+ _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
+ /* Start reading at aligned_addr + dif_len */
+ for (i = dif_len; ((i < 4) && (num > 0)); i++, num--, buf++)
+ _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf);
aligned_addr += 4;
}
- /* Write DWs through autoinc register */
- _ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr);
- aligned_len = num & CX2_INDIRECT_ADDR_MASK;
- for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
- _ipw_write32(priv, CX2_AUTOINC_DATA, *(u32 *) buf);
+ _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr);
+ for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4)
+ _ipw_write32(priv, IPW_AUTOINC_DATA, *(u32 *) buf);
/* Copy the last nibble */
- dif_len = num - aligned_len;
- _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr);
- for (i = 0; i < dif_len; i++, buf++)
- _ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf);
+ if (unlikely(num)) {
+ _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
+ for (i = 0; num > 0; i++, num--, buf++)
+ _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf);
+ }
}
static void ipw_write_direct(struct ipw_priv *priv, u32 addr, void *buf,
@@ -371,7 +451,7 @@ static inline void ipw_enable_interrupts(struct ipw_priv *priv)
if (priv->status & STATUS_INT_ENABLED)
return;
priv->status |= STATUS_INT_ENABLED;
- ipw_write32(priv, CX2_INTA_MASK_R, CX2_INTA_MASK_ALL);
+ ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL);
}
static inline void ipw_disable_interrupts(struct ipw_priv *priv)
@@ -379,9 +459,10 @@ static inline void ipw_disable_interrupts(struct ipw_priv *priv)
if (!(priv->status & STATUS_INT_ENABLED))
return;
priv->status &= ~STATUS_INT_ENABLED;
- ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL);
+ ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
}
+#ifdef CONFIG_IPW_DEBUG
static char *ipw_error_desc(u32 val)
{
switch (val) {
@@ -394,81 +475,65 @@ static char *ipw_error_desc(u32 val)
case IPW_FW_ERROR_MEMORY_OVERFLOW:
return "MEMORY_OVERFLOW";
case IPW_FW_ERROR_BAD_PARAM:
- return "ERROR_BAD_PARAM";
+ return "BAD_PARAM";
case IPW_FW_ERROR_BAD_CHECKSUM:
- return "ERROR_BAD_CHECKSUM";
+ return "BAD_CHECKSUM";
case IPW_FW_ERROR_NMI_INTERRUPT:
- return "ERROR_NMI_INTERRUPT";
+ return "NMI_INTERRUPT";
case IPW_FW_ERROR_BAD_DATABASE:
- return "ERROR_BAD_DATABASE";
+ return "BAD_DATABASE";
case IPW_FW_ERROR_ALLOC_FAIL:
- return "ERROR_ALLOC_FAIL";
+ return "ALLOC_FAIL";
case IPW_FW_ERROR_DMA_UNDERRUN:
- return "ERROR_DMA_UNDERRUN";
+ return "DMA_UNDERRUN";
case IPW_FW_ERROR_DMA_STATUS:
- return "ERROR_DMA_STATUS";
- case IPW_FW_ERROR_DINOSTATUS_ERROR:
- return "ERROR_DINOSTATUS_ERROR";
- case IPW_FW_ERROR_EEPROMSTATUS_ERROR:
- return "ERROR_EEPROMSTATUS_ERROR";
+ return "DMA_STATUS";
+ case IPW_FW_ERROR_DINO_ERROR:
+ return "DINO_ERROR";
+ case IPW_FW_ERROR_EEPROM_ERROR:
+ return "EEPROM_ERROR";
case IPW_FW_ERROR_SYSASSERT:
- return "ERROR_SYSASSERT";
+ return "SYSASSERT";
case IPW_FW_ERROR_FATAL_ERROR:
- return "ERROR_FATALSTATUS_ERROR";
+ return "FATAL_ERROR";
default:
- return "UNKNOWNSTATUS_ERROR";
+ return "UNKNOWN_ERROR";
}
}
-static void ipw_dump_nic_error_log(struct ipw_priv *priv)
+static void ipw_dump_error_log(struct ipw_priv *priv,
+ struct ipw_fw_error *error)
{
- u32 desc, time, blink1, blink2, ilink1, ilink2, idata, i, count, base;
-
- base = ipw_read32(priv, IPWSTATUS_ERROR_LOG);
- count = ipw_read_reg32(priv, base);
+ u32 i;
- if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
- IPW_ERROR("Start IPW Error Log Dump:\n");
- IPW_ERROR("Status: 0x%08X, Config: %08X\n",
- priv->status, priv->config);
+ if (!error) {
+ IPW_ERROR("Error allocating and capturing error log. "
+ "Nothing to dump.\n");
+ return;
}
- for (i = ERROR_START_OFFSET;
- i <= count * ERROR_ELEM_SIZE; i += ERROR_ELEM_SIZE) {
- desc = ipw_read_reg32(priv, base + i);
- time = ipw_read_reg32(priv, base + i + 1 * sizeof(u32));
- blink1 = ipw_read_reg32(priv, base + i + 2 * sizeof(u32));
- blink2 = ipw_read_reg32(priv, base + i + 3 * sizeof(u32));
- ilink1 = ipw_read_reg32(priv, base + i + 4 * sizeof(u32));
- ilink2 = ipw_read_reg32(priv, base + i + 5 * sizeof(u32));
- idata = ipw_read_reg32(priv, base + i + 6 * sizeof(u32));
+ IPW_ERROR("Start IPW Error Log Dump:\n");
+ IPW_ERROR("Status: 0x%08X, Config: %08X\n",
+ error->status, error->config);
+ for (i = 0; i < error->elem_len; i++)
IPW_ERROR("%s %i 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
- ipw_error_desc(desc), time, blink1, blink2,
- ilink1, ilink2, idata);
- }
+ ipw_error_desc(error->elem[i].desc),
+ error->elem[i].time,
+ error->elem[i].blink1,
+ error->elem[i].blink2,
+ error->elem[i].link1,
+ error->elem[i].link2, error->elem[i].data);
+ for (i = 0; i < error->log_len; i++)
+ IPW_ERROR("%i\t0x%08x\t%i\n",
+ error->log[i].time,
+ error->log[i].data, error->log[i].event);
}
+#endif
-static void ipw_dump_nic_event_log(struct ipw_priv *priv)
+static inline int ipw_is_init(struct ipw_priv *priv)
{
- u32 ev, time, data, i, count, base;
-
- base = ipw_read32(priv, IPW_EVENT_LOG);
- count = ipw_read_reg32(priv, base);
-
- if (EVENT_START_OFFSET <= count * EVENT_ELEM_SIZE)
- IPW_ERROR("Start IPW Event Log Dump:\n");
-
- for (i = EVENT_START_OFFSET;
- i <= count * EVENT_ELEM_SIZE; i += EVENT_ELEM_SIZE) {
- ev = ipw_read_reg32(priv, base + i);
- time = ipw_read_reg32(priv, base + i + 1 * sizeof(u32));
- data = ipw_read_reg32(priv, base + i + 2 * sizeof(u32));
-
-#ifdef CONFIG_IPW_DEBUG
- IPW_ERROR("%i\t0x%08x\t%i\n", time, data, ev);
-#endif
- }
+ return (priv->status & STATUS_INIT) ? 1 : 0;
}
static int ipw_get_ordinal(struct ipw_priv *priv, u32 ord, void *val, u32 * len)
@@ -636,6 +701,340 @@ static void ipw_init_ordinals(struct ipw_priv *priv)
}
+u32 ipw_register_toggle(u32 reg)
+{
+ reg &= ~IPW_START_STANDBY;
+ if (reg & IPW_GATE_ODMA)
+ reg &= ~IPW_GATE_ODMA;
+ if (reg & IPW_GATE_IDMA)
+ reg &= ~IPW_GATE_IDMA;
+ if (reg & IPW_GATE_ADMA)
+ reg &= ~IPW_GATE_ADMA;
+ return reg;
+}
+
+/*
+ * LED behavior:
+ * - On radio ON, turn on any LEDs that require to be on during start
+ * - On initialization, start unassociated blink
+ * - On association, disable unassociated blink
+ * - On disassociation, start unassociated blink
+ * - On radio OFF, turn off any LEDs started during radio on
+ *
+ */
+#define LD_TIME_LINK_ON 300
+#define LD_TIME_LINK_OFF 2700
+#define LD_TIME_ACT_ON 250
+
+void ipw_led_link_on(struct ipw_priv *priv)
+{
+ unsigned long flags;
+ u32 led;
+
+ /* If configured to not use LEDs, or nic_type is 1,
+ * then we don't toggle a LINK led */
+ if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1)
+ return;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (!(priv->status & STATUS_RF_KILL_MASK) &&
+ !(priv->status & STATUS_LED_LINK_ON)) {
+ IPW_DEBUG_LED("Link LED On\n");
+ led = ipw_read_reg32(priv, IPW_EVENT_REG);
+ led |= priv->led_association_on;
+
+ led = ipw_register_toggle(led);
+
+ IPW_DEBUG_LED("Reg: 0x%08X\n", led);
+ ipw_write_reg32(priv, IPW_EVENT_REG, led);
+
+ priv->status |= STATUS_LED_LINK_ON;
+
+ /* If we aren't associated, schedule turning the LED off */
+ if (!(priv->status & STATUS_ASSOCIATED))
+ queue_delayed_work(priv->workqueue,
+ &priv->led_link_off,
+ LD_TIME_LINK_ON);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void ipw_bg_led_link_on(void *data)
+{
+ struct ipw_priv *priv = data;
+ down(&priv->sem);
+ ipw_led_link_on(data);
+ up(&priv->sem);
+}
+
+void ipw_led_link_off(struct ipw_priv *priv)
+{
+ unsigned long flags;
+ u32 led;
+
+ /* If configured not to use LEDs, or nic type is 1,
+ * then we don't goggle the LINK led. */
+ if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1)
+ return;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->status & STATUS_LED_LINK_ON) {
+ led = ipw_read_reg32(priv, IPW_EVENT_REG);
+ led &= priv->led_association_off;
+ led = ipw_register_toggle(led);
+
+ IPW_DEBUG_LED("Reg: 0x%08X\n", led);
+ ipw_write_reg32(priv, IPW_EVENT_REG, led);
+
+ IPW_DEBUG_LED("Link LED Off\n");
+
+ priv->status &= ~STATUS_LED_LINK_ON;
+
+ /* If we aren't associated and the radio is on, schedule
+ * turning the LED on (blink while unassociated) */
+ if (!(priv->status & STATUS_RF_KILL_MASK) &&
+ !(priv->status & STATUS_ASSOCIATED))
+ queue_delayed_work(priv->workqueue, &priv->led_link_on,
+ LD_TIME_LINK_OFF);
+
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void ipw_bg_led_link_off(void *data)
+{
+ struct ipw_priv *priv = data;
+ down(&priv->sem);
+ ipw_led_link_off(data);
+ up(&priv->sem);
+}
+
+static inline void __ipw_led_activity_on(struct ipw_priv *priv)
+{
+ u32 led;
+
+ if (priv->config & CFG_NO_LED)
+ return;
+
+ if (priv->status & STATUS_RF_KILL_MASK)
+ return;
+
+ if (!(priv->status & STATUS_LED_ACT_ON)) {
+ led = ipw_read_reg32(priv, IPW_EVENT_REG);
+ led |= priv->led_activity_on;
+
+ led = ipw_register_toggle(led);
+
+ IPW_DEBUG_LED("Reg: 0x%08X\n", led);
+ ipw_write_reg32(priv, IPW_EVENT_REG, led);
+
+ IPW_DEBUG_LED("Activity LED On\n");
+
+ priv->status |= STATUS_LED_ACT_ON;
+
+ cancel_delayed_work(&priv->led_act_off);
+ queue_delayed_work(priv->workqueue, &priv->led_act_off,
+ LD_TIME_ACT_ON);
+ } else {
+ /* Reschedule LED off for full time period */
+ cancel_delayed_work(&priv->led_act_off);
+ queue_delayed_work(priv->workqueue, &priv->led_act_off,
+ LD_TIME_ACT_ON);
+ }
+}
+
+void ipw_led_activity_on(struct ipw_priv *priv)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&priv->lock, flags);
+ __ipw_led_activity_on(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+void ipw_led_activity_off(struct ipw_priv *priv)
+{
+ unsigned long flags;
+ u32 led;
+
+ if (priv->config & CFG_NO_LED)
+ return;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->status & STATUS_LED_ACT_ON) {
+ led = ipw_read_reg32(priv, IPW_EVENT_REG);
+ led &= priv->led_activity_off;
+
+ led = ipw_register_toggle(led);
+
+ IPW_DEBUG_LED("Reg: 0x%08X\n", led);
+ ipw_write_reg32(priv, IPW_EVENT_REG, led);
+
+ IPW_DEBUG_LED("Activity LED Off\n");
+
+ priv->status &= ~STATUS_LED_ACT_ON;
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void ipw_bg_led_activity_off(void *data)
+{
+ struct ipw_priv *priv = data;
+ down(&priv->sem);
+ ipw_led_activity_off(data);
+ up(&priv->sem);
+}
+
+void ipw_led_band_on(struct ipw_priv *priv)
+{
+ unsigned long flags;
+ u32 led;
+
+ /* Only nic type 1 supports mode LEDs */
+ if (priv->config & CFG_NO_LED ||
+ priv->nic_type != EEPROM_NIC_TYPE_1 || !priv->assoc_network)
+ return;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ led = ipw_read_reg32(priv, IPW_EVENT_REG);
+ if (priv->assoc_network->mode == IEEE_A) {
+ led |= priv->led_ofdm_on;
+ led &= priv->led_association_off;
+ IPW_DEBUG_LED("Mode LED On: 802.11a\n");
+ } else if (priv->assoc_network->mode == IEEE_G) {
+ led |= priv->led_ofdm_on;
+ led |= priv->led_association_on;
+ IPW_DEBUG_LED("Mode LED On: 802.11g\n");
+ } else {
+ led &= priv->led_ofdm_off;
+ led |= priv->led_association_on;
+ IPW_DEBUG_LED("Mode LED On: 802.11b\n");
+ }
+
+ led = ipw_register_toggle(led);
+
+ IPW_DEBUG_LED("Reg: 0x%08X\n", led);
+ ipw_write_reg32(priv, IPW_EVENT_REG, led);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+void ipw_led_band_off(struct ipw_priv *priv)
+{
+ unsigned long flags;
+ u32 led;
+
+ /* Only nic type 1 supports mode LEDs */
+ if (priv->config & CFG_NO_LED || priv->nic_type != EEPROM_NIC_TYPE_1)
+ return;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ led = ipw_read_reg32(priv, IPW_EVENT_REG);
+ led &= priv->led_ofdm_off;
+ led &= priv->led_association_off;
+
+ led = ipw_register_toggle(led);
+
+ IPW_DEBUG_LED("Reg: 0x%08X\n", led);
+ ipw_write_reg32(priv, IPW_EVENT_REG, led);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+void ipw_led_radio_on(struct ipw_priv *priv)
+{
+ ipw_led_link_on(priv);
+}
+
+void ipw_led_radio_off(struct ipw_priv *priv)
+{
+ ipw_led_activity_off(priv);
+ ipw_led_link_off(priv);
+}
+
+void ipw_led_link_up(struct ipw_priv *priv)
+{
+ /* Set the Link Led on for all nic types */
+ ipw_led_link_on(priv);
+}
+
+void ipw_led_link_down(struct ipw_priv *priv)
+{
+ ipw_led_activity_off(priv);
+ ipw_led_link_off(priv);
+
+ if (priv->status & STATUS_RF_KILL_MASK)
+ ipw_led_radio_off(priv);
+}
+
+void ipw_led_init(struct ipw_priv *priv)
+{
+ priv->nic_type = priv->eeprom[EEPROM_NIC_TYPE];
+
+ /* Set the default PINs for the link and activity leds */
+ priv->led_activity_on = IPW_ACTIVITY_LED;
+ priv->led_activity_off = ~(IPW_ACTIVITY_LED);
+
+ priv->led_association_on = IPW_ASSOCIATED_LED;
+ priv->led_association_off = ~(IPW_ASSOCIATED_LED);
+
+ /* Set the default PINs for the OFDM leds */
+ priv->led_ofdm_on = IPW_OFDM_LED;
+ priv->led_ofdm_off = ~(IPW_OFDM_LED);
+
+ switch (priv->nic_type) {
+ case EEPROM_NIC_TYPE_1:
+ /* In this NIC type, the LEDs are reversed.... */
+ priv->led_activity_on = IPW_ASSOCIATED_LED;
+ priv->led_activity_off = ~(IPW_ASSOCIATED_LED);
+ priv->led_association_on = IPW_ACTIVITY_LED;
+ priv->led_association_off = ~(IPW_ACTIVITY_LED);
+
+ if (!(priv->config & CFG_NO_LED))
+ ipw_led_band_on(priv);
+
+ /* And we don't blink link LEDs for this nic, so
+ * just return here */
+ return;
+
+ case EEPROM_NIC_TYPE_3:
+ case EEPROM_NIC_TYPE_2:
+ case EEPROM_NIC_TYPE_4:
+ case EEPROM_NIC_TYPE_0:
+ break;
+
+ default:
+ IPW_DEBUG_INFO("Unknown NIC type from EEPROM: %d\n",
+ priv->nic_type);
+ priv->nic_type = EEPROM_NIC_TYPE_0;
+ break;
+ }
+
+ if (!(priv->config & CFG_NO_LED)) {
+ if (priv->status & STATUS_ASSOCIATED)
+ ipw_led_link_on(priv);
+ else
+ ipw_led_link_off(priv);
+ }
+}
+
+void ipw_led_shutdown(struct ipw_priv *priv)
+{
+ ipw_led_activity_off(priv);
+ ipw_led_link_off(priv);
+ ipw_led_band_off(priv);
+ cancel_delayed_work(&priv->led_link_on);
+ cancel_delayed_work(&priv->led_link_off);
+ cancel_delayed_work(&priv->led_act_off);
+}
+
/*
* The following adds a new attribute to the sysfs representation
* of this device driver (i.e. a new file in /sys/bus/pci/drivers/ipw/)
@@ -647,8 +1046,9 @@ static ssize_t show_debug_level(struct device_driver *d, char *buf)
{
return sprintf(buf, "0x%08X\n", ipw_debug_level);
}
-static ssize_t store_debug_level(struct device_driver *d,
- const char *buf, size_t count)
+
+static ssize_t store_debug_level(struct device_driver *d, const char *buf,
+ size_t count)
{
char *p = (char *)buf;
u32 val;
@@ -672,75 +1072,263 @@ static ssize_t store_debug_level(struct device_driver *d,
static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
show_debug_level, store_debug_level);
-static ssize_t show_status(struct device *d,
- struct device_attribute *attr, char *buf)
+static inline u32 ipw_get_event_log_len(struct ipw_priv *priv)
{
- struct ipw_priv *p = d->driver_data;
- return sprintf(buf, "0x%08x\n", (int)p->status);
+ return ipw_read_reg32(priv, ipw_read32(priv, IPW_EVENT_LOG));
}
-static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+static void ipw_capture_event_log(struct ipw_priv *priv,
+ u32 log_len, struct ipw_event *log)
+{
+ u32 base;
-static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
- char *buf)
+ if (log_len) {
+ base = ipw_read32(priv, IPW_EVENT_LOG);
+ ipw_read_indirect(priv, base + sizeof(base) + sizeof(u32),
+ (u8 *) log, sizeof(*log) * log_len);
+ }
+}
+
+static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv)
{
- struct ipw_priv *p = d->driver_data;
- return sprintf(buf, "0x%08x\n", (int)p->config);
+ struct ipw_fw_error *error;
+ u32 log_len = ipw_get_event_log_len(priv);
+ u32 base = ipw_read32(priv, IPW_ERROR_LOG);
+ u32 elem_len = ipw_read_reg32(priv, base);
+
+ error = kmalloc(sizeof(*error) +
+ sizeof(*error->elem) * elem_len +
+ sizeof(*error->log) * log_len, GFP_ATOMIC);
+ if (!error) {
+ IPW_ERROR("Memory allocation for firmware error log "
+ "failed.\n");
+ return NULL;
+ }
+ error->jiffies = jiffies;
+ error->status = priv->status;
+ error->config = priv->config;
+ error->elem_len = elem_len;
+ error->log_len = log_len;
+ error->elem = (struct ipw_error_elem *)error->payload;
+ error->log = (struct ipw_event *)(error->elem +
+ (sizeof(*error->elem) * elem_len));
+
+ ipw_capture_event_log(priv, log_len, error->log);
+
+ if (elem_len)
+ ipw_read_indirect(priv, base + sizeof(base), (u8 *) error->elem,
+ sizeof(*error->elem) * elem_len);
+
+ return error;
}
-static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL);
+static void ipw_free_error_log(struct ipw_fw_error *error)
+{
+ if (error)
+ kfree(error);
+}
-static ssize_t show_nic_type(struct device *d,
- struct device_attribute *attr, char *buf)
+static ssize_t show_event_log(struct device *d,
+ struct device_attribute *attr, char *buf)
{
- struct ipw_priv *p = d->driver_data;
- u8 type = p->eeprom[EEPROM_NIC_TYPE];
+ struct ipw_priv *priv = dev_get_drvdata(d);
+ u32 log_len = ipw_get_event_log_len(priv);
+ struct ipw_event log[log_len];
+ u32 len = 0, i;
+
+ ipw_capture_event_log(priv, log_len, log);
+
+ len += snprintf(buf + len, PAGE_SIZE - len, "%08X", log_len);
+ for (i = 0; i < log_len; i++)
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "\n%08X%08X%08X",
+ log[i].time, log[i].event, log[i].data);
+ len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+ return len;
+}
- switch (type) {
- case EEPROM_NIC_TYPE_STANDARD:
- return sprintf(buf, "STANDARD\n");
- case EEPROM_NIC_TYPE_DELL:
- return sprintf(buf, "DELL\n");
- case EEPROM_NIC_TYPE_FUJITSU:
- return sprintf(buf, "FUJITSU\n");
- case EEPROM_NIC_TYPE_IBM:
- return sprintf(buf, "IBM\n");
- case EEPROM_NIC_TYPE_HP:
- return sprintf(buf, "HP\n");
+static DEVICE_ATTR(event_log, S_IRUGO, show_event_log, NULL);
+
+static ssize_t show_error(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct ipw_priv *priv = dev_get_drvdata(d);
+ u32 len = 0, i;
+ if (!priv->error)
+ return 0;
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "%08lX%08X%08X%08X",
+ priv->error->jiffies,
+ priv->error->status,
+ priv->error->config, priv->error->elem_len);
+ for (i = 0; i < priv->error->elem_len; i++)
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "\n%08X%08X%08X%08X%08X%08X%08X",
+ priv->error->elem[i].time,
+ priv->error->elem[i].desc,
+ priv->error->elem[i].blink1,
+ priv->error->elem[i].blink2,
+ priv->error->elem[i].link1,
+ priv->error->elem[i].link2,
+ priv->error->elem[i].data);
+
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "\n%08X", priv->error->log_len);
+ for (i = 0; i < priv->error->log_len; i++)
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "\n%08X%08X%08X",
+ priv->error->log[i].time,
+ priv->error->log[i].event,
+ priv->error->log[i].data);
+ len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+ return len;
+}
+
+static ssize_t clear_error(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ipw_priv *priv = dev_get_drvdata(d);
+ if (priv->error) {
+ ipw_free_error_log(priv->error);
+ priv->error = NULL;
}
+ return count;
+}
+
+static DEVICE_ATTR(error, S_IRUGO | S_IWUSR, show_error, clear_error);
- return sprintf(buf, "UNKNOWN\n");
+static ssize_t show_cmd_log(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct ipw_priv *priv = dev_get_drvdata(d);
+ u32 len = 0, i;
+ if (!priv->cmdlog)
+ return 0;
+ for (i = (priv->cmdlog_pos + 1) % priv->cmdlog_len;
+ (i != priv->cmdlog_pos) && (PAGE_SIZE - len);
+ i = (i + 1) % priv->cmdlog_len) {
+ len +=
+ snprintf(buf + len, PAGE_SIZE - len,
+ "\n%08lX%08X%08X%08X\n", priv->cmdlog[i].jiffies,
+ priv->cmdlog[i].retcode, priv->cmdlog[i].cmd.cmd,
+ priv->cmdlog[i].cmd.len);
+ len +=
+ snprintk_buf(buf + len, PAGE_SIZE - len,
+ (u8 *) priv->cmdlog[i].cmd.param,
+ priv->cmdlog[i].cmd.len);
+ len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+ }
+ len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+ return len;
}
-static DEVICE_ATTR(nic_type, S_IRUGO, show_nic_type, NULL);
+static DEVICE_ATTR(cmd_log, S_IRUGO, show_cmd_log, NULL);
-static ssize_t dump_error_log(struct device *d,
- struct device_attribute *attr, const char *buf,
- size_t count)
+static ssize_t show_scan_age(struct device *d, struct device_attribute *attr,
+ char *buf)
{
- char *p = (char *)buf;
+ struct ipw_priv *priv = dev_get_drvdata(d);
+ return sprintf(buf, "%d\n", priv->ieee->scan_age);
+}
- if (p[0] == '1')
- ipw_dump_nic_error_log((struct ipw_priv *)d->driver_data);
+static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ipw_priv *priv = dev_get_drvdata(d);
+#ifdef CONFIG_IPW_DEBUG
+ struct net_device *dev = priv->net_dev;
+#endif
+ char buffer[] = "00000000";
+ unsigned long len =
+ (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1;
+ unsigned long val;
+ char *p = buffer;
- return strnlen(buf, count);
+ IPW_DEBUG_INFO("enter\n");
+
+ strncpy(buffer, buf, len);
+ buffer[len] = 0;
+
+ if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
+ p++;
+ if (p[0] == 'x' || p[0] == 'X')
+ p++;
+ val = simple_strtoul(p, &p, 16);
+ } else
+ val = simple_strtoul(p, &p, 10);
+ if (p == buffer) {
+ IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name);
+ } else {
+ priv->ieee->scan_age = val;
+ IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age);
+ }
+
+ IPW_DEBUG_INFO("exit\n");
+ return len;
}
-static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log);
+static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age);
-static ssize_t dump_event_log(struct device *d,
- struct device_attribute *attr, const char *buf,
- size_t count)
+static ssize_t show_led(struct device *d, struct device_attribute *attr,
+ char *buf)
{
- char *p = (char *)buf;
+ struct ipw_priv *priv = dev_get_drvdata(d);
+ return sprintf(buf, "%d\n", (priv->config & CFG_NO_LED) ? 0 : 1);
+}
- if (p[0] == '1')
- ipw_dump_nic_event_log((struct ipw_priv *)d->driver_data);
+static ssize_t store_led(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ipw_priv *priv = dev_get_drvdata(d);
- return strnlen(buf, count);
+ IPW_DEBUG_INFO("enter\n");
+
+ if (count == 0)
+ return 0;
+
+ if (*buf == 0) {
+ IPW_DEBUG_LED("Disabling LED control.\n");
+ priv->config |= CFG_NO_LED;
+ ipw_led_shutdown(priv);
+ } else {
+ IPW_DEBUG_LED("Enabling LED control.\n");
+ priv->config &= ~CFG_NO_LED;
+ ipw_led_init(priv);
+ }
+
+ IPW_DEBUG_INFO("exit\n");
+ return count;
+}
+
+static DEVICE_ATTR(led, S_IWUSR | S_IRUGO, show_led, store_led);
+
+static ssize_t show_status(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct ipw_priv *p = d->driver_data;
+ return sprintf(buf, "0x%08x\n", (int)p->status);
}
-static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
+static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw_priv *p = d->driver_data;
+ return sprintf(buf, "0x%08x\n", (int)p->config);
+}
+
+static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL);
+
+static ssize_t show_nic_type(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct ipw_priv *priv = d->driver_data;
+ return sprintf(buf, "TYPE: %d\n", priv->nic_type);
+}
+
+static DEVICE_ATTR(nic_type, S_IRUGO, show_nic_type, NULL);
static ssize_t show_ucode_version(struct device *d,
struct device_attribute *attr, char *buf)
@@ -798,7 +1386,7 @@ static ssize_t show_command_event_reg(struct device *d,
u32 reg = 0;
struct ipw_priv *p = d->driver_data;
- reg = ipw_read_reg32(p, CX2_INTERNAL_CMD_EVENT);
+ reg = ipw_read_reg32(p, IPW_INTERNAL_CMD_EVENT);
return sprintf(buf, "0x%08x\n", reg);
}
static ssize_t store_command_event_reg(struct device *d,
@@ -809,7 +1397,7 @@ static ssize_t store_command_event_reg(struct device *d,
struct ipw_priv *p = d->driver_data;
sscanf(buf, "%x", &reg);
- ipw_write_reg32(p, CX2_INTERNAL_CMD_EVENT, reg);
+ ipw_write_reg32(p, IPW_INTERNAL_CMD_EVENT, reg);
return strnlen(buf, count);
}
@@ -845,6 +1433,7 @@ static ssize_t show_indirect_dword(struct device *d,
{
u32 reg = 0;
struct ipw_priv *priv = d->driver_data;
+
if (priv->status & STATUS_INDIRECT_DWORD)
reg = ipw_read_reg32(priv, priv->indirect_dword);
else
@@ -871,6 +1460,7 @@ static ssize_t show_indirect_byte(struct device *d,
{
u8 reg = 0;
struct ipw_priv *priv = d->driver_data;
+
if (priv->status & STATUS_INDIRECT_BYTE)
reg = ipw_read_reg8(priv, priv->indirect_byte);
else
@@ -945,7 +1535,7 @@ static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr,
static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
{
if ((disable_radio ? 1 : 0) ==
- (priv->status & STATUS_RF_KILL_SW ? 1 : 0))
+ ((priv->status & STATUS_RF_KILL_SW) ? 1 : 0))
return 0;
IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n",
@@ -954,10 +1544,8 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
if (disable_radio) {
priv->status |= STATUS_RF_KILL_SW;
- if (priv->workqueue) {
+ if (priv->workqueue)
cancel_delayed_work(&priv->request_scan);
- }
- wake_up_interruptible(&priv->wait_command_queue);
queue_work(priv->workqueue, &priv->down);
} else {
priv->status &= ~STATUS_RF_KILL_SW;
@@ -987,6 +1575,93 @@ static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr,
static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
+static ssize_t show_speed_scan(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw_priv *priv = (struct ipw_priv *)d->driver_data;
+ int pos = 0, len = 0;
+ if (priv->config & CFG_SPEED_SCAN) {
+ while (priv->speed_scan[pos] != 0)
+ len += sprintf(&buf[len], "%d ",
+ priv->speed_scan[pos++]);
+ return len + sprintf(&buf[len], "\n");
+ }
+
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t store_speed_scan(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ipw_priv *priv = (struct ipw_priv *)d->driver_data;
+ int channel, pos = 0;
+ const char *p = buf;
+
+ /* list of space separated channels to scan, optionally ending with 0 */
+ while ((channel = simple_strtol(p, NULL, 0))) {
+ if (pos == MAX_SPEED_SCAN - 1) {
+ priv->speed_scan[pos] = 0;
+ break;
+ }
+
+ if (ipw_is_valid_channel(priv->ieee, channel))
+ priv->speed_scan[pos++] = channel;
+ else
+ IPW_WARNING("Skipping invalid channel request: %d\n",
+ channel);
+ p = strchr(p, ' ');
+ if (!p)
+ break;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ }
+
+ if (pos == 0)
+ priv->config &= ~CFG_SPEED_SCAN;
+ else {
+ priv->speed_scan_pos = 0;
+ priv->config |= CFG_SPEED_SCAN;
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(speed_scan, S_IWUSR | S_IRUGO, show_speed_scan,
+ store_speed_scan);
+
+static ssize_t show_net_stats(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw_priv *priv = (struct ipw_priv *)d->driver_data;
+ return sprintf(buf, "%c\n", (priv->config & CFG_NET_STATS) ? '1' : '0');
+}
+
+static ssize_t store_net_stats(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ipw_priv *priv = (struct ipw_priv *)d->driver_data;
+ if (buf[0] == '1')
+ priv->config |= CFG_NET_STATS;
+ else
+ priv->config &= ~CFG_NET_STATS;
+
+ return count;
+}
+
+static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO,
+ show_net_stats, store_net_stats);
+
+static void notify_wx_assoc_event(struct ipw_priv *priv)
+{
+ union iwreq_data wrqu;
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ if (priv->status & STATUS_ASSOCIATED)
+ memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
+ else
+ memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+ wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
+}
+
static void ipw_irq_tasklet(struct ipw_priv *priv)
{
u32 inta, inta_mask, handled = 0;
@@ -995,102 +1670,135 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
spin_lock_irqsave(&priv->lock, flags);
- inta = ipw_read32(priv, CX2_INTA_RW);
- inta_mask = ipw_read32(priv, CX2_INTA_MASK_R);
- inta &= (CX2_INTA_MASK_ALL & inta_mask);
+ inta = ipw_read32(priv, IPW_INTA_RW);
+ inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
+ inta &= (IPW_INTA_MASK_ALL & inta_mask);
/* Add any cached INTA values that need to be handled */
inta |= priv->isr_inta;
/* handle all the justifications for the interrupt */
- if (inta & CX2_INTA_BIT_RX_TRANSFER) {
+ if (inta & IPW_INTA_BIT_RX_TRANSFER) {
ipw_rx(priv);
- handled |= CX2_INTA_BIT_RX_TRANSFER;
+ handled |= IPW_INTA_BIT_RX_TRANSFER;
}
- if (inta & CX2_INTA_BIT_TX_CMD_QUEUE) {
+ if (inta & IPW_INTA_BIT_TX_CMD_QUEUE) {
IPW_DEBUG_HC("Command completed.\n");
rc = ipw_queue_tx_reclaim(priv, &priv->txq_cmd, -1);
priv->status &= ~STATUS_HCMD_ACTIVE;
wake_up_interruptible(&priv->wait_command_queue);
- handled |= CX2_INTA_BIT_TX_CMD_QUEUE;
+ handled |= IPW_INTA_BIT_TX_CMD_QUEUE;
}
- if (inta & CX2_INTA_BIT_TX_QUEUE_1) {
+ if (inta & IPW_INTA_BIT_TX_QUEUE_1) {
IPW_DEBUG_TX("TX_QUEUE_1\n");
rc = ipw_queue_tx_reclaim(priv, &priv->txq[0], 0);
- handled |= CX2_INTA_BIT_TX_QUEUE_1;
+ handled |= IPW_INTA_BIT_TX_QUEUE_1;
}
- if (inta & CX2_INTA_BIT_TX_QUEUE_2) {
+ if (inta & IPW_INTA_BIT_TX_QUEUE_2) {
IPW_DEBUG_TX("TX_QUEUE_2\n");
rc = ipw_queue_tx_reclaim(priv, &priv->txq[1], 1);
- handled |= CX2_INTA_BIT_TX_QUEUE_2;
+ handled |= IPW_INTA_BIT_TX_QUEUE_2;
}
- if (inta & CX2_INTA_BIT_TX_QUEUE_3) {
+ if (inta & IPW_INTA_BIT_TX_QUEUE_3) {
IPW_DEBUG_TX("TX_QUEUE_3\n");
rc = ipw_queue_tx_reclaim(priv, &priv->txq[2], 2);
- handled |= CX2_INTA_BIT_TX_QUEUE_3;
+ handled |= IPW_INTA_BIT_TX_QUEUE_3;
}
- if (inta & CX2_INTA_BIT_TX_QUEUE_4) {
+ if (inta & IPW_INTA_BIT_TX_QUEUE_4) {
IPW_DEBUG_TX("TX_QUEUE_4\n");
rc = ipw_queue_tx_reclaim(priv, &priv->txq[3], 3);
- handled |= CX2_INTA_BIT_TX_QUEUE_4;
+ handled |= IPW_INTA_BIT_TX_QUEUE_4;
}
- if (inta & CX2_INTA_BIT_STATUS_CHANGE) {
+ if (inta & IPW_INTA_BIT_STATUS_CHANGE) {
IPW_WARNING("STATUS_CHANGE\n");
- handled |= CX2_INTA_BIT_STATUS_CHANGE;
+ handled |= IPW_INTA_BIT_STATUS_CHANGE;
}
- if (inta & CX2_INTA_BIT_BEACON_PERIOD_EXPIRED) {
+ if (inta & IPW_INTA_BIT_BEACON_PERIOD_EXPIRED) {
IPW_WARNING("TX_PERIOD_EXPIRED\n");
- handled |= CX2_INTA_BIT_BEACON_PERIOD_EXPIRED;
+ handled |= IPW_INTA_BIT_BEACON_PERIOD_EXPIRED;
}
- if (inta & CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE) {
+ if (inta & IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE) {
IPW_WARNING("HOST_CMD_DONE\n");
- handled |= CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE;
+ handled |= IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE;
}
- if (inta & CX2_INTA_BIT_FW_INITIALIZATION_DONE) {
+ if (inta & IPW_INTA_BIT_FW_INITIALIZATION_DONE) {
IPW_WARNING("FW_INITIALIZATION_DONE\n");
- handled |= CX2_INTA_BIT_FW_INITIALIZATION_DONE;
+ handled |= IPW_INTA_BIT_FW_INITIALIZATION_DONE;
}
- if (inta & CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE) {
+ if (inta & IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE) {
IPW_WARNING("PHY_OFF_DONE\n");
- handled |= CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE;
+ handled |= IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE;
}
- if (inta & CX2_INTA_BIT_RF_KILL_DONE) {
+ if (inta & IPW_INTA_BIT_RF_KILL_DONE) {
IPW_DEBUG_RF_KILL("RF_KILL_DONE\n");
priv->status |= STATUS_RF_KILL_HW;
wake_up_interruptible(&priv->wait_command_queue);
- netif_carrier_off(priv->net_dev);
- netif_stop_queue(priv->net_dev);
+ priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
cancel_delayed_work(&priv->request_scan);
+ schedule_work(&priv->link_down);
queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ);
- handled |= CX2_INTA_BIT_RF_KILL_DONE;
+ handled |= IPW_INTA_BIT_RF_KILL_DONE;
}
- if (inta & CX2_INTA_BIT_FATAL_ERROR) {
+ if (inta & IPW_INTA_BIT_FATAL_ERROR) {
IPW_ERROR("Firmware error detected. Restarting.\n");
+ if (priv->error) {
+ IPW_ERROR("Sysfs 'error' log already exists.\n");
#ifdef CONFIG_IPW_DEBUG
- if (ipw_debug_level & IPW_DL_FW_ERRORS) {
- ipw_dump_nic_error_log(priv);
- ipw_dump_nic_event_log(priv);
- }
+ if (ipw_debug_level & IPW_DL_FW_ERRORS) {
+ struct ipw_fw_error *error =
+ ipw_alloc_error_log(priv);
+ ipw_dump_error_log(priv, error);
+ if (error)
+ ipw_free_error_log(error);
+ }
#endif
+ } else {
+ priv->error = ipw_alloc_error_log(priv);
+ if (priv->error)
+ IPW_ERROR("Sysfs 'error' log captured.\n");
+ else
+ IPW_ERROR("Error allocating sysfs 'error' "
+ "log.\n");
+#ifdef CONFIG_IPW_DEBUG
+ if (ipw_debug_level & IPW_DL_FW_ERRORS)
+ ipw_dump_error_log(priv, priv->error);
+#endif
+ }
+
+ /* XXX: If hardware encryption is for WPA/WPA2,
+ * we have to notify the supplicant. */
+ if (priv->ieee->sec.encrypt) {
+ priv->status &= ~STATUS_ASSOCIATED;
+ notify_wx_assoc_event(priv);
+ }
+
+ /* Keep the restart process from trying to send host
+ * commands by clearing the INIT status bit */
+ priv->status &= ~STATUS_INIT;
+
+ /* Cancel currently queued command. */
+ priv->status &= ~STATUS_HCMD_ACTIVE;
+ wake_up_interruptible(&priv->wait_command_queue);
+
queue_work(priv->workqueue, &priv->adapter_restart);
- handled |= CX2_INTA_BIT_FATAL_ERROR;
+ handled |= IPW_INTA_BIT_FATAL_ERROR;
}
- if (inta & CX2_INTA_BIT_PARITY_ERROR) {
+ if (inta & IPW_INTA_BIT_PARITY_ERROR) {
IPW_ERROR("Parity error\n");
- handled |= CX2_INTA_BIT_PARITY_ERROR;
+ handled |= IPW_INTA_BIT_PARITY_ERROR;
}
if (handled != inta) {
@@ -1103,7 +1811,6 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
spin_unlock_irqrestore(&priv->lock, flags);
}
-#ifdef CONFIG_IPW_DEBUG
#define IPW_CMD(x) case IPW_CMD_ ## x : return #x
static char *get_cmd_string(u8 cmd)
{
@@ -1162,44 +1869,78 @@ static char *get_cmd_string(u8 cmd)
return "UNKNOWN";
}
}
-#endif /* CONFIG_IPW_DEBUG */
#define HOST_COMPLETE_TIMEOUT HZ
static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd)
{
int rc = 0;
+ unsigned long flags;
+ spin_lock_irqsave(&priv->lock, flags);
if (priv->status & STATUS_HCMD_ACTIVE) {
- IPW_ERROR("Already sending a command\n");
- return -1;
+ IPW_ERROR("Failed to send %s: Already sending a command.\n",
+ get_cmd_string(cmd->cmd));
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return -EAGAIN;
}
priv->status |= STATUS_HCMD_ACTIVE;
- IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n",
- get_cmd_string(cmd->cmd), cmd->cmd, cmd->len);
+ if (priv->cmdlog) {
+ priv->cmdlog[priv->cmdlog_pos].jiffies = jiffies;
+ priv->cmdlog[priv->cmdlog_pos].cmd.cmd = cmd->cmd;
+ priv->cmdlog[priv->cmdlog_pos].cmd.len = cmd->len;
+ memcpy(priv->cmdlog[priv->cmdlog_pos].cmd.param, cmd->param,
+ cmd->len);
+ priv->cmdlog[priv->cmdlog_pos].retcode = -1;
+ }
+
+ IPW_DEBUG_HC("%s command (#%d) %d bytes: 0x%08X\n",
+ get_cmd_string(cmd->cmd), cmd->cmd, cmd->len,
+ priv->status);
printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len);
rc = ipw_queue_tx_hcmd(priv, cmd->cmd, &cmd->param, cmd->len, 0);
- if (rc)
- return rc;
+ if (rc) {
+ priv->status &= ~STATUS_HCMD_ACTIVE;
+ IPW_ERROR("Failed to send %s: Reason %d\n",
+ get_cmd_string(cmd->cmd), rc);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ goto exit;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
rc = wait_event_interruptible_timeout(priv->wait_command_queue,
!(priv->
status & STATUS_HCMD_ACTIVE),
HOST_COMPLETE_TIMEOUT);
if (rc == 0) {
- IPW_DEBUG_INFO("Command completion failed out after %dms.\n",
- jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
- priv->status &= ~STATUS_HCMD_ACTIVE;
- return -EIO;
- }
- if (priv->status & STATUS_RF_KILL_MASK) {
- IPW_DEBUG_INFO("Command aborted due to RF Kill Switch\n");
- return -EIO;
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->status & STATUS_HCMD_ACTIVE) {
+ IPW_ERROR("Failed to send %s: Command timed out.\n",
+ get_cmd_string(cmd->cmd));
+ priv->status &= ~STATUS_HCMD_ACTIVE;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ rc = -EIO;
+ goto exit;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ } else
+ rc = 0;
+
+ if (priv->status & STATUS_RF_KILL_HW) {
+ IPW_ERROR("Failed to send %s: Aborted due to RF kill switch.\n",
+ get_cmd_string(cmd->cmd));
+ rc = -EIO;
+ goto exit;
}
- return 0;
+ exit:
+ if (priv->cmdlog) {
+ priv->cmdlog[priv->cmdlog_pos++].retcode = rc;
+ priv->cmdlog_pos %= priv->cmdlog_len;
+ }
+ return rc;
}
static int ipw_send_host_complete(struct ipw_priv *priv)
@@ -1214,12 +1955,7 @@ static int ipw_send_host_complete(struct ipw_priv *priv)
return -1;
}
- if (ipw_send_cmd(priv, &cmd)) {
- IPW_ERROR("failed to send HOST_COMPLETE command\n");
- return -1;
- }
-
- return 0;
+ return ipw_send_cmd(priv, &cmd);
}
static int ipw_send_system_config(struct ipw_priv *priv,
@@ -1235,13 +1971,8 @@ static int ipw_send_system_config(struct ipw_priv *priv,
return -1;
}
- memcpy(&cmd.param, config, sizeof(*config));
- if (ipw_send_cmd(priv, &cmd)) {
- IPW_ERROR("failed to send SYSTEM_CONFIG command\n");
- return -1;
- }
-
- return 0;
+ memcpy(cmd.param, config, sizeof(*config));
+ return ipw_send_cmd(priv, &cmd);
}
static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len)
@@ -1256,13 +1987,8 @@ static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len)
return -1;
}
- memcpy(&cmd.param, ssid, cmd.len);
- if (ipw_send_cmd(priv, &cmd)) {
- IPW_ERROR("failed to send SSID command\n");
- return -1;
- }
-
- return 0;
+ memcpy(cmd.param, ssid, cmd.len);
+ return ipw_send_cmd(priv, &cmd);
}
static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac)
@@ -1280,16 +2006,15 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac)
IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n",
priv->net_dev->name, MAC_ARG(mac));
- memcpy(&cmd.param, mac, ETH_ALEN);
-
- if (ipw_send_cmd(priv, &cmd)) {
- IPW_ERROR("failed to send ADAPTER_ADDRESS command\n");
- return -1;
- }
-
- return 0;
+ memcpy(cmd.param, mac, ETH_ALEN);
+ return ipw_send_cmd(priv, &cmd);
}
+/*
+ * NOTE: This must be executed from our workqueue as it results in udelay
+ * being called which may corrupt the keyboard if executed on default
+ * workqueue
+ */
static void ipw_adapter_restart(void *adapter)
{
struct ipw_priv *priv = adapter;
@@ -1298,12 +2023,25 @@ static void ipw_adapter_restart(void *adapter)
return;
ipw_down(priv);
+
+ if (priv->assoc_network &&
+ (priv->assoc_network->capability & WLAN_CAPABILITY_IBSS))
+ ipw_remove_current_network(priv);
+
if (ipw_up(priv)) {
IPW_ERROR("Failed to up device\n");
return;
}
}
+static void ipw_bg_adapter_restart(void *data)
+{
+ struct ipw_priv *priv = data;
+ down(&priv->sem);
+ ipw_adapter_restart(data);
+ up(&priv->sem);
+}
+
#define IPW_SCAN_CHECK_WATCHDOG (5 * HZ)
static void ipw_scan_check(void *data)
@@ -1313,10 +2051,18 @@ static void ipw_scan_check(void *data)
IPW_DEBUG_SCAN("Scan completion watchdog resetting "
"adapter (%dms).\n",
IPW_SCAN_CHECK_WATCHDOG / 100);
- ipw_adapter_restart(priv);
+ queue_work(priv->workqueue, &priv->adapter_restart);
}
}
+static void ipw_bg_scan_check(void *data)
+{
+ struct ipw_priv *priv = data;
+ down(&priv->sem);
+ ipw_scan_check(data);
+ up(&priv->sem);
+}
+
static int ipw_send_scan_request_ext(struct ipw_priv *priv,
struct ipw_scan_request_ext *request)
{
@@ -1325,20 +2071,8 @@ static int ipw_send_scan_request_ext(struct ipw_priv *priv,
.len = sizeof(*request)
};
- if (!priv || !request) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- memcpy(&cmd.param, request, sizeof(*request));
- if (ipw_send_cmd(priv, &cmd)) {
- IPW_ERROR("failed to send SCAN_REQUEST_EXT command\n");
- return -1;
- }
-
- queue_delayed_work(priv->workqueue, &priv->scan_check,
- IPW_SCAN_CHECK_WATCHDOG);
- return 0;
+ memcpy(cmd.param, request, sizeof(*request));
+ return ipw_send_cmd(priv, &cmd);
}
static int ipw_send_scan_abort(struct ipw_priv *priv)
@@ -1353,12 +2087,7 @@ static int ipw_send_scan_abort(struct ipw_priv *priv)
return -1;
}
- if (ipw_send_cmd(priv, &cmd)) {
- IPW_ERROR("failed to send SCAN_ABORT command\n");
- return -1;
- }
-
- return 0;
+ return ipw_send_cmd(priv, &cmd);
}
static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens)
@@ -1370,12 +2099,7 @@ static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens)
struct ipw_sensitivity_calib *calib = (struct ipw_sensitivity_calib *)
&cmd.param;
calib->beacon_rssi_raw = sens;
- if (ipw_send_cmd(priv, &cmd)) {
- IPW_ERROR("failed to send SENSITIVITY CALIB command\n");
- return -1;
- }
-
- return 0;
+ return ipw_send_cmd(priv, &cmd);
}
static int ipw_send_associate(struct ipw_priv *priv,
@@ -1386,18 +2110,26 @@ static int ipw_send_associate(struct ipw_priv *priv,
.len = sizeof(*associate)
};
+ struct ipw_associate tmp_associate;
+ memcpy(&tmp_associate, associate, sizeof(*associate));
+ tmp_associate.policy_support =
+ cpu_to_le16(tmp_associate.policy_support);
+ tmp_associate.assoc_tsf_msw = cpu_to_le32(tmp_associate.assoc_tsf_msw);
+ tmp_associate.assoc_tsf_lsw = cpu_to_le32(tmp_associate.assoc_tsf_lsw);
+ tmp_associate.capability = cpu_to_le16(tmp_associate.capability);
+ tmp_associate.listen_interval =
+ cpu_to_le16(tmp_associate.listen_interval);
+ tmp_associate.beacon_interval =
+ cpu_to_le16(tmp_associate.beacon_interval);
+ tmp_associate.atim_window = cpu_to_le16(tmp_associate.atim_window);
+
if (!priv || !associate) {
IPW_ERROR("Invalid args\n");
return -1;
}
- memcpy(&cmd.param, associate, sizeof(*associate));
- if (ipw_send_cmd(priv, &cmd)) {
- IPW_ERROR("failed to send ASSOCIATE command\n");
- return -1;
- }
-
- return 0;
+ memcpy(cmd.param, &tmp_associate, sizeof(*associate));
+ return ipw_send_cmd(priv, &cmd);
}
static int ipw_send_supported_rates(struct ipw_priv *priv,
@@ -1413,13 +2145,8 @@ static int ipw_send_supported_rates(struct ipw_priv *priv,
return -1;
}
- memcpy(&cmd.param, rates, sizeof(*rates));
- if (ipw_send_cmd(priv, &cmd)) {
- IPW_ERROR("failed to send SUPPORTED_RATES command\n");
- return -1;
- }
-
- return 0;
+ memcpy(cmd.param, rates, sizeof(*rates));
+ return ipw_send_cmd(priv, &cmd);
}
static int ipw_set_random_seed(struct ipw_priv *priv)
@@ -1436,15 +2163,9 @@ static int ipw_set_random_seed(struct ipw_priv *priv)
get_random_bytes(&cmd.param, sizeof(u32));
- if (ipw_send_cmd(priv, &cmd)) {
- IPW_ERROR("failed to send SEED_NUMBER command\n");
- return -1;
- }
-
- return 0;
+ return ipw_send_cmd(priv, &cmd);
}
-#if 0
static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off)
{
struct host_cmd cmd = {
@@ -1459,14 +2180,8 @@ static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off)
*((u32 *) & cmd.param) = phy_off;
- if (ipw_send_cmd(priv, &cmd)) {
- IPW_ERROR("failed to send CARD_DISABLE command\n");
- return -1;
- }
-
- return 0;
+ return ipw_send_cmd(priv, &cmd);
}
-#endif
static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power)
{
@@ -1480,12 +2195,51 @@ static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power)
return -1;
}
- memcpy(&cmd.param, power, sizeof(*power));
- if (ipw_send_cmd(priv, &cmd)) {
- IPW_ERROR("failed to send TX_POWER command\n");
- return -1;
+ memcpy(cmd.param, power, sizeof(*power));
+ return ipw_send_cmd(priv, &cmd);
+}
+
+static int ipw_set_tx_power(struct ipw_priv *priv)
+{
+ const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee);
+ struct ipw_tx_power tx_power;
+ s8 max_power;
+ int i;
+
+ memset(&tx_power, 0, sizeof(tx_power));
+
+ /* configure device for 'G' band */
+ tx_power.ieee_mode = IPW_G_MODE;
+ tx_power.num_channels = geo->bg_channels;
+ for (i = 0; i < geo->bg_channels; i++) {
+ max_power = geo->bg[i].max_power;
+ tx_power.channels_tx_power[i].channel_number =
+ geo->bg[i].channel;
+ tx_power.channels_tx_power[i].tx_power = max_power ?
+ min(max_power, priv->tx_power) : priv->tx_power;
}
+ if (ipw_send_tx_power(priv, &tx_power))
+ return -EIO;
+
+ /* configure device to also handle 'B' band */
+ tx_power.ieee_mode = IPW_B_MODE;
+ if (ipw_send_tx_power(priv, &tx_power))
+ return -EIO;
+ /* configure device to also handle 'A' band */
+ if (priv->ieee->abg_true) {
+ tx_power.ieee_mode = IPW_A_MODE;
+ tx_power.num_channels = geo->a_channels;
+ for (i = 0; i < tx_power.num_channels; i++) {
+ max_power = geo->a[i].max_power;
+ tx_power.channels_tx_power[i].channel_number =
+ geo->a[i].channel;
+ tx_power.channels_tx_power[i].tx_power = max_power ?
+ min(max_power, priv->tx_power) : priv->tx_power;
+ }
+ if (ipw_send_tx_power(priv, &tx_power))
+ return -EIO;
+ }
return 0;
}
@@ -1504,13 +2258,8 @@ static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts)
return -1;
}
- memcpy(&cmd.param, &rts_threshold, sizeof(rts_threshold));
- if (ipw_send_cmd(priv, &cmd)) {
- IPW_ERROR("failed to send RTS_THRESHOLD command\n");
- return -1;
- }
-
- return 0;
+ memcpy(cmd.param, &rts_threshold, sizeof(rts_threshold));
+ return ipw_send_cmd(priv, &cmd);
}
static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag)
@@ -1528,13 +2277,8 @@ static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag)
return -1;
}
- memcpy(&cmd.param, &frag_threshold, sizeof(frag_threshold));
- if (ipw_send_cmd(priv, &cmd)) {
- IPW_ERROR("failed to send FRAG_THRESHOLD command\n");
- return -1;
- }
-
- return 0;
+ memcpy(cmd.param, &frag_threshold, sizeof(frag_threshold));
+ return ipw_send_cmd(priv, &cmd);
}
static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode)
@@ -1564,12 +2308,27 @@ static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode)
break;
}
- if (ipw_send_cmd(priv, &cmd)) {
- IPW_ERROR("failed to send POWER_MODE command\n");
+ return ipw_send_cmd(priv, &cmd);
+}
+
+static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit)
+{
+ struct ipw_retry_limit retry_limit = {
+ .short_retry_limit = slimit,
+ .long_retry_limit = llimit
+ };
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_RETRY_LIMIT,
+ .len = sizeof(retry_limit)
+ };
+
+ if (!priv) {
+ IPW_ERROR("Invalid args\n");
return -1;
}
- return 0;
+ memcpy(cmd.param, &retry_limit, sizeof(retry_limit));
+ return ipw_send_cmd(priv, &cmd);
}
/*
@@ -1671,8 +2430,7 @@ static u16 eeprom_read_u16(struct ipw_priv *priv, u8 addr)
/* data's copy of the eeprom data */
static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac)
{
- u8 *ee = (u8 *) priv->eeprom;
- memcpy(mac, &ee[EEPROM_MAC_ADDRESS], 6);
+ memcpy(mac, &priv->eeprom[EEPROM_MAC_ADDRESS], 6);
}
/*
@@ -1692,7 +2450,7 @@ static void ipw_eeprom_init_sram(struct ipw_priv *priv)
/* read entire contents of eeprom into private buffer */
for (i = 0; i < 128; i++)
- eeprom[i] = eeprom_read_u16(priv, (u8) i);
+ eeprom[i] = le16_to_cpu(eeprom_read_u16(priv, (u8) i));
/*
If the data looks correct, then copy it to our private
@@ -1703,7 +2461,7 @@ static void ipw_eeprom_init_sram(struct ipw_priv *priv)
IPW_DEBUG_INFO("Writing EEPROM data into SRAM\n");
/* write the eeprom data to sram */
- for (i = 0; i < CX2_EEPROM_IMAGE_SIZE; i++)
+ for (i = 0; i < IPW_EEPROM_IMAGE_SIZE; i++)
ipw_write8(priv, IPW_EEPROM_DATA + i, priv->eeprom[i]);
/* Do not load eeprom data on fatal error or suspend */
@@ -1723,14 +2481,14 @@ static inline void ipw_zero_memory(struct ipw_priv *priv, u32 start, u32 count)
count >>= 2;
if (!count)
return;
- _ipw_write32(priv, CX2_AUTOINC_ADDR, start);
+ _ipw_write32(priv, IPW_AUTOINC_ADDR, start);
while (count--)
- _ipw_write32(priv, CX2_AUTOINC_DATA, 0);
+ _ipw_write32(priv, IPW_AUTOINC_DATA, 0);
}
static inline void ipw_fw_dma_reset_command_blocks(struct ipw_priv *priv)
{
- ipw_zero_memory(priv, CX2_SHARED_SRAM_DMA_CONTROL,
+ ipw_zero_memory(priv, IPW_SHARED_SRAM_DMA_CONTROL,
CB_NUMBER_OF_ELEMENTS_SMALL *
sizeof(struct command_block));
}
@@ -1744,7 +2502,7 @@ static int ipw_fw_dma_enable(struct ipw_priv *priv)
ipw_fw_dma_reset_command_blocks(priv);
/* Write CB base address */
- ipw_write_reg32(priv, CX2_DMA_I_CB_BASE, CX2_SHARED_SRAM_DMA_CONTROL);
+ ipw_write_reg32(priv, IPW_DMA_I_CB_BASE, IPW_SHARED_SRAM_DMA_CONTROL);
IPW_DEBUG_FW("<< : \n");
return 0;
@@ -1758,7 +2516,7 @@ static void ipw_fw_dma_abort(struct ipw_priv *priv)
//set the Stop and Abort bit
control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT;
- ipw_write_reg32(priv, CX2_DMA_I_DMA_CONTROL, control);
+ ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
priv->sram_desc.last_cb_index = 0;
IPW_DEBUG_FW("<< \n");
@@ -1768,7 +2526,7 @@ static int ipw_fw_dma_write_command_block(struct ipw_priv *priv, int index,
struct command_block *cb)
{
u32 address =
- CX2_SHARED_SRAM_DMA_CONTROL +
+ IPW_SHARED_SRAM_DMA_CONTROL +
(sizeof(struct command_block) * index);
IPW_DEBUG_FW(">> :\n");
@@ -1792,13 +2550,13 @@ static int ipw_fw_dma_kick(struct ipw_priv *priv)
&priv->sram_desc.cb_list[index]);
/* Enable the DMA in the CSR register */
- ipw_clear_bit(priv, CX2_RESET_REG,
- CX2_RESET_REG_MASTER_DISABLED |
- CX2_RESET_REG_STOP_MASTER);
+ ipw_clear_bit(priv, IPW_RESET_REG,
+ IPW_RESET_REG_MASTER_DISABLED |
+ IPW_RESET_REG_STOP_MASTER);
/* Set the Start bit. */
control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_START;
- ipw_write_reg32(priv, CX2_DMA_I_DMA_CONTROL, control);
+ ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
IPW_DEBUG_FW("<< :\n");
return 0;
@@ -1811,12 +2569,12 @@ static void ipw_fw_dma_dump_command_block(struct ipw_priv *priv)
u32 cb_fields_address = 0;
IPW_DEBUG_FW(">> :\n");
- address = ipw_read_reg32(priv, CX2_DMA_I_CURRENT_CB);
+ address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB);
IPW_DEBUG_FW_INFO("Current CB is 0x%x \n", address);
/* Read the DMA Controlor register */
- register_value = ipw_read_reg32(priv, CX2_DMA_I_DMA_CONTROL);
- IPW_DEBUG_FW_INFO("CX2_DMA_I_DMA_CONTROL is 0x%x \n", register_value);
+ register_value = ipw_read_reg32(priv, IPW_DMA_I_DMA_CONTROL);
+ IPW_DEBUG_FW_INFO("IPW_DMA_I_DMA_CONTROL is 0x%x \n", register_value);
/* Print the CB values */
cb_fields_address = address;
@@ -1845,9 +2603,9 @@ static int ipw_fw_dma_command_block_index(struct ipw_priv *priv)
u32 current_cb_index = 0;
IPW_DEBUG_FW("<< :\n");
- current_cb_address = ipw_read_reg32(priv, CX2_DMA_I_CURRENT_CB);
+ current_cb_address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB);
- current_cb_index = (current_cb_address - CX2_SHARED_SRAM_DMA_CONTROL) /
+ current_cb_index = (current_cb_address - IPW_SHARED_SRAM_DMA_CONTROL) /
sizeof(struct command_block);
IPW_DEBUG_FW_INFO("Current CB index 0x%x address = 0x%X \n",
@@ -1976,8 +2734,8 @@ static int ipw_fw_dma_wait(struct ipw_priv *priv)
ipw_fw_dma_abort(priv);
/*Disable the DMA in the CSR register */
- ipw_set_bit(priv, CX2_RESET_REG,
- CX2_RESET_REG_MASTER_DISABLED | CX2_RESET_REG_STOP_MASTER);
+ ipw_set_bit(priv, IPW_RESET_REG,
+ IPW_RESET_REG_MASTER_DISABLED | IPW_RESET_REG_STOP_MASTER);
IPW_DEBUG_FW("<< dmaWaitSync \n");
return 0;
@@ -1987,6 +2745,9 @@ static void ipw_remove_current_network(struct ipw_priv *priv)
{
struct list_head *element, *safe;
struct ieee80211_network *network = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->ieee->lock, flags);
list_for_each_safe(element, safe, &priv->ieee->network_list) {
network = list_entry(element, struct ieee80211_network, list);
if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
@@ -1995,6 +2756,7 @@ static void ipw_remove_current_network(struct ipw_priv *priv)
&priv->ieee->network_free_list);
}
}
+ spin_unlock_irqrestore(&priv->ieee->lock, flags);
}
/**
@@ -2037,10 +2799,10 @@ static int ipw_stop_master(struct ipw_priv *priv)
IPW_DEBUG_TRACE(">> \n");
/* stop master. typical delay - 0 */
- ipw_set_bit(priv, CX2_RESET_REG, CX2_RESET_REG_STOP_MASTER);
+ ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER);
- rc = ipw_poll_bit(priv, CX2_RESET_REG,
- CX2_RESET_REG_MASTER_DISABLED, 100);
+ rc = ipw_poll_bit(priv, IPW_RESET_REG,
+ IPW_RESET_REG_MASTER_DISABLED, 100);
if (rc < 0) {
IPW_ERROR("stop master failed in 10ms\n");
return -1;
@@ -2056,7 +2818,7 @@ static void ipw_arc_release(struct ipw_priv *priv)
IPW_DEBUG_TRACE(">> \n");
mdelay(5);
- ipw_clear_bit(priv, CX2_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
+ ipw_clear_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
/* no one knows timing, for safety add some delay */
mdelay(5);
@@ -2073,13 +2835,12 @@ struct fw_chunk {
};
#define IPW_FW_MAJOR_VERSION 2
-#define IPW_FW_MINOR_VERSION 2
+#define IPW_FW_MINOR_VERSION 4
#define IPW_FW_MINOR(x) ((x & 0xff) >> 8)
#define IPW_FW_MAJOR(x) (x & 0xff)
-#define IPW_FW_VERSION ((IPW_FW_MINOR_VERSION << 8) | \
- IPW_FW_MAJOR_VERSION)
+#define IPW_FW_VERSION ((IPW_FW_MINOR_VERSION << 8) | IPW_FW_MAJOR_VERSION)
#define IPW_FW_PREFIX "ipw-" __stringify(IPW_FW_MAJOR_VERSION) \
"." __stringify(IPW_FW_MINOR_VERSION) "-"
@@ -2107,8 +2868,8 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
// spin_lock_irqsave(&priv->lock, flags);
- for (addr = CX2_SHARED_LOWER_BOUND;
- addr < CX2_REGISTER_DOMAIN1_END; addr += 4) {
+ for (addr = IPW_SHARED_LOWER_BOUND;
+ addr < IPW_REGISTER_DOMAIN1_END; addr += 4) {
ipw_write32(priv, addr, 0);
}
@@ -2117,16 +2878,16 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
/* destroy DMA queues */
/* reset sequence */
- ipw_write_reg32(priv, CX2_MEM_HALT_AND_RESET, CX2_BIT_HALT_RESET_ON);
+ ipw_write_reg32(priv, IPW_MEM_HALT_AND_RESET, IPW_BIT_HALT_RESET_ON);
ipw_arc_release(priv);
- ipw_write_reg32(priv, CX2_MEM_HALT_AND_RESET, CX2_BIT_HALT_RESET_OFF);
+ ipw_write_reg32(priv, IPW_MEM_HALT_AND_RESET, IPW_BIT_HALT_RESET_OFF);
mdelay(1);
/* reset PHY */
- ipw_write_reg32(priv, CX2_INTERNAL_CMD_EVENT, CX2_BASEBAND_POWER_DOWN);
+ ipw_write_reg32(priv, IPW_INTERNAL_CMD_EVENT, IPW_BASEBAND_POWER_DOWN);
mdelay(1);
- ipw_write_reg32(priv, CX2_INTERNAL_CMD_EVENT, 0);
+ ipw_write_reg32(priv, IPW_INTERNAL_CMD_EVENT, 0);
mdelay(1);
/* enable ucode store */
@@ -2144,18 +2905,19 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
*/
/* load new ipw uCode */
for (i = 0; i < len / 2; i++)
- ipw_write_reg16(priv, CX2_BASEBAND_CONTROL_STORE, image[i]);
+ ipw_write_reg16(priv, IPW_BASEBAND_CONTROL_STORE,
+ cpu_to_le16(image[i]));
/* enable DINO */
- ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, 0);
- ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, DINO_ENABLE_SYSTEM);
+ ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
+ ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, DINO_ENABLE_SYSTEM);
/* this is where the igx / win driver deveates from the VAP driver. */
/* wait for alive response */
for (i = 0; i < 100; i++) {
/* poll for incoming data */
- cr = ipw_read_reg8(priv, CX2_BASEBAND_CONTROL_STATUS);
+ cr = ipw_read_reg8(priv, IPW_BASEBAND_CONTROL_STATUS);
if (cr & DINO_RXFIFO_DATA)
break;
mdelay(1);
@@ -2167,7 +2929,8 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
for (i = 0; i < ARRAY_SIZE(response_buffer); i++)
response_buffer[i] =
- ipw_read_reg32(priv, CX2_BASEBAND_RX_FIFO_READ);
+ le32_to_cpu(ipw_read_reg32(priv,
+ IPW_BASEBAND_RX_FIFO_READ));
memcpy(&priv->dino_alive, response_buffer,
sizeof(priv->dino_alive));
if (priv->dino_alive.alive_command == 1
@@ -2196,7 +2959,7 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
/* disable DINO, otherwise for some reason
firmware have problem getting alive resp. */
- ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, 0);
+ ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
// spin_unlock_irqrestore(&priv->lock, flags);
@@ -2236,13 +2999,14 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len)
* offeset*/
/* Dma loading */
rc = ipw_fw_dma_add_buffer(priv, shared_phys + offset,
- chunk->address, chunk->length);
+ le32_to_cpu(chunk->address),
+ le32_to_cpu(chunk->length));
if (rc) {
IPW_DEBUG_INFO("dmaAddBuffer Failed\n");
goto out;
}
- offset += chunk->length;
+ offset += le32_to_cpu(chunk->length);
} while (offset < len);
/* Run the DMA and wait for the answer */
@@ -2268,16 +3032,16 @@ static int ipw_stop_nic(struct ipw_priv *priv)
int rc = 0;
/* stop */
- ipw_write32(priv, CX2_RESET_REG, CX2_RESET_REG_STOP_MASTER);
+ ipw_write32(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER);
- rc = ipw_poll_bit(priv, CX2_RESET_REG,
- CX2_RESET_REG_MASTER_DISABLED, 500);
+ rc = ipw_poll_bit(priv, IPW_RESET_REG,
+ IPW_RESET_REG_MASTER_DISABLED, 500);
if (rc < 0) {
IPW_ERROR("wait for reg master disabled failed\n");
return rc;
}
- ipw_set_bit(priv, CX2_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
+ ipw_set_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
return rc;
}
@@ -2287,14 +3051,14 @@ static void ipw_start_nic(struct ipw_priv *priv)
IPW_DEBUG_TRACE(">>\n");
/* prvHwStartNic release ARC */
- ipw_clear_bit(priv, CX2_RESET_REG,
- CX2_RESET_REG_MASTER_DISABLED |
- CX2_RESET_REG_STOP_MASTER |
+ ipw_clear_bit(priv, IPW_RESET_REG,
+ IPW_RESET_REG_MASTER_DISABLED |
+ IPW_RESET_REG_STOP_MASTER |
CBD_RESET_REG_PRINCETON_RESET);
/* enable power management */
- ipw_set_bit(priv, CX2_GP_CNTRL_RW,
- CX2_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
+ ipw_set_bit(priv, IPW_GP_CNTRL_RW,
+ IPW_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
IPW_DEBUG_TRACE("<<\n");
}
@@ -2307,25 +3071,25 @@ static int ipw_init_nic(struct ipw_priv *priv)
/* reset */
/*prvHwInitNic */
/* set "initialization complete" bit to move adapter to D0 state */
- ipw_set_bit(priv, CX2_GP_CNTRL_RW, CX2_GP_CNTRL_BIT_INIT_DONE);
+ ipw_set_bit(priv, IPW_GP_CNTRL_RW, IPW_GP_CNTRL_BIT_INIT_DONE);
/* low-level PLL activation */
- ipw_write32(priv, CX2_READ_INT_REGISTER,
- CX2_BIT_INT_HOST_SRAM_READ_INT_REGISTER);
+ ipw_write32(priv, IPW_READ_INT_REGISTER,
+ IPW_BIT_INT_HOST_SRAM_READ_INT_REGISTER);
/* wait for clock stabilization */
- rc = ipw_poll_bit(priv, CX2_GP_CNTRL_RW,
- CX2_GP_CNTRL_BIT_CLOCK_READY, 250);
+ rc = ipw_poll_bit(priv, IPW_GP_CNTRL_RW,
+ IPW_GP_CNTRL_BIT_CLOCK_READY, 250);
if (rc < 0)
IPW_DEBUG_INFO("FAILED wait for clock stablization\n");
/* assert SW reset */
- ipw_set_bit(priv, CX2_RESET_REG, CX2_RESET_REG_SW_RESET);
+ ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_SW_RESET);
udelay(10);
/* set "initialization complete" bit to move adapter to D0 state */
- ipw_set_bit(priv, CX2_GP_CNTRL_RW, CX2_GP_CNTRL_BIT_INIT_DONE);
+ ipw_set_bit(priv, IPW_GP_CNTRL_RW, IPW_GP_CNTRL_BIT_INIT_DONE);
IPW_DEBUG_TRACE(">>\n");
return 0;
@@ -2337,14 +3101,19 @@ static int ipw_init_nic(struct ipw_priv *priv)
static int ipw_reset_nic(struct ipw_priv *priv)
{
int rc = 0;
+ unsigned long flags;
IPW_DEBUG_TRACE(">>\n");
rc = ipw_init_nic(priv);
+ spin_lock_irqsave(&priv->lock, flags);
/* Clear the 'host command active' bit... */
priv->status &= ~STATUS_HCMD_ACTIVE;
wake_up_interruptible(&priv->wait_command_queue);
+ priv->status &= ~(STATUS_SCANNING | STATUS_SCAN_ABORTING);
+ wake_up_interruptible(&priv->wait_state);
+ spin_unlock_irqrestore(&priv->lock, flags);
IPW_DEBUG_TRACE("<<\n");
return rc;
@@ -2364,22 +3133,23 @@ static int ipw_get_fw(struct ipw_priv *priv,
}
header = (struct fw_header *)(*fw)->data;
- if (IPW_FW_MAJOR(header->version) != IPW_FW_MAJOR_VERSION) {
+ if (IPW_FW_MAJOR(le32_to_cpu(header->version)) != IPW_FW_MAJOR_VERSION) {
IPW_ERROR("'%s' firmware version not compatible (%d != %d)\n",
name,
- IPW_FW_MAJOR(header->version), IPW_FW_MAJOR_VERSION);
+ IPW_FW_MAJOR(le32_to_cpu(header->version)),
+ IPW_FW_MAJOR_VERSION);
return -EINVAL;
}
IPW_DEBUG_INFO("Loading firmware '%s' file v%d.%d (%zd bytes)\n",
name,
- IPW_FW_MAJOR(header->version),
- IPW_FW_MINOR(header->version),
+ IPW_FW_MAJOR(le32_to_cpu(header->version)),
+ IPW_FW_MINOR(le32_to_cpu(header->version)),
(*fw)->size - sizeof(struct fw_header));
return 0;
}
-#define CX2_RX_BUF_SIZE (3000)
+#define IPW_RX_BUF_SIZE (3000)
static inline void ipw_rx_queue_reset(struct ipw_priv *priv,
struct ipw_rx_queue *rxq)
@@ -2398,8 +3168,9 @@ static inline void ipw_rx_queue_reset(struct ipw_priv *priv,
* to an SKB, so we need to unmap and free potential storage */
if (rxq->pool[i].skb != NULL) {
pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr,
- CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
dev_kfree_skb(rxq->pool[i].skb);
+ rxq->pool[i].skb = NULL;
}
list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
}
@@ -2417,6 +3188,19 @@ static int fw_loaded = 0;
static const struct firmware *bootfw = NULL;
static const struct firmware *firmware = NULL;
static const struct firmware *ucode = NULL;
+
+static void free_firmware(void)
+{
+ if (fw_loaded) {
+ release_firmware(bootfw);
+ release_firmware(ucode);
+ release_firmware(firmware);
+ bootfw = ucode = firmware = NULL;
+ fw_loaded = 0;
+ }
+}
+#else
+#define free_firmware() do {} while (0)
#endif
static int ipw_load(struct ipw_priv *priv)
@@ -2445,10 +3229,10 @@ static int ipw_load(struct ipw_priv *priv)
rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("ibss"));
break;
-#ifdef CONFIG_IPW_PROMISC
+#ifdef CONFIG_IPW2200_MONITOR
case IW_MODE_MONITOR:
rc = ipw_get_fw(priv, &ucode,
- IPW_FW_NAME("ibss_ucode"));
+ IPW_FW_NAME("sniffer_ucode"));
if (rc)
goto error;
@@ -2487,11 +3271,11 @@ static int ipw_load(struct ipw_priv *priv)
retry:
/* Ensure interrupts are disabled */
- ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL);
+ ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
priv->status &= ~STATUS_INT_ENABLED;
/* ack pending interrupts */
- ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL);
+ ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL);
ipw_stop_nic(priv);
@@ -2501,14 +3285,14 @@ static int ipw_load(struct ipw_priv *priv)
goto error;
}
- ipw_zero_memory(priv, CX2_NIC_SRAM_LOWER_BOUND,
- CX2_NIC_SRAM_UPPER_BOUND - CX2_NIC_SRAM_LOWER_BOUND);
+ ipw_zero_memory(priv, IPW_NIC_SRAM_LOWER_BOUND,
+ IPW_NIC_SRAM_UPPER_BOUND - IPW_NIC_SRAM_LOWER_BOUND);
/* DMA the initial boot firmware into the device */
rc = ipw_load_firmware(priv, bootfw->data + sizeof(struct fw_header),
bootfw->size - sizeof(struct fw_header));
if (rc < 0) {
- IPW_ERROR("Unable to load boot firmware\n");
+ IPW_ERROR("Unable to load boot firmware: %d\n", rc);
goto error;
}
@@ -2516,8 +3300,8 @@ static int ipw_load(struct ipw_priv *priv)
ipw_start_nic(priv);
/* wait for the device to finish it's initial startup sequence */
- rc = ipw_poll_bit(priv, CX2_INTA_RW,
- CX2_INTA_BIT_FW_INITIALIZATION_DONE, 500);
+ rc = ipw_poll_bit(priv, IPW_INTA_RW,
+ IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500);
if (rc < 0) {
IPW_ERROR("device failed to boot initial fw image\n");
goto error;
@@ -2525,13 +3309,13 @@ static int ipw_load(struct ipw_priv *priv)
IPW_DEBUG_INFO("initial device response after %dms\n", rc);
/* ack fw init done interrupt */
- ipw_write32(priv, CX2_INTA_RW, CX2_INTA_BIT_FW_INITIALIZATION_DONE);
+ ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
/* DMA the ucode into the device */
rc = ipw_load_ucode(priv, ucode->data + sizeof(struct fw_header),
ucode->size - sizeof(struct fw_header));
if (rc < 0) {
- IPW_ERROR("Unable to load ucode\n");
+ IPW_ERROR("Unable to load ucode: %d\n", rc);
goto error;
}
@@ -2543,7 +3327,7 @@ static int ipw_load(struct ipw_priv *priv)
sizeof(struct fw_header),
firmware->size - sizeof(struct fw_header));
if (rc < 0) {
- IPW_ERROR("Unable to load firmware\n");
+ IPW_ERROR("Unable to load firmware: %d\n", rc);
goto error;
}
@@ -2556,12 +3340,14 @@ static int ipw_load(struct ipw_priv *priv)
}
/* Ensure interrupts are disabled */
- ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL);
+ ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
+ /* ack pending interrupts */
+ ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL);
/* kick start the device */
ipw_start_nic(priv);
- if (ipw_read32(priv, CX2_INTA_RW) & CX2_INTA_BIT_PARITY_ERROR) {
+ if (ipw_read32(priv, IPW_INTA_RW) & IPW_INTA_BIT_PARITY_ERROR) {
if (retries > 0) {
IPW_WARNING("Parity error. Retrying init.\n");
retries--;
@@ -2574,8 +3360,8 @@ static int ipw_load(struct ipw_priv *priv)
}
/* wait for the device */
- rc = ipw_poll_bit(priv, CX2_INTA_RW,
- CX2_INTA_BIT_FW_INITIALIZATION_DONE, 500);
+ rc = ipw_poll_bit(priv, IPW_INTA_RW,
+ IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500);
if (rc < 0) {
IPW_ERROR("device failed to start after 500ms\n");
goto error;
@@ -2583,7 +3369,7 @@ static int ipw_load(struct ipw_priv *priv)
IPW_DEBUG_INFO("device response after %dms\n", rc);
/* ack fw init done interrupt */
- ipw_write32(priv, CX2_INTA_RW, CX2_INTA_BIT_FW_INITIALIZATION_DONE);
+ ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
/* read eeprom data and initialize the eeprom region of sram */
priv->eeprom_delay = 1;
@@ -2595,10 +3381,10 @@ static int ipw_load(struct ipw_priv *priv)
/* Ensure our queue has valid packets */
ipw_rx_queue_replenish(priv);
- ipw_write32(priv, CX2_RX_READ_INDEX, priv->rxq->read);
+ ipw_write32(priv, IPW_RX_READ_INDEX, priv->rxq->read);
/* ack pending interrupts */
- ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL);
+ ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL);
#ifndef CONFIG_PM
release_firmware(bootfw);
@@ -2755,16 +3541,18 @@ static void ipw_queue_tx_free_tfd(struct ipw_priv *priv,
return;
/* sanity check */
- if (bd->u.data.num_chunks > NUM_TFD_CHUNKS) {
- IPW_ERROR("Too many chunks: %i\n", bd->u.data.num_chunks);
+ if (le32_to_cpu(bd->u.data.num_chunks) > NUM_TFD_CHUNKS) {
+ IPW_ERROR("Too many chunks: %i\n",
+ le32_to_cpu(bd->u.data.num_chunks));
/** @todo issue fatal error, it is quite serious situation */
return;
}
/* unmap chunks if any */
- for (i = 0; i < bd->u.data.num_chunks; i++) {
- pci_unmap_single(dev, bd->u.data.chunk_ptr[i],
- bd->u.data.chunk_len[i], PCI_DMA_TODEVICE);
+ for (i = 0; i < le32_to_cpu(bd->u.data.num_chunks); i++) {
+ pci_unmap_single(dev, le32_to_cpu(bd->u.data.chunk_ptr[i]),
+ le16_to_cpu(bd->u.data.chunk_len[i]),
+ PCI_DMA_TODEVICE);
if (txq->txb[txq->q.last_used]) {
ieee80211_txb_free(txq->txb[txq->q.last_used]);
txq->txb[txq->q.last_used] = NULL;
@@ -2821,21 +3609,6 @@ static void ipw_tx_queue_free(struct ipw_priv *priv)
ipw_queue_tx_free(priv, &priv->txq[3]);
}
-static void inline __maybe_wake_tx(struct ipw_priv *priv)
-{
- if (netif_running(priv->net_dev)) {
- switch (priv->port_type) {
- case DCR_TYPE_MU_BSS:
- case DCR_TYPE_MU_IBSS:
- if (!(priv->status & STATUS_ASSOCIATED)) {
- return;
- }
- }
- netif_wake_queue(priv->net_dev);
- }
-
-}
-
static inline void ipw_create_bssid(struct ipw_priv *priv, u8 * bssid)
{
/* First 3 bytes are manufacturer */
@@ -2898,7 +3671,13 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet)
{
int err;
- if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED))) {
+ if (priv->status & STATUS_ASSOCIATING) {
+ IPW_DEBUG_ASSOC("Disassociating while associating.\n");
+ queue_work(priv->workqueue, &priv->disassociate);
+ return;
+ }
+
+ if (!(priv->status & STATUS_ASSOCIATED)) {
IPW_DEBUG_ASSOC("Disassociating while not associated.\n");
return;
}
@@ -2915,6 +3694,7 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet)
priv->assoc_request.assoc_type = HC_DISASSOC_QUIET;
else
priv->assoc_request.assoc_type = HC_DISASSOCIATE;
+
err = ipw_send_associate(priv, &priv->assoc_request);
if (err) {
IPW_DEBUG_HC("Attempt to send [dis]associate command "
@@ -2924,20 +3704,27 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet)
}
-static void ipw_disassociate(void *data)
+static int ipw_disassociate(void *data)
{
+ struct ipw_priv *priv = data;
+ if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
+ return 0;
ipw_send_disassociate(data, 0);
+ return 1;
}
-static void notify_wx_assoc_event(struct ipw_priv *priv)
+static void ipw_bg_disassociate(void *data)
{
- union iwreq_data wrqu;
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- if (priv->status & STATUS_ASSOCIATED)
- memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
- else
- memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
- wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
+ struct ipw_priv *priv = data;
+ down(&priv->sem);
+ ipw_disassociate(data);
+ up(&priv->sem);
+}
+
+static void ipw_system_config(void *data)
+{
+ struct ipw_priv *priv = data;
+ ipw_send_system_config(priv, &priv->sys_config);
}
struct ipw_status_code {
@@ -2997,7 +3784,7 @@ static const char *ipw_get_status_code(u16 status)
{
int i;
for (i = 0; i < ARRAY_SIZE(ipw_status_codes); i++)
- if (ipw_status_codes[i].status == status)
+ if (ipw_status_codes[i].status == (status & 0xff))
return ipw_status_codes[i].reason;
return "Unknown status value.";
}
@@ -3076,18 +3863,30 @@ static inline u32 ipw_get_max_rate(struct ipw_priv *priv)
while (i && !(mask & i))
i >>= 1;
switch (i) {
- case IEEE80211_CCK_RATE_1MB_MASK: return 1000000;
- case IEEE80211_CCK_RATE_2MB_MASK: return 2000000;
- case IEEE80211_CCK_RATE_5MB_MASK: return 5500000;
- case IEEE80211_OFDM_RATE_6MB_MASK: return 6000000;
- case IEEE80211_OFDM_RATE_9MB_MASK: return 9000000;
- case IEEE80211_CCK_RATE_11MB_MASK: return 11000000;
- case IEEE80211_OFDM_RATE_12MB_MASK: return 12000000;
- case IEEE80211_OFDM_RATE_18MB_MASK: return 18000000;
- case IEEE80211_OFDM_RATE_24MB_MASK: return 24000000;
- case IEEE80211_OFDM_RATE_36MB_MASK: return 36000000;
- case IEEE80211_OFDM_RATE_48MB_MASK: return 48000000;
- case IEEE80211_OFDM_RATE_54MB_MASK: return 54000000;
+ case IEEE80211_CCK_RATE_1MB_MASK:
+ return 1000000;
+ case IEEE80211_CCK_RATE_2MB_MASK:
+ return 2000000;
+ case IEEE80211_CCK_RATE_5MB_MASK:
+ return 5500000;
+ case IEEE80211_OFDM_RATE_6MB_MASK:
+ return 6000000;
+ case IEEE80211_OFDM_RATE_9MB_MASK:
+ return 9000000;
+ case IEEE80211_CCK_RATE_11MB_MASK:
+ return 11000000;
+ case IEEE80211_OFDM_RATE_12MB_MASK:
+ return 12000000;
+ case IEEE80211_OFDM_RATE_18MB_MASK:
+ return 18000000;
+ case IEEE80211_OFDM_RATE_24MB_MASK:
+ return 24000000;
+ case IEEE80211_OFDM_RATE_36MB_MASK:
+ return 36000000;
+ case IEEE80211_OFDM_RATE_48MB_MASK:
+ return 48000000;
+ case IEEE80211_OFDM_RATE_54MB_MASK:
+ return 54000000;
}
if (priv->ieee->mode == IEEE_B)
@@ -3115,25 +3914,35 @@ static u32 ipw_get_current_rate(struct ipw_priv *priv)
return ipw_get_max_rate(priv);
switch (rate) {
- case IPW_TX_RATE_1MB: return 1000000;
- case IPW_TX_RATE_2MB: return 2000000;
- case IPW_TX_RATE_5MB: return 5500000;
- case IPW_TX_RATE_6MB: return 6000000;
- case IPW_TX_RATE_9MB: return 9000000;
- case IPW_TX_RATE_11MB: return 11000000;
- case IPW_TX_RATE_12MB: return 12000000;
- case IPW_TX_RATE_18MB: return 18000000;
- case IPW_TX_RATE_24MB: return 24000000;
- case IPW_TX_RATE_36MB: return 36000000;
- case IPW_TX_RATE_48MB: return 48000000;
- case IPW_TX_RATE_54MB: return 54000000;
+ case IPW_TX_RATE_1MB:
+ return 1000000;
+ case IPW_TX_RATE_2MB:
+ return 2000000;
+ case IPW_TX_RATE_5MB:
+ return 5500000;
+ case IPW_TX_RATE_6MB:
+ return 6000000;
+ case IPW_TX_RATE_9MB:
+ return 9000000;
+ case IPW_TX_RATE_11MB:
+ return 11000000;
+ case IPW_TX_RATE_12MB:
+ return 12000000;
+ case IPW_TX_RATE_18MB:
+ return 18000000;
+ case IPW_TX_RATE_24MB:
+ return 24000000;
+ case IPW_TX_RATE_36MB:
+ return 36000000;
+ case IPW_TX_RATE_48MB:
+ return 48000000;
+ case IPW_TX_RATE_54MB:
+ return 54000000;
}
return 0;
}
-#define PERFECT_RSSI (-50)
-#define WORST_RSSI (-85)
#define IPW_STATS_INTERVAL (2 * HZ)
static void ipw_gather_stats(struct ipw_priv *priv)
{
@@ -3145,6 +3954,7 @@ static void ipw_gather_stats(struct ipw_priv *priv)
s16 rssi;
u32 beacon_quality, signal_quality, tx_quality, rx_quality,
rate_quality;
+ u32 max_rate;
if (!(priv->status & STATUS_ASSOCIATED)) {
priv->quality = 0;
@@ -3201,7 +4011,8 @@ static void ipw_gather_stats(struct ipw_priv *priv)
beacon_quality, missed_beacons_percent);
priv->last_rate = ipw_get_current_rate(priv);
- rate_quality = priv->last_rate * 40 / priv->last_rate + 60;
+ max_rate = ipw_get_max_rate(priv);
+ rate_quality = priv->last_rate * 40 / max_rate + 60;
IPW_DEBUG_STATS("Rate quality : %3d%% (%dMbs)\n",
rate_quality, priv->last_rate / 1000000);
@@ -3222,13 +4033,20 @@ static void ipw_gather_stats(struct ipw_priv *priv)
tx_quality, tx_failures_delta, tx_packets_delta);
rssi = average_value(&priv->average_rssi);
- if (rssi > PERFECT_RSSI)
+ signal_quality =
+ (100 *
+ (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) *
+ (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) -
+ (priv->ieee->perfect_rssi - rssi) *
+ (15 * (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) +
+ 62 * (priv->ieee->perfect_rssi - rssi))) /
+ ((priv->ieee->perfect_rssi - priv->ieee->worst_rssi) *
+ (priv->ieee->perfect_rssi - priv->ieee->worst_rssi));
+ if (signal_quality > 100)
signal_quality = 100;
- else if (rssi < WORST_RSSI)
+ else if (signal_quality < 1)
signal_quality = 0;
- else
- signal_quality = (rssi - WORST_RSSI) * 100 /
- (PERFECT_RSSI - WORST_RSSI);
+
IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n",
signal_quality, rssi);
@@ -3257,6 +4075,85 @@ static void ipw_gather_stats(struct ipw_priv *priv)
IPW_STATS_INTERVAL);
}
+static void ipw_bg_gather_stats(void *data)
+{
+ struct ipw_priv *priv = data;
+ down(&priv->sem);
+ ipw_gather_stats(data);
+ up(&priv->sem);
+}
+
+/* Missed beacon behavior:
+ * 1st missed -> roaming_threshold, just wait, don't do any scan/roam.
+ * roaming_threshold -> disassociate_threshold, scan and roam for better signal.
+ * Above disassociate threshold, give up and stop scanning.
+ * Roaming is disabled if disassociate_threshold <= roaming_threshold */
+static inline void ipw_handle_missed_beacon(struct ipw_priv *priv,
+ int missed_count)
+{
+ priv->notif_missed_beacons = missed_count;
+
+ if (missed_count > priv->disassociate_threshold &&
+ priv->status & STATUS_ASSOCIATED) {
+ /* If associated and we've hit the missed
+ * beacon threshold, disassociate, turn
+ * off roaming, and abort any active scans */
+ IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
+ IPW_DL_STATE | IPW_DL_ASSOC,
+ "Missed beacon: %d - disassociate\n", missed_count);
+ priv->status &= ~STATUS_ROAMING;
+ if (priv->status & STATUS_SCANNING) {
+ IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
+ IPW_DL_STATE,
+ "Aborting scan with missed beacon.\n");
+ queue_work(priv->workqueue, &priv->abort_scan);
+ }
+
+ queue_work(priv->workqueue, &priv->disassociate);
+ return;
+ }
+
+ if (priv->status & STATUS_ROAMING) {
+ /* If we are currently roaming, then just
+ * print a debug statement... */
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
+ "Missed beacon: %d - roam in progress\n",
+ missed_count);
+ return;
+ }
+
+ if (missed_count > priv->roaming_threshold &&
+ missed_count <= priv->disassociate_threshold) {
+ /* If we are not already roaming, set the ROAM
+ * bit in the status and kick off a scan.
+ * This can happen several times before we reach
+ * disassociate_threshold. */
+ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
+ "Missed beacon: %d - initiate "
+ "roaming\n", missed_count);
+ if (!(priv->status & STATUS_ROAMING)) {
+ priv->status |= STATUS_ROAMING;
+ if (!(priv->status & STATUS_SCANNING))
+ queue_work(priv->workqueue,
+ &priv->request_scan);
+ }
+ return;
+ }
+
+ if (priv->status & STATUS_SCANNING) {
+ /* Stop scan to keep fw from getting
+ * stuck (only if we aren't roaming --
+ * otherwise we'll never scan more than 2 or 3
+ * channels..) */
+ IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | IPW_DL_STATE,
+ "Aborting scan with missed beacon.\n");
+ queue_work(priv->workqueue, &priv->abort_scan);
+ }
+
+ IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count);
+
+}
+
/**
* Handle host notification packet.
* Called from interrupt routine
@@ -3264,6 +4161,8 @@ static void ipw_gather_stats(struct ipw_priv *priv)
static inline void ipw_rx_notification(struct ipw_priv *priv,
struct ipw_rx_notification *notif)
{
+ notif->size = le16_to_cpu(notif->size);
+
IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, notif->size);
switch (notif->subtype) {
@@ -3307,30 +4206,44 @@ static inline void ipw_rx_notification(struct ipw_priv *priv,
priv->status &= ~STATUS_ASSOCIATING;
priv->status |= STATUS_ASSOCIATED;
-
- netif_carrier_on(priv->net_dev);
- if (netif_queue_stopped(priv->net_dev)) {
- IPW_DEBUG_NOTIF
- ("waking queue\n");
- netif_wake_queue(priv->net_dev);
- } else {
- IPW_DEBUG_NOTIF
- ("starting queue\n");
- netif_start_queue(priv->
- net_dev);
+ queue_work(priv->workqueue,
+ &priv->system_config);
+
+#ifdef CONFIG_IPW_QOS
+#define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \
+ le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_ctl))
+ if ((priv->status & STATUS_AUTH) &&
+ (IPW_GET_PACKET_STYPE(&notif->u.raw)
+ == IEEE80211_STYPE_ASSOC_RESP)) {
+ if ((sizeof
+ (struct
+ ieee80211_assoc_response)
+ <= notif->size)
+ && (notif->size <= 2314)) {
+ struct
+ ieee80211_rx_stats
+ stats = {
+ .len =
+ notif->
+ size - 1,
+ };
+
+ IPW_DEBUG_QOS
+ ("QoS Associate "
+ "size %d\n",
+ notif->size);
+ ieee80211_rx_mgt(priv->
+ ieee,
+ (struct
+ ieee80211_hdr_4addr
+ *)
+ &notif->u.raw, &stats);
+ }
}
+#endif
- ipw_reset_stats(priv);
- /* Ensure the rate is updated immediately */
- priv->last_rate =
- ipw_get_current_rate(priv);
- schedule_work(&priv->gather_stats);
- notify_wx_assoc_event(priv);
+ schedule_work(&priv->link_up);
-/* queue_delayed_work(priv->workqueue,
- &priv->request_scan,
- SCAN_ASSOCIATED_INTERVAL);
-*/
break;
}
@@ -3363,12 +4276,7 @@ static inline void ipw_rx_notification(struct ipw_priv *priv,
STATUS_AUTH |
STATUS_ASSOCIATED);
- netif_carrier_off(priv->
- net_dev);
- netif_stop_queue(priv->net_dev);
- queue_work(priv->workqueue,
- &priv->request_scan);
- notify_wx_assoc_event(priv);
+ schedule_work(&priv->link_down);
break;
}
@@ -3383,6 +4291,24 @@ static inline void ipw_rx_notification(struct ipw_priv *priv,
}
case CMAS_INIT:{
+ if (priv->status & STATUS_AUTH) {
+ struct
+ ieee80211_assoc_response
+ *resp;
+ resp =
+ (struct
+ ieee80211_assoc_response
+ *)&notif->u.raw;
+ IPW_DEBUG(IPW_DL_NOTIF |
+ IPW_DL_STATE |
+ IPW_DL_ASSOC,
+ "association failed (0x%04X): %s\n",
+ ntohs(resp->status),
+ ipw_get_status_code
+ (ntohs
+ (resp->status)));
+ }
+
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
"disassociated: '%s' " MAC_FMT
@@ -3395,35 +4321,21 @@ static inline void ipw_rx_notification(struct ipw_priv *priv,
~(STATUS_DISASSOCIATING |
STATUS_ASSOCIATING |
STATUS_ASSOCIATED | STATUS_AUTH);
+ if (priv->assoc_network
+ && (priv->assoc_network->
+ capability &
+ WLAN_CAPABILITY_IBSS))
+ ipw_remove_current_network
+ (priv);
- netif_stop_queue(priv->net_dev);
- if (!(priv->status & STATUS_ROAMING)) {
- netif_carrier_off(priv->
- net_dev);
- notify_wx_assoc_event(priv);
-
- /* Cancel any queued work ... */
- cancel_delayed_work(&priv->
- request_scan);
- cancel_delayed_work(&priv->
- adhoc_check);
-
- /* Queue up another scan... */
- queue_work(priv->workqueue,
- &priv->request_scan);
-
- cancel_delayed_work(&priv->
- gather_stats);
- } else {
- priv->status |= STATUS_ROAMING;
- queue_work(priv->workqueue,
- &priv->request_scan);
- }
+ schedule_work(&priv->link_down);
- ipw_reset_stats(priv);
break;
}
+ case CMAS_RX_ASSOC_RESP:
+ break;
+
default:
IPW_ERROR("assoc: unknown (%d)\n",
assoc->state);
@@ -3466,11 +4378,7 @@ static inline void ipw_rx_notification(struct ipw_priv *priv,
STATUS_AUTH |
STATUS_ASSOCIATED);
- netif_carrier_off(priv->net_dev);
- netif_stop_queue(priv->net_dev);
- queue_work(priv->workqueue,
- &priv->request_scan);
- notify_wx_assoc_event(priv);
+ schedule_work(&priv->link_down);
break;
case CMAS_TX_AUTH_SEQ_1:
@@ -3512,6 +4420,7 @@ static inline void ipw_rx_notification(struct ipw_priv *priv,
case CMAS_RX_ASSOC_RESP:
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC, "RX_ASSOC_RESP\n");
+
break;
case CMAS_ASSOCIATED:
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
@@ -3556,43 +4465,67 @@ static inline void ipw_rx_notification(struct ipw_priv *priv,
priv->status &=
~(STATUS_SCANNING | STATUS_SCAN_ABORTING);
+ wake_up_interruptible(&priv->wait_state);
cancel_delayed_work(&priv->scan_check);
+ if (priv->status & STATUS_EXIT_PENDING)
+ break;
+
+ priv->ieee->scans++;
+
+#ifdef CONFIG_IPW2200_MONITOR
+ if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+ priv->status |= STATUS_SCAN_FORCED;
+ queue_work(priv->workqueue,
+ &priv->request_scan);
+ break;
+ }
+ priv->status &= ~STATUS_SCAN_FORCED;
+#endif /* CONFIG_IPW2200_MONITOR */
+
if (!(priv->status & (STATUS_ASSOCIATED |
STATUS_ASSOCIATING |
STATUS_ROAMING |
STATUS_DISASSOCIATING)))
queue_work(priv->workqueue, &priv->associate);
else if (priv->status & STATUS_ROAMING) {
- /* If a scan completed and we are in roam mode, then
- * the scan that completed was the one requested as a
- * result of entering roam... so, schedule the
- * roam work */
- queue_work(priv->workqueue, &priv->roam);
+ if (x->status == SCAN_COMPLETED_STATUS_COMPLETE)
+ /* If a scan completed and we are in roam mode, then
+ * the scan that completed was the one requested as a
+ * result of entering roam... so, schedule the
+ * roam work */
+ queue_work(priv->workqueue,
+ &priv->roam);
+ else
+ /* Don't schedule if we aborted the scan */
+ priv->status &= ~STATUS_ROAMING;
} else if (priv->status & STATUS_SCAN_PENDING)
queue_work(priv->workqueue,
&priv->request_scan);
-
- priv->ieee->scans++;
+ else if (priv->config & CFG_BACKGROUND_SCAN
+ && priv->status & STATUS_ASSOCIATED)
+ queue_delayed_work(priv->workqueue,
+ &priv->request_scan, HZ);
break;
}
case HOST_NOTIFICATION_STATUS_FRAG_LENGTH:{
struct notif_frag_length *x = &notif->u.frag_len;
- if (notif->size == sizeof(*x)) {
- IPW_ERROR("Frag length: %d\n", x->frag_length);
- } else {
+ if (notif->size == sizeof(*x))
+ IPW_ERROR("Frag length: %d\n",
+ le16_to_cpu(x->frag_length));
+ else
IPW_ERROR("Frag length of wrong size %d "
"(should be %zd)\n",
notif->size, sizeof(*x));
- }
break;
}
case HOST_NOTIFICATION_STATUS_LINK_DETERIORATION:{
struct notif_link_deterioration *x =
&notif->u.link_deterioration;
+
if (notif->size == sizeof(*x)) {
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
"link deterioration: '%s' " MAC_FMT
@@ -3612,11 +4545,9 @@ static inline void ipw_rx_notification(struct ipw_priv *priv,
case HOST_NOTIFICATION_DINO_CONFIG_RESPONSE:{
IPW_ERROR("Dino config\n");
if (priv->hcmd
- && priv->hcmd->cmd == HOST_CMD_DINO_CONFIG) {
- /* TODO: Do anything special? */
- } else {
+ && priv->hcmd->cmd != HOST_CMD_DINO_CONFIG)
IPW_ERROR("Unexpected DINO_CONFIG_RESPONSE\n");
- }
+
break;
}
@@ -3629,36 +4560,11 @@ static inline void ipw_rx_notification(struct ipw_priv *priv,
break;
}
- if (x->state == HOST_NOTIFICATION_STATUS_BEACON_MISSING) {
- if (priv->status & STATUS_SCANNING) {
- /* Stop scan to keep fw from getting
- * stuck... */
- queue_work(priv->workqueue,
- &priv->abort_scan);
- }
-
- if (x->number > priv->missed_beacon_threshold &&
- priv->status & STATUS_ASSOCIATED) {
- IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
- IPW_DL_STATE,
- "Missed beacon: %d - disassociate\n",
- x->number);
- queue_work(priv->workqueue,
- &priv->disassociate);
- } else if (x->number > priv->roaming_threshold) {
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
- "Missed beacon: %d - initiate "
- "roaming\n", x->number);
- queue_work(priv->workqueue,
- &priv->roam);
- } else {
- IPW_DEBUG_NOTIF("Missed beacon: %d\n",
- x->number);
- }
-
- priv->notif_missed_beacons = x->number;
-
- }
+ if (le32_to_cpu(x->state) ==
+ HOST_NOTIFICATION_STATUS_BEACON_MISSING)
+ ipw_handle_missed_beacon(priv,
+ le32_to_cpu(x->
+ number));
break;
}
@@ -3697,7 +4603,8 @@ static inline void ipw_rx_notification(struct ipw_priv *priv,
case HOST_NOTIFICATION_NOISE_STATS:{
if (notif->size == sizeof(u32)) {
priv->last_noise =
- (u8) (notif->u.noise.value & 0xff);
+ (u8) (le32_to_cpu(notif->u.noise.value) &
+ 0xff);
average_add(&priv->average_noise,
priv->last_noise);
break;
@@ -3730,43 +4637,43 @@ static int ipw_queue_reset(struct ipw_priv *priv)
ipw_tx_queue_free(priv);
/* Tx CMD queue */
rc = ipw_queue_tx_init(priv, &priv->txq_cmd, nTxCmd,
- CX2_TX_CMD_QUEUE_READ_INDEX,
- CX2_TX_CMD_QUEUE_WRITE_INDEX,
- CX2_TX_CMD_QUEUE_BD_BASE,
- CX2_TX_CMD_QUEUE_BD_SIZE);
+ IPW_TX_CMD_QUEUE_READ_INDEX,
+ IPW_TX_CMD_QUEUE_WRITE_INDEX,
+ IPW_TX_CMD_QUEUE_BD_BASE,
+ IPW_TX_CMD_QUEUE_BD_SIZE);
if (rc) {
IPW_ERROR("Tx Cmd queue init failed\n");
goto error;
}
/* Tx queue(s) */
rc = ipw_queue_tx_init(priv, &priv->txq[0], nTx,
- CX2_TX_QUEUE_0_READ_INDEX,
- CX2_TX_QUEUE_0_WRITE_INDEX,
- CX2_TX_QUEUE_0_BD_BASE, CX2_TX_QUEUE_0_BD_SIZE);
+ IPW_TX_QUEUE_0_READ_INDEX,
+ IPW_TX_QUEUE_0_WRITE_INDEX,
+ IPW_TX_QUEUE_0_BD_BASE, IPW_TX_QUEUE_0_BD_SIZE);
if (rc) {
IPW_ERROR("Tx 0 queue init failed\n");
goto error;
}
rc = ipw_queue_tx_init(priv, &priv->txq[1], nTx,
- CX2_TX_QUEUE_1_READ_INDEX,
- CX2_TX_QUEUE_1_WRITE_INDEX,
- CX2_TX_QUEUE_1_BD_BASE, CX2_TX_QUEUE_1_BD_SIZE);
+ IPW_TX_QUEUE_1_READ_INDEX,
+ IPW_TX_QUEUE_1_WRITE_INDEX,
+ IPW_TX_QUEUE_1_BD_BASE, IPW_TX_QUEUE_1_BD_SIZE);
if (rc) {
IPW_ERROR("Tx 1 queue init failed\n");
goto error;
}
rc = ipw_queue_tx_init(priv, &priv->txq[2], nTx,
- CX2_TX_QUEUE_2_READ_INDEX,
- CX2_TX_QUEUE_2_WRITE_INDEX,
- CX2_TX_QUEUE_2_BD_BASE, CX2_TX_QUEUE_2_BD_SIZE);
+ IPW_TX_QUEUE_2_READ_INDEX,
+ IPW_TX_QUEUE_2_WRITE_INDEX,
+ IPW_TX_QUEUE_2_BD_BASE, IPW_TX_QUEUE_2_BD_SIZE);
if (rc) {
IPW_ERROR("Tx 2 queue init failed\n");
goto error;
}
rc = ipw_queue_tx_init(priv, &priv->txq[3], nTx,
- CX2_TX_QUEUE_3_READ_INDEX,
- CX2_TX_QUEUE_3_WRITE_INDEX,
- CX2_TX_QUEUE_3_BD_BASE, CX2_TX_QUEUE_3_BD_SIZE);
+ IPW_TX_QUEUE_3_READ_INDEX,
+ IPW_TX_QUEUE_3_WRITE_INDEX,
+ IPW_TX_QUEUE_3_BD_BASE, IPW_TX_QUEUE_3_BD_SIZE);
if (rc) {
IPW_ERROR("Tx 3 queue init failed\n");
goto error;
@@ -3814,9 +4721,10 @@ static int ipw_queue_tx_reclaim(struct ipw_priv *priv,
priv->tx_packets++;
}
done:
- if (ipw_queue_space(q) > q->low_mark && qindex >= 0) {
- __maybe_wake_tx(priv);
- }
+ if ((ipw_queue_space(q) > q->low_mark) &&
+ (qindex >= 0) &&
+ (priv->status & STATUS_ASSOCIATED) && netif_running(priv->net_dev))
+ netif_wake_queue(priv->net_dev);
used = q->first_empty - q->last_used;
if (used < 0)
used += q->n_bd;
@@ -3857,7 +4765,7 @@ static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, void *buf,
* Rx theory of operation
*
* The host allocates 32 DMA target addresses and passes the host address
- * to the firmware at register CX2_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
+ * to the firmware at register IPW_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
* 0 to 31
*
* Rx Queue Indexes
@@ -3941,7 +4849,7 @@ static void ipw_rx_queue_restock(struct ipw_priv *priv)
rxb = list_entry(element, struct ipw_rx_mem_buffer, list);
list_del(element);
- ipw_write32(priv, CX2_RFDS_TABLE_LOWER + rxq->write * RFD_SIZE,
+ ipw_write32(priv, IPW_RFDS_TABLE_LOWER + rxq->write * RFD_SIZE,
rxb->dma_addr);
rxq->queue[rxq->write] = rxb;
rxq->write = (rxq->write + 1) % RX_QUEUE_SIZE;
@@ -3956,7 +4864,7 @@ static void ipw_rx_queue_restock(struct ipw_priv *priv)
/* If we've added more space for the firmware to place data, tell it */
if (write != rxq->write)
- ipw_write32(priv, CX2_RX_WRITE_INDEX, rxq->write);
+ ipw_write32(priv, IPW_RX_WRITE_INDEX, rxq->write);
}
/*
@@ -3977,7 +4885,7 @@ static void ipw_rx_queue_replenish(void *data)
while (!list_empty(&rxq->rx_used)) {
element = rxq->rx_used.next;
rxb = list_entry(element, struct ipw_rx_mem_buffer, list);
- rxb->skb = alloc_skb(CX2_RX_BUF_SIZE, GFP_ATOMIC);
+ rxb->skb = alloc_skb(IPW_RX_BUF_SIZE, GFP_ATOMIC);
if (!rxb->skb) {
printk(KERN_CRIT "%s: Can not allocate SKB buffers.\n",
priv->net_dev->name);
@@ -3991,7 +4899,7 @@ static void ipw_rx_queue_replenish(void *data)
rxb->rxb = (struct ipw_rx_buffer *)rxb->skb->data;
rxb->dma_addr =
pci_map_single(priv->pci_dev, rxb->skb->data,
- CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++;
@@ -4001,6 +4909,14 @@ static void ipw_rx_queue_replenish(void *data)
ipw_rx_queue_restock(priv);
}
+static void ipw_bg_rx_queue_replenish(void *data)
+{
+ struct ipw_priv *priv = data;
+ down(&priv->sem);
+ ipw_rx_queue_replenish(data);
+ up(&priv->sem);
+}
+
/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
* If an SKB has been detached, the POOL needs to have it's SKB set to NULL
* This free routine walks the list of POOL entries and if SKB is set to
@@ -4016,7 +4932,7 @@ static void ipw_rx_queue_free(struct ipw_priv *priv, struct ipw_rx_queue *rxq)
for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
if (rxq->pool[i].skb != NULL) {
pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr,
- CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
dev_kfree_skb(rxq->pool[i].skb);
}
}
@@ -4135,8 +5051,18 @@ static int ipw_compatible_rates(struct ipw_priv *priv,
num_rates = min(network->rates_len, (u8) IPW_MAX_RATES);
rates->num_rates = 0;
for (i = 0; i < num_rates; i++) {
- if (!ipw_is_rate_in_mask
- (priv, network->mode, network->rates[i])) {
+ if (!ipw_is_rate_in_mask(priv, network->mode,
+ network->rates[i])) {
+
+ if (network->rates[i] & IEEE80211_BASIC_RATE_MASK) {
+ IPW_DEBUG_SCAN("Adding masked mandatory "
+ "rate %02X\n",
+ network->rates[i]);
+ rates->supported_rates[rates->num_rates++] =
+ network->rates[i];
+ continue;
+ }
+
IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n",
network->rates[i], priv->rates_mask);
continue;
@@ -4145,11 +5071,20 @@ static int ipw_compatible_rates(struct ipw_priv *priv,
rates->supported_rates[rates->num_rates++] = network->rates[i];
}
- num_rates =
- min(network->rates_ex_len, (u8) (IPW_MAX_RATES - num_rates));
+ num_rates = min(network->rates_ex_len,
+ (u8) (IPW_MAX_RATES - num_rates));
for (i = 0; i < num_rates; i++) {
- if (!ipw_is_rate_in_mask
- (priv, network->mode, network->rates_ex[i])) {
+ if (!ipw_is_rate_in_mask(priv, network->mode,
+ network->rates_ex[i])) {
+ if (network->rates_ex[i] & IEEE80211_BASIC_RATE_MASK) {
+ IPW_DEBUG_SCAN("Adding masked mandatory "
+ "rate %02X\n",
+ network->rates_ex[i]);
+ rates->supported_rates[rates->num_rates++] =
+ network->rates[i];
+ continue;
+ }
+
IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n",
network->rates_ex[i], priv->rates_mask);
continue;
@@ -4159,7 +5094,7 @@ static int ipw_compatible_rates(struct ipw_priv *priv,
network->rates_ex[i];
}
- return rates->num_rates;
+ return 1;
}
static inline void ipw_copy_rates(struct ipw_supported_rates *dest,
@@ -4241,6 +5176,216 @@ struct ipw_network_match {
struct ipw_supported_rates rates;
};
+static int ipw_find_adhoc_network(struct ipw_priv *priv,
+ struct ipw_network_match *match,
+ struct ieee80211_network *network,
+ int roaming)
+{
+ struct ipw_supported_rates rates;
+
+ /* Verify that this network's capability is compatible with the
+ * current mode (AdHoc or Infrastructure) */
+ if ((priv->ieee->iw_mode == IW_MODE_ADHOC &&
+ !(network->capability & WLAN_CAPABILITY_IBSS))) {
+ IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded due to "
+ "capability mismatch.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid));
+ return 0;
+ }
+
+ /* If we do not have an ESSID for this AP, we can not associate with
+ * it */
+ if (network->flags & NETWORK_EMPTY_ESSID) {
+ IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ "because of hidden ESSID.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid));
+ return 0;
+ }
+
+ if (unlikely(roaming)) {
+ /* If we are roaming, then ensure check if this is a valid
+ * network to try and roam to */
+ if ((network->ssid_len != match->network->ssid_len) ||
+ memcmp(network->ssid, match->network->ssid,
+ network->ssid_len)) {
+ IPW_DEBUG_MERGE("Netowrk '%s (" MAC_FMT ")' excluded "
+ "because of non-network ESSID.\n",
+ escape_essid(network->ssid,
+ network->ssid_len),
+ MAC_ARG(network->bssid));
+ return 0;
+ }
+ } else {
+ /* If an ESSID has been configured then compare the broadcast
+ * ESSID to ours */
+ if ((priv->config & CFG_STATIC_ESSID) &&
+ ((network->ssid_len != priv->essid_len) ||
+ memcmp(network->ssid, priv->essid,
+ min(network->ssid_len, priv->essid_len)))) {
+ char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+
+ strncpy(escaped,
+ escape_essid(network->ssid, network->ssid_len),
+ sizeof(escaped));
+ IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ "because of ESSID mismatch: '%s'.\n",
+ escaped, MAC_ARG(network->bssid),
+ escape_essid(priv->essid,
+ priv->essid_len));
+ return 0;
+ }
+ }
+
+ /* If the old network rate is better than this one, don't bother
+ * testing everything else. */
+
+ if (network->time_stamp[0] < match->network->time_stamp[0]) {
+ IPW_DEBUG_MERGE("Network '%s excluded because newer than "
+ "current network.\n",
+ escape_essid(match->network->ssid,
+ match->network->ssid_len));
+ return 0;
+ } else if (network->time_stamp[1] < match->network->time_stamp[1]) {
+ IPW_DEBUG_MERGE("Network '%s excluded because newer than "
+ "current network.\n",
+ escape_essid(match->network->ssid,
+ match->network->ssid_len));
+ return 0;
+ }
+
+ /* Now go through and see if the requested network is valid... */
+ if (priv->ieee->scan_age != 0 &&
+ time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
+ IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ "because of age: %lums.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid),
+ 1000 * (jiffies - network->last_scanned) / HZ);
+ return 0;
+ }
+
+ if ((priv->config & CFG_STATIC_CHANNEL) &&
+ (network->channel != priv->channel)) {
+ IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ "because of channel mismatch: %d != %d.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid),
+ network->channel, priv->channel);
+ return 0;
+ }
+
+ /* Verify privacy compatability */
+ if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
+ ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
+ IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ "because of privacy mismatch: %s != %s.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid),
+ priv->
+ capability & CAP_PRIVACY_ON ? "on" : "off",
+ network->
+ capability & WLAN_CAPABILITY_PRIVACY ? "on" :
+ "off");
+ return 0;
+ }
+
+ if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
+ IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ "because of the same BSSID match: " MAC_FMT
+ ".\n", escape_essid(network->ssid,
+ network->ssid_len),
+ MAC_ARG(network->bssid), MAC_ARG(priv->bssid));
+ return 0;
+ }
+
+ /* Filter out any incompatible freq / mode combinations */
+ if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) {
+ IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ "because of invalid frequency/mode "
+ "combination.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid));
+ return 0;
+ }
+
+ /* Ensure that the rates supported by the driver are compatible with
+ * this AP, including verification of basic rates (mandatory) */
+ if (!ipw_compatible_rates(priv, network, &rates)) {
+ IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ "because configured rate mask excludes "
+ "AP mandatory rate.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid));
+ return 0;
+ }
+
+ if (rates.num_rates == 0) {
+ IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ "because of no compatible rates.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid));
+ return 0;
+ }
+
+ /* TODO: Perform any further minimal comparititive tests. We do not
+ * want to put too much policy logic here; intelligent scan selection
+ * should occur within a generic IEEE 802.11 user space tool. */
+
+ /* Set up 'new' AP to this network */
+ ipw_copy_rates(&match->rates, &rates);
+ match->network = network;
+ IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' is a viable match.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid));
+
+ return 1;
+}
+
+static void ipw_merge_adhoc_network(void *data)
+{
+ struct ipw_priv *priv = data;
+ struct ieee80211_network *network = NULL;
+ struct ipw_network_match match = {
+ .network = priv->assoc_network
+ };
+
+ if ((priv->status & STATUS_ASSOCIATED) &&
+ (priv->ieee->iw_mode == IW_MODE_ADHOC)) {
+ /* First pass through ROAM process -- look for a better
+ * network */
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->ieee->lock, flags);
+ list_for_each_entry(network, &priv->ieee->network_list, list) {
+ if (network != priv->assoc_network)
+ ipw_find_adhoc_network(priv, &match, network,
+ 1);
+ }
+ spin_unlock_irqrestore(&priv->ieee->lock, flags);
+
+ if (match.network == priv->assoc_network) {
+ IPW_DEBUG_MERGE("No better ADHOC in this network to "
+ "merge to.\n");
+ return;
+ }
+
+ down(&priv->sem);
+ if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) {
+ IPW_DEBUG_MERGE("remove network %s\n",
+ escape_essid(priv->essid,
+ priv->essid_len));
+ ipw_remove_current_network(priv);
+ }
+
+ ipw_disassociate(priv);
+ priv->assoc_network = match.network;
+ up(&priv->sem);
+ return;
+ }
+}
+
static int ipw_best_network(struct ipw_priv *priv,
struct ipw_network_match *match,
struct ieee80211_network *network, int roaming)
@@ -4322,9 +5467,9 @@ static int ipw_best_network(struct ipw_priv *priv,
/* If this network has already had an association attempt within the
* last 3 seconds, do not try and associate again... */
if (network->last_associate &&
- time_after(network->last_associate + (HZ * 5UL), jiffies)) {
+ time_after(network->last_associate + (HZ * 3UL), jiffies)) {
IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
- "because of storming (%lu since last "
+ "because of storming (%lus since last "
"assoc attempt).\n",
escape_essid(network->ssid, network->ssid_len),
MAC_ARG(network->bssid),
@@ -4334,12 +5479,12 @@ static int ipw_best_network(struct ipw_priv *priv,
/* Now go through and see if the requested network is valid... */
if (priv->ieee->scan_age != 0 &&
- jiffies - network->last_scanned > priv->ieee->scan_age) {
+ time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
"because of age: %lums.\n",
escape_essid(network->ssid, network->ssid_len),
MAC_ARG(network->bssid),
- (jiffies - network->last_scanned) / (HZ / 100));
+ 1000 * (jiffies - network->last_scanned) / HZ);
return 0;
}
@@ -4367,6 +5512,15 @@ static int ipw_best_network(struct ipw_priv *priv,
return 0;
}
+ if (!priv->ieee->wpa_enabled && (network->wpa_ie_len > 0 ||
+ network->rsn_ie_len > 0)) {
+ IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ "because of WPA capability mismatch.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid));
+ return 0;
+ }
+
if ((priv->config & CFG_STATIC_BSSID) &&
memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
@@ -4386,7 +5540,26 @@ static int ipw_best_network(struct ipw_priv *priv,
return 0;
}
- ipw_compatible_rates(priv, network, &rates);
+ /* Filter out invalid channel in current GEO */
+ if (!ipw_is_valid_channel(priv->ieee, network->channel)) {
+ IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ "because of invalid channel in current GEO\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid));
+ return 0;
+ }
+
+ /* Ensure that the rates supported by the driver are compatible with
+ * this AP, including verification of basic rates (mandatory) */
+ if (!ipw_compatible_rates(priv, network, &rates)) {
+ IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ "because configured rate mask excludes "
+ "AP mandatory rate.\n",
+ escape_essid(network->ssid, network->ssid_len),
+ MAC_ARG(network->bssid));
+ return 0;
+ }
+
if (rates.num_rates == 0) {
IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
"because of no compatible rates.\n",
@@ -4413,6 +5586,9 @@ static int ipw_best_network(struct ipw_priv *priv,
static void ipw_adhoc_create(struct ipw_priv *priv,
struct ieee80211_network *network)
{
+ const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee);
+ int i;
+
/*
* For the purposes of scanning, we can set our wireless mode
* to trigger scans across combinations of bands, but when it
@@ -4423,22 +5599,47 @@ static void ipw_adhoc_create(struct ipw_priv *priv,
* chossen band. Attempting to create a new ad-hoc network
* with an invalid channel for wireless mode will trigger a
* FW fatal error.
+ *
*/
- network->mode = is_valid_channel(priv->ieee->mode, priv->channel);
- if (network->mode) {
- network->channel = priv->channel;
- } else {
+ switch (ipw_is_valid_channel(priv->ieee, priv->channel)) {
+ case IEEE80211_52GHZ_BAND:
+ network->mode = IEEE_A;
+ i = ipw_channel_to_index(priv->ieee, priv->channel);
+ if (i == -1)
+ BUG();
+ if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) {
+ IPW_WARNING("Overriding invalid channel\n");
+ priv->channel = geo->a[0].channel;
+ }
+ break;
+
+ case IEEE80211_24GHZ_BAND:
+ if (priv->ieee->mode & IEEE_G)
+ network->mode = IEEE_G;
+ else
+ network->mode = IEEE_B;
+ i = ipw_channel_to_index(priv->ieee, priv->channel);
+ if (i == -1)
+ BUG();
+ if (geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY) {
+ IPW_WARNING("Overriding invalid channel\n");
+ priv->channel = geo->bg[0].channel;
+ }
+ break;
+
+ default:
IPW_WARNING("Overriding invalid channel\n");
if (priv->ieee->mode & IEEE_A) {
network->mode = IEEE_A;
- priv->channel = band_a_active_channel[0];
+ priv->channel = geo->a[0].channel;
} else if (priv->ieee->mode & IEEE_G) {
network->mode = IEEE_G;
- priv->channel = band_b_active_channel[0];
+ priv->channel = geo->bg[0].channel;
} else {
network->mode = IEEE_B;
- priv->channel = band_b_active_channel[0];
+ priv->channel = geo->bg[0].channel;
}
+ break;
}
network->channel = priv->channel;
@@ -4448,6 +5649,8 @@ static void ipw_adhoc_create(struct ipw_priv *priv,
memcpy(network->ssid, priv->essid, priv->essid_len);
memset(&network->stats, 0, sizeof(network->stats));
network->capability = WLAN_CAPABILITY_IBSS;
+ if (!(priv->config & CFG_PREAMBLE_LONG))
+ network->capability |= WLAN_CAPABILITY_SHORT_PREAMBLE;
if (priv->capability & CAP_PRIVACY_ON)
network->capability |= WLAN_CAPABILITY_PRIVACY;
network->rates_len = min(priv->rates.num_rates, MAX_RATES_LENGTH);
@@ -4464,13 +5667,35 @@ static void ipw_adhoc_create(struct ipw_priv *priv,
network->beacon_interval = 100; /* Default */
network->listen_interval = 10; /* Default */
network->atim_window = 0; /* Default */
-#ifdef CONFIG_IEEE80211_WPA
network->wpa_ie_len = 0;
network->rsn_ie_len = 0;
-#endif /* CONFIG_IEEE80211_WPA */
}
-static void ipw_send_wep_keys(struct ipw_priv *priv)
+static void ipw_send_tgi_tx_key(struct ipw_priv *priv, int type, int index)
+{
+ struct ipw_tgi_tx_key *key;
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_TGI_TX_KEY,
+ .len = sizeof(*key)
+ };
+
+ if (!(priv->ieee->sec.flags & (1 << index)))
+ return;
+
+ key = (struct ipw_tgi_tx_key *)&cmd.param;
+ key->key_id = index;
+ memcpy(key->key, priv->ieee->sec.keys[index], SCM_TEMPORAL_KEY_LENGTH);
+ key->security_type = type;
+ key->station_index = 0; /* always 0 for BSS */
+ key->flags = 0;
+ /* 0 for new key; previous value of counter (after fatal error) */
+ key->tx_counter[0] = 0;
+ key->tx_counter[1] = 0;
+
+ ipw_send_cmd(priv, &cmd);
+}
+
+static void ipw_send_wep_keys(struct ipw_priv *priv, int type)
{
struct ipw_wep_key *key;
int i;
@@ -4483,19 +5708,97 @@ static void ipw_send_wep_keys(struct ipw_priv *priv)
key->cmd_id = DINO_CMD_WEP_KEY;
key->seq_num = 0;
+ /* Note: AES keys cannot be set for multiple times.
+ * Only set it at the first time. */
for (i = 0; i < 4; i++) {
- key->key_index = i;
- if (!(priv->sec.flags & (1 << i))) {
+ key->key_index = i | type;
+ if (!(priv->ieee->sec.flags & (1 << i))) {
key->key_size = 0;
- } else {
- key->key_size = priv->sec.key_sizes[i];
- memcpy(key->key, priv->sec.keys[i], key->key_size);
+ continue;
}
- if (ipw_send_cmd(priv, &cmd)) {
- IPW_ERROR("failed to send WEP_KEY command\n");
- return;
- }
+ key->key_size = priv->ieee->sec.key_sizes[i];
+ memcpy(key->key, priv->ieee->sec.keys[i], key->key_size);
+
+ ipw_send_cmd(priv, &cmd);
+ }
+}
+
+static void ipw_set_hw_decrypt_unicast(struct ipw_priv *priv, int level)
+{
+ if (priv->ieee->host_encrypt)
+ return;
+
+ switch (level) {
+ case SEC_LEVEL_3:
+ priv->sys_config.disable_unicast_decryption = 0;
+ priv->ieee->host_decrypt = 0;
+ break;
+ case SEC_LEVEL_2:
+ priv->sys_config.disable_unicast_decryption = 1;
+ priv->ieee->host_decrypt = 1;
+ break;
+ case SEC_LEVEL_1:
+ priv->sys_config.disable_unicast_decryption = 0;
+ priv->ieee->host_decrypt = 0;
+ break;
+ case SEC_LEVEL_0:
+ priv->sys_config.disable_unicast_decryption = 1;
+ break;
+ default:
+ break;
+ }
+}
+
+static void ipw_set_hw_decrypt_multicast(struct ipw_priv *priv, int level)
+{
+ if (priv->ieee->host_encrypt)
+ return;
+
+ switch (level) {
+ case SEC_LEVEL_3:
+ priv->sys_config.disable_multicast_decryption = 0;
+ break;
+ case SEC_LEVEL_2:
+ priv->sys_config.disable_multicast_decryption = 1;
+ break;
+ case SEC_LEVEL_1:
+ priv->sys_config.disable_multicast_decryption = 0;
+ break;
+ case SEC_LEVEL_0:
+ priv->sys_config.disable_multicast_decryption = 1;
+ break;
+ default:
+ break;
+ }
+}
+
+static void ipw_set_hwcrypto_keys(struct ipw_priv *priv)
+{
+ switch (priv->ieee->sec.level) {
+ case SEC_LEVEL_3:
+ if (priv->ieee->sec.flags & SEC_ACTIVE_KEY)
+ ipw_send_tgi_tx_key(priv,
+ DCT_FLAG_EXT_SECURITY_CCM,
+ priv->ieee->sec.active_key);
+
+ if (!priv->ieee->host_mc_decrypt)
+ ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM);
+ break;
+ case SEC_LEVEL_2:
+ if (priv->ieee->sec.flags & SEC_ACTIVE_KEY)
+ ipw_send_tgi_tx_key(priv,
+ DCT_FLAG_EXT_SECURITY_TKIP,
+ priv->ieee->sec.active_key);
+ break;
+ case SEC_LEVEL_1:
+ ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP);
+ ipw_set_hw_decrypt_unicast(priv, priv->ieee->sec.level);
+ ipw_set_hw_decrypt_multicast(priv, priv->ieee->sec.level);
+ break;
+ case SEC_LEVEL_0:
+ default:
+ break;
}
}
@@ -4503,9 +5806,12 @@ static void ipw_adhoc_check(void *data)
{
struct ipw_priv *priv = data;
- if (priv->missed_adhoc_beacons++ > priv->missed_beacon_threshold &&
+ if (priv->missed_adhoc_beacons++ > priv->disassociate_threshold &&
!(priv->config & CFG_ADHOC_PERSIST)) {
- IPW_DEBUG_SCAN("Disassociating due to missed beacons\n");
+ IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
+ IPW_DL_STATE | IPW_DL_ASSOC,
+ "Missed beacon: %d - disassociate\n",
+ priv->missed_adhoc_beacons);
ipw_remove_current_network(priv);
ipw_disassociate(priv);
return;
@@ -4515,6 +5821,14 @@ static void ipw_adhoc_check(void *data)
priv->assoc_request.beacon_interval);
}
+static void ipw_bg_adhoc_check(void *data)
+{
+ struct ipw_priv *priv = data;
+ down(&priv->sem);
+ ipw_adhoc_check(data);
+ up(&priv->sem);
+}
+
#ifdef CONFIG_IPW_DEBUG
static void ipw_debug_config(struct ipw_priv *priv)
{
@@ -4530,7 +5844,8 @@ static void ipw_debug_config(struct ipw_priv *priv)
else
IPW_DEBUG_INFO("ESSID unlocked.\n");
if (priv->config & CFG_STATIC_BSSID)
- IPW_DEBUG_INFO("BSSID locked to %d\n", priv->channel);
+ IPW_DEBUG_INFO("BSSID locked to " MAC_FMT "\n",
+ MAC_ARG(priv->bssid));
else
IPW_DEBUG_INFO("BSSID unlocked.\n");
if (priv->capability & CAP_PRIVACY_ON)
@@ -4543,8 +5858,7 @@ static void ipw_debug_config(struct ipw_priv *priv)
#define ipw_debug_config(x) do {} while (0)
#endif
-static inline void ipw_set_fixed_rate(struct ipw_priv *priv,
- struct ieee80211_network *network)
+static inline void ipw_set_fixed_rate(struct ipw_priv *priv, int mode)
{
/* TODO: Verify that this works... */
struct ipw_fixed_rate fr = {
@@ -4561,6 +5875,8 @@ static inline void ipw_set_fixed_rate(struct ipw_priv *priv,
/* IEEE_A */
if (priv->rates_mask & ~IEEE80211_OFDM_RATES_MASK) {
/* Invalid fixed rate mask */
+ IPW_DEBUG_WX
+ ("invalid fixed rate mask in ipw_set_fixed_rate\n");
fr.tx_rates = 0;
break;
}
@@ -4570,9 +5886,11 @@ static inline void ipw_set_fixed_rate(struct ipw_priv *priv,
default: /* 2.4Ghz or Mixed */
/* IEEE_B */
- if (network->mode == IEEE_B) {
+ if (mode == IEEE_B) {
if (fr.tx_rates & ~IEEE80211_CCK_RATES_MASK) {
/* Invalid fixed rate mask */
+ IPW_DEBUG_WX
+ ("invalid fixed rate mask in ipw_set_fixed_rate\n");
fr.tx_rates = 0;
}
break;
@@ -4582,6 +5900,8 @@ static inline void ipw_set_fixed_rate(struct ipw_priv *priv,
if (fr.tx_rates & ~(IEEE80211_CCK_RATES_MASK |
IEEE80211_OFDM_RATES_MASK)) {
/* Invalid fixed rate mask */
+ IPW_DEBUG_WX
+ ("invalid fixed rate mask in ipw_set_fixed_rate\n");
fr.tx_rates = 0;
break;
}
@@ -4609,6 +5929,1112 @@ static inline void ipw_set_fixed_rate(struct ipw_priv *priv,
ipw_write_reg32(priv, reg, *(u32 *) & fr);
}
+static void ipw_abort_scan(struct ipw_priv *priv)
+{
+ int err;
+
+ if (priv->status & STATUS_SCAN_ABORTING) {
+ IPW_DEBUG_HC("Ignoring concurrent scan abort request.\n");
+ return;
+ }
+ priv->status |= STATUS_SCAN_ABORTING;
+
+ err = ipw_send_scan_abort(priv);
+ if (err)
+ IPW_DEBUG_HC("Request to abort scan failed.\n");
+}
+
+static void ipw_add_scan_channels(struct ipw_priv *priv,
+ struct ipw_scan_request_ext *scan,
+ int scan_type)
+{
+ int channel_index = 0;
+ const struct ieee80211_geo *geo;
+ int i;
+
+ geo = ipw_get_geo(priv->ieee);
+
+ if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) {
+ int start = channel_index;
+ for (i = 0; i < geo->a_channels; i++) {
+ if ((priv->status & STATUS_ASSOCIATED) &&
+ geo->a[i].channel == priv->channel)
+ continue;
+ channel_index++;
+ scan->channels_list[channel_index] = geo->a[i].channel;
+ ipw_set_scan_type(scan, channel_index,
+ geo->a[i].
+ flags & IEEE80211_CH_PASSIVE_ONLY ?
+ IPW_SCAN_PASSIVE_FULL_DWELL_SCAN :
+ scan_type);
+ }
+
+ if (start != channel_index) {
+ scan->channels_list[start] = (u8) (IPW_A_MODE << 6) |
+ (channel_index - start);
+ channel_index++;
+ }
+ }
+
+ if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) {
+ int start = channel_index;
+ if (priv->config & CFG_SPEED_SCAN) {
+ int index;
+ u8 channels[IEEE80211_24GHZ_CHANNELS] = {
+ /* nop out the list */
+ [0] = 0
+ };
+
+ u8 channel;
+ while (channel_index < IPW_SCAN_CHANNELS) {
+ channel =
+ priv->speed_scan[priv->speed_scan_pos];
+ if (channel == 0) {
+ priv->speed_scan_pos = 0;
+ channel = priv->speed_scan[0];
+ }
+ if ((priv->status & STATUS_ASSOCIATED) &&
+ channel == priv->channel) {
+ priv->speed_scan_pos++;
+ continue;
+ }
+
+ /* If this channel has already been
+ * added in scan, break from loop
+ * and this will be the first channel
+ * in the next scan.
+ */
+ if (channels[channel - 1] != 0)
+ break;
+
+ channels[channel - 1] = 1;
+ priv->speed_scan_pos++;
+ channel_index++;
+ scan->channels_list[channel_index] = channel;
+ index =
+ ipw_channel_to_index(priv->ieee, channel);
+ ipw_set_scan_type(scan, channel_index,
+ geo->bg[index].
+ flags &
+ IEEE80211_CH_PASSIVE_ONLY ?
+ IPW_SCAN_PASSIVE_FULL_DWELL_SCAN
+ : scan_type);
+ }
+ } else {
+ for (i = 0; i < geo->bg_channels; i++) {
+ if ((priv->status & STATUS_ASSOCIATED) &&
+ geo->bg[i].channel == priv->channel)
+ continue;
+ channel_index++;
+ scan->channels_list[channel_index] =
+ geo->bg[i].channel;
+ ipw_set_scan_type(scan, channel_index,
+ geo->bg[i].
+ flags &
+ IEEE80211_CH_PASSIVE_ONLY ?
+ IPW_SCAN_PASSIVE_FULL_DWELL_SCAN
+ : scan_type);
+ }
+ }
+
+ if (start != channel_index) {
+ scan->channels_list[start] = (u8) (IPW_B_MODE << 6) |
+ (channel_index - start);
+ }
+ }
+}
+
+static int ipw_request_scan(struct ipw_priv *priv)
+{
+ struct ipw_scan_request_ext scan;
+ int err = 0, scan_type;
+
+ if (!(priv->status & STATUS_INIT) ||
+ (priv->status & STATUS_EXIT_PENDING))
+ return 0;
+
+ down(&priv->sem);
+
+ if (priv->status & STATUS_SCANNING) {
+ IPW_DEBUG_HC("Concurrent scan requested. Ignoring.\n");
+ priv->status |= STATUS_SCAN_PENDING;
+ goto done;
+ }
+
+ if (!(priv->status & STATUS_SCAN_FORCED) &&
+ priv->status & STATUS_SCAN_ABORTING) {
+ IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n");
+ priv->status |= STATUS_SCAN_PENDING;
+ goto done;
+ }
+
+ if (priv->status & STATUS_RF_KILL_MASK) {
+ IPW_DEBUG_HC("Aborting scan due to RF Kill activation\n");
+ priv->status |= STATUS_SCAN_PENDING;
+ goto done;
+ }
+
+ memset(&scan, 0, sizeof(scan));
+
+ if (priv->config & CFG_SPEED_SCAN)
+ scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
+ cpu_to_le16(30);
+ else
+ scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
+ cpu_to_le16(20);
+
+ scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] =
+ cpu_to_le16(20);
+ scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120);
+
+ scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee));
+
+#ifdef CONFIG_IPW2200_MONITOR
+ if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+ u8 channel;
+ u8 band = 0;
+
+ switch (ipw_is_valid_channel(priv->ieee, priv->channel)) {
+ case IEEE80211_52GHZ_BAND:
+ band = (u8) (IPW_A_MODE << 6) | 1;
+ channel = priv->channel;
+ break;
+
+ case IEEE80211_24GHZ_BAND:
+ band = (u8) (IPW_B_MODE << 6) | 1;
+ channel = priv->channel;
+ break;
+
+ default:
+ band = (u8) (IPW_B_MODE << 6) | 1;
+ channel = 9;
+ break;
+ }
+
+ scan.channels_list[0] = band;
+ scan.channels_list[1] = channel;
+ ipw_set_scan_type(&scan, 1, IPW_SCAN_PASSIVE_FULL_DWELL_SCAN);
+
+ /* NOTE: The card will sit on this channel for this time
+ * period. Scan aborts are timing sensitive and frequently
+ * result in firmware restarts. As such, it is best to
+ * set a small dwell_time here and just keep re-issuing
+ * scans. Otherwise fast channel hopping will not actually
+ * hop channels.
+ *
+ * TODO: Move SPEED SCAN support to all modes and bands */
+ scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
+ cpu_to_le16(2000);
+ } else {
+#endif /* CONFIG_IPW2200_MONITOR */
+ /* If we are roaming, then make this a directed scan for the
+ * current network. Otherwise, ensure that every other scan
+ * is a fast channel hop scan */
+ if ((priv->status & STATUS_ROAMING)
+ || (!(priv->status & STATUS_ASSOCIATED)
+ && (priv->config & CFG_STATIC_ESSID)
+ && (le32_to_cpu(scan.full_scan_index) % 2))) {
+ err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
+ if (err) {
+ IPW_DEBUG_HC("Attempt to send SSID command "
+ "failed.\n");
+ goto done;
+ }
+
+ scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
+ } else
+ scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN;
+
+ ipw_add_scan_channels(priv, &scan, scan_type);
+#ifdef CONFIG_IPW2200_MONITOR
+ }
+#endif
+
+ err = ipw_send_scan_request_ext(priv, &scan);
+ if (err) {
+ IPW_DEBUG_HC("Sending scan command failed: %08X\n", err);
+ goto done;
+ }
+
+ priv->status |= STATUS_SCANNING;
+ priv->status &= ~STATUS_SCAN_PENDING;
+ queue_delayed_work(priv->workqueue, &priv->scan_check,
+ IPW_SCAN_CHECK_WATCHDOG);
+ done:
+ up(&priv->sem);
+ return err;
+}
+
+static void ipw_bg_abort_scan(void *data)
+{
+ struct ipw_priv *priv = data;
+ down(&priv->sem);
+ ipw_abort_scan(data);
+ up(&priv->sem);
+}
+
+static int ipw_wpa_enable(struct ipw_priv *priv, int value)
+{
+ /* This is called when wpa_supplicant loads and closes the driver
+ * interface. */
+ priv->ieee->wpa_enabled = value;
+ return 0;
+}
+
+static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value)
+{
+ struct ieee80211_device *ieee = priv->ieee;
+ struct ieee80211_security sec = {
+ .flags = SEC_AUTH_MODE,
+ };
+ int ret = 0;
+
+ if (value & IW_AUTH_ALG_SHARED_KEY) {
+ sec.auth_mode = WLAN_AUTH_SHARED_KEY;
+ ieee->open_wep = 0;
+ } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
+ sec.auth_mode = WLAN_AUTH_OPEN;
+ ieee->open_wep = 1;
+ } else
+ return -EINVAL;
+
+ if (ieee->set_security)
+ ieee->set_security(ieee->dev, &sec);
+ else
+ ret = -EOPNOTSUPP;
+
+ return ret;
+}
+
+void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, int wpa_ie_len)
+{
+ /* make sure WPA is enabled */
+ ipw_wpa_enable(priv, 1);
+
+ ipw_disassociate(priv);
+}
+
+static int ipw_set_rsn_capa(struct ipw_priv *priv,
+ char *capabilities, int length)
+{
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_RSN_CAPABILITIES,
+ .len = length,
+ };
+
+ IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n");
+
+ memcpy(cmd.param, capabilities, length);
+ return ipw_send_cmd(priv, &cmd);
+}
+
+/*
+ * WE-18 support
+ */
+
+/* SIOCSIWGENIE */
+static int ipw_wx_set_genie(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ieee80211_device *ieee = priv->ieee;
+ u8 *buf;
+ int err = 0;
+
+ if (wrqu->data.length > MAX_WPA_IE_LEN ||
+ (wrqu->data.length && extra == NULL))
+ return -EINVAL;
+
+ //down(&priv->sem);
+
+ //if (!ieee->wpa_enabled) {
+ // err = -EOPNOTSUPP;
+ // goto out;
+ //}
+
+ if (wrqu->data.length) {
+ buf = kmalloc(wrqu->data.length, GFP_KERNEL);
+ if (buf == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ memcpy(buf, extra, wrqu->data.length);
+ kfree(ieee->wpa_ie);
+ ieee->wpa_ie = buf;
+ ieee->wpa_ie_len = wrqu->data.length;
+ } else {
+ kfree(ieee->wpa_ie);
+ ieee->wpa_ie = NULL;
+ ieee->wpa_ie_len = 0;
+ }
+
+ ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
+ out:
+ //up(&priv->sem);
+ return err;
+}
+
+/* SIOCGIWGENIE */
+static int ipw_wx_get_genie(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ieee80211_device *ieee = priv->ieee;
+ int err = 0;
+
+ //down(&priv->sem);
+
+ //if (!ieee->wpa_enabled) {
+ // err = -EOPNOTSUPP;
+ // goto out;
+ //}
+
+ if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
+ wrqu->data.length = 0;
+ goto out;
+ }
+
+ if (wrqu->data.length < ieee->wpa_ie_len) {
+ err = -E2BIG;
+ goto out;
+ }
+
+ wrqu->data.length = ieee->wpa_ie_len;
+ memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
+
+ out:
+ //up(&priv->sem);
+ return err;
+}
+
+static int wext_cipher2level(int cipher)
+{
+ switch (cipher) {
+ case IW_AUTH_CIPHER_NONE:
+ return SEC_LEVEL_0;
+ case IW_AUTH_CIPHER_WEP40:
+ case IW_AUTH_CIPHER_WEP104:
+ return SEC_LEVEL_1;
+ case IW_AUTH_CIPHER_TKIP:
+ return SEC_LEVEL_2;
+ case IW_AUTH_CIPHER_CCMP:
+ return SEC_LEVEL_3;
+ default:
+ return -1;
+ }
+}
+
+/* SIOCSIWAUTH */
+static int ipw_wx_set_auth(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ieee80211_device *ieee = priv->ieee;
+ struct iw_param *param = &wrqu->param;
+ struct ieee80211_crypt_data *crypt;
+ unsigned long flags;
+ int ret = 0;
+
+ switch (param->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_WPA_VERSION:
+ break;
+ case IW_AUTH_CIPHER_PAIRWISE:
+ ipw_set_hw_decrypt_unicast(priv,
+ wext_cipher2level(param->value));
+ break;
+ case IW_AUTH_CIPHER_GROUP:
+ ipw_set_hw_decrypt_multicast(priv,
+ wext_cipher2level(param->value));
+ break;
+ case IW_AUTH_KEY_MGMT:
+ /*
+ * ipw2200 does not use these parameters
+ */
+ break;
+
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+ if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
+ break;
+
+ flags = crypt->ops->get_flags(crypt->priv);
+
+ if (param->value)
+ flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
+ else
+ flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
+
+ crypt->ops->set_flags(flags, crypt->priv);
+
+ break;
+
+ case IW_AUTH_DROP_UNENCRYPTED:{
+ /* HACK:
+ *
+ * wpa_supplicant calls set_wpa_enabled when the driver
+ * is loaded and unloaded, regardless of if WPA is being
+ * used. No other calls are made which can be used to
+ * determine if encryption will be used or not prior to
+ * association being expected. If encryption is not being
+ * used, drop_unencrypted is set to false, else true -- we
+ * can use this to determine if the CAP_PRIVACY_ON bit should
+ * be set.
+ */
+ struct ieee80211_security sec = {
+ .flags = SEC_ENABLED,
+ .enabled = param->value,
+ };
+ priv->ieee->drop_unencrypted = param->value;
+ /* We only change SEC_LEVEL for open mode. Others
+ * are set by ipw_wpa_set_encryption.
+ */
+ if (!param->value) {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_0;
+ } else {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_1;
+ }
+ if (priv->ieee->set_security)
+ priv->ieee->set_security(priv->ieee->dev, &sec);
+ break;
+ }
+
+ case IW_AUTH_80211_AUTH_ALG:
+ ret = ipw_wpa_set_auth_algs(priv, param->value);
+ break;
+
+ case IW_AUTH_WPA_ENABLED:
+ ret = ipw_wpa_enable(priv, param->value);
+ break;
+
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ ieee->ieee802_1x = param->value;
+ break;
+
+ //case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ ieee->privacy_invoked = param->value;
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+ return ret;
+}
+
+/* SIOCGIWAUTH */
+static int ipw_wx_get_auth(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ struct ieee80211_device *ieee = priv->ieee;
+ struct ieee80211_crypt_data *crypt;
+ struct iw_param *param = &wrqu->param;
+ int ret = 0;
+
+ switch (param->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_WPA_VERSION:
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ case IW_AUTH_KEY_MGMT:
+ /*
+ * wpa_supplicant will control these internally
+ */
+ ret = -EOPNOTSUPP;
+ break;
+
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ crypt = priv->ieee->crypt[priv->ieee->tx_keyidx];
+ if (!crypt || !crypt->ops->get_flags)
+ break;
+
+ param->value = (crypt->ops->get_flags(crypt->priv) &
+ IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0;
+
+ break;
+
+ case IW_AUTH_DROP_UNENCRYPTED:
+ param->value = ieee->drop_unencrypted;
+ break;
+
+ case IW_AUTH_80211_AUTH_ALG:
+ param->value = ieee->sec.auth_mode;
+ break;
+
+ case IW_AUTH_WPA_ENABLED:
+ param->value = ieee->wpa_enabled;
+ break;
+
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ param->value = ieee->ieee802_1x;
+ break;
+
+ case IW_AUTH_ROAMING_CONTROL:
+ case IW_AUTH_PRIVACY_INVOKED:
+ param->value = ieee->privacy_invoked;
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+/* SIOCSIWENCODEEXT */
+static int ipw_wx_set_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+
+ if (hwcrypto) {
+ if (ext->alg == IW_ENCODE_ALG_TKIP) {
+ /* IPW HW can't build TKIP MIC,
+ host decryption still needed */
+ if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
+ priv->ieee->host_mc_decrypt = 1;
+ else {
+ priv->ieee->host_encrypt = 0;
+ priv->ieee->host_encrypt_msdu = 1;
+ priv->ieee->host_decrypt = 1;
+ }
+ } else {
+ priv->ieee->host_encrypt = 0;
+ priv->ieee->host_encrypt_msdu = 0;
+ priv->ieee->host_decrypt = 0;
+ priv->ieee->host_mc_decrypt = 0;
+ }
+ }
+
+ return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra);
+}
+
+/* SIOCGIWENCODEEXT */
+static int ipw_wx_get_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra);
+}
+
+/* SIOCSIWMLME */
+static int ipw_wx_set_mlme(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ struct iw_mlme *mlme = (struct iw_mlme *)extra;
+ u16 reason;
+
+ reason = cpu_to_le16(mlme->reason_code);
+
+ switch (mlme->cmd) {
+ case IW_MLME_DEAUTH:
+ // silently ignore
+ break;
+
+ case IW_MLME_DISASSOC:
+ ipw_disassociate(priv);
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_IPW_QOS
+
+/* QoS */
+/*
+* get the modulation type of the current network or
+* the card current mode
+*/
+u8 ipw_qos_current_mode(struct ipw_priv * priv)
+{
+ u8 mode = 0;
+
+ if (priv->status & STATUS_ASSOCIATED) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->ieee->lock, flags);
+ mode = priv->assoc_network->mode;
+ spin_unlock_irqrestore(&priv->ieee->lock, flags);
+ } else {
+ mode = priv->ieee->mode;
+ }
+ IPW_DEBUG_QOS("QoS network/card mode %d \n", mode);
+ return mode;
+}
+
+/*
+* Handle management frame beacon and probe response
+*/
+static int ipw_qos_handle_probe_response(struct ipw_priv *priv,
+ int active_network,
+ struct ieee80211_network *network)
+{
+ u32 size = sizeof(struct ieee80211_qos_parameters);
+
+ if (network->capability & WLAN_CAPABILITY_IBSS)
+ network->qos_data.active = network->qos_data.supported;
+
+ if (network->flags & NETWORK_HAS_QOS_MASK) {
+ if (active_network &&
+ (network->flags & NETWORK_HAS_QOS_PARAMETERS))
+ network->qos_data.active = network->qos_data.supported;
+
+ if ((network->qos_data.active == 1) && (active_network == 1) &&
+ (network->flags & NETWORK_HAS_QOS_PARAMETERS) &&
+ (network->qos_data.old_param_count !=
+ network->qos_data.param_count)) {
+ network->qos_data.old_param_count =
+ network->qos_data.param_count;
+ schedule_work(&priv->qos_activate);
+ IPW_DEBUG_QOS("QoS parameters change call "
+ "qos_activate\n");
+ }
+ } else {
+ if ((priv->ieee->mode == IEEE_B) || (network->mode == IEEE_B))
+ memcpy(&network->qos_data.parameters,
+ &def_parameters_CCK, size);
+ else
+ memcpy(&network->qos_data.parameters,
+ &def_parameters_OFDM, size);
+
+ if ((network->qos_data.active == 1) && (active_network == 1)) {
+ IPW_DEBUG_QOS("QoS was disabled call qos_activate \n");
+ schedule_work(&priv->qos_activate);
+ }
+
+ network->qos_data.active = 0;
+ network->qos_data.supported = 0;
+ }
+ if ((priv->status & STATUS_ASSOCIATED) &&
+ (priv->ieee->iw_mode == IW_MODE_ADHOC) && (active_network == 0)) {
+ if (memcmp(network->bssid, priv->bssid, ETH_ALEN))
+ if ((network->capability & WLAN_CAPABILITY_IBSS) &&
+ !(network->flags & NETWORK_EMPTY_ESSID))
+ if ((network->ssid_len ==
+ priv->assoc_network->ssid_len) &&
+ !memcmp(network->ssid,
+ priv->assoc_network->ssid,
+ network->ssid_len)) {
+ queue_work(priv->workqueue,
+ &priv->merge_networks);
+ }
+ }
+
+ return 0;
+}
+
+/*
+* This function set up the firmware to support QoS. It sends
+* IPW_CMD_QOS_PARAMETERS and IPW_CMD_WME_INFO
+*/
+static int ipw_qos_activate(struct ipw_priv *priv,
+ struct ieee80211_qos_data *qos_network_data)
+{
+ int err;
+ struct ieee80211_qos_parameters qos_parameters[QOS_QOS_SETS];
+ struct ieee80211_qos_parameters *active_one = NULL;
+ u32 size = sizeof(struct ieee80211_qos_parameters);
+ u32 burst_duration;
+ int i;
+ u8 type;
+
+ type = ipw_qos_current_mode(priv);
+
+ active_one = &(qos_parameters[QOS_PARAM_SET_DEF_CCK]);
+ memcpy(active_one, priv->qos_data.def_qos_parm_CCK, size);
+ active_one = &(qos_parameters[QOS_PARAM_SET_DEF_OFDM]);
+ memcpy(active_one, priv->qos_data.def_qos_parm_OFDM, size);
+
+ if (qos_network_data == NULL) {
+ if (type == IEEE_B) {
+ IPW_DEBUG_QOS("QoS activate network mode %d\n", type);
+ active_one = &def_parameters_CCK;
+ } else
+ active_one = &def_parameters_OFDM;
+
+ memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size);
+ burst_duration = ipw_qos_get_burst_duration(priv);
+ for (i = 0; i < QOS_QUEUE_NUM; i++)
+ qos_parameters[QOS_PARAM_SET_ACTIVE].tx_op_limit[i] =
+ (u16) burst_duration;
+ } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+ if (type == IEEE_B) {
+ IPW_DEBUG_QOS("QoS activate IBSS nework mode %d\n",
+ type);
+ if (priv->qos_data.qos_enable == 0)
+ active_one = &def_parameters_CCK;
+ else
+ active_one = priv->qos_data.def_qos_parm_CCK;
+ } else {
+ if (priv->qos_data.qos_enable == 0)
+ active_one = &def_parameters_OFDM;
+ else
+ active_one = priv->qos_data.def_qos_parm_OFDM;
+ }
+ memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size);
+ } else {
+ unsigned long flags;
+ int active;
+
+ spin_lock_irqsave(&priv->ieee->lock, flags);
+ active_one = &(qos_network_data->parameters);
+ qos_network_data->old_param_count =
+ qos_network_data->param_count;
+ memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size);
+ active = qos_network_data->supported;
+ spin_unlock_irqrestore(&priv->ieee->lock, flags);
+
+ if (active == 0) {
+ burst_duration = ipw_qos_get_burst_duration(priv);
+ for (i = 0; i < QOS_QUEUE_NUM; i++)
+ qos_parameters[QOS_PARAM_SET_ACTIVE].
+ tx_op_limit[i] = (u16) burst_duration;
+ }
+ }
+
+ IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n");
+ err = ipw_send_qos_params_command(priv,
+ (struct ieee80211_qos_parameters *)
+ &(qos_parameters[0]));
+ if (err)
+ IPW_DEBUG_QOS("QoS IPW_CMD_QOS_PARAMETERS failed\n");
+
+ return err;
+}
+
+/*
+* send IPW_CMD_WME_INFO to the firmware
+*/
+static int ipw_qos_set_info_element(struct ipw_priv *priv)
+{
+ int ret = 0;
+ struct ieee80211_qos_information_element qos_info;
+
+ if (priv == NULL)
+ return -1;
+
+ qos_info.elementID = QOS_ELEMENT_ID;
+ qos_info.length = sizeof(struct ieee80211_qos_information_element) - 2;
+
+ qos_info.version = QOS_VERSION_1;
+ qos_info.ac_info = 0;
+
+ memcpy(qos_info.qui, qos_oui, QOS_OUI_LEN);
+ qos_info.qui_type = QOS_OUI_TYPE;
+ qos_info.qui_subtype = QOS_OUI_INFO_SUB_TYPE;
+
+ ret = ipw_send_qos_info_command(priv, &qos_info);
+ if (ret != 0) {
+ IPW_DEBUG_QOS("QoS error calling ipw_send_qos_info_command\n");
+ }
+ return ret;
+}
+
+/*
+* Set the QoS parameter with the association request structure
+*/
+static int ipw_qos_association(struct ipw_priv *priv,
+ struct ieee80211_network *network)
+{
+ int err = 0;
+ struct ieee80211_qos_data *qos_data = NULL;
+ struct ieee80211_qos_data ibss_data = {
+ .supported = 1,
+ .active = 1,
+ };
+
+ switch (priv->ieee->iw_mode) {
+ case IW_MODE_ADHOC:
+ if (!(network->capability & WLAN_CAPABILITY_IBSS))
+ BUG();
+
+ qos_data = &ibss_data;
+ break;
+
+ case IW_MODE_INFRA:
+ qos_data = &network->qos_data;
+ break;
+
+ default:
+ BUG();
+ break;
+ }
+
+ err = ipw_qos_activate(priv, qos_data);
+ if (err) {
+ priv->assoc_request.policy_support &= ~HC_QOS_SUPPORT_ASSOC;
+ return err;
+ }
+
+ if (priv->qos_data.qos_enable && qos_data->supported) {
+ IPW_DEBUG_QOS("QoS will be enabled for this association\n");
+ priv->assoc_request.policy_support |= HC_QOS_SUPPORT_ASSOC;
+ return ipw_qos_set_info_element(priv);
+ }
+
+ return 0;
+}
+
+/*
+* handling the beaconing responces. if we get different QoS setting
+* of the network from the the associated setting adjust the QoS
+* setting
+*/
+static int ipw_qos_association_resp(struct ipw_priv *priv,
+ struct ieee80211_network *network)
+{
+ int ret = 0;
+ unsigned long flags;
+ u32 size = sizeof(struct ieee80211_qos_parameters);
+ int set_qos_param = 0;
+
+ if ((priv == NULL) || (network == NULL) ||
+ (priv->assoc_network == NULL))
+ return ret;
+
+ if (!(priv->status & STATUS_ASSOCIATED))
+ return ret;
+
+ if ((priv->ieee->iw_mode != IW_MODE_INFRA))
+ return ret;
+
+ spin_lock_irqsave(&priv->ieee->lock, flags);
+ if (network->flags & NETWORK_HAS_QOS_PARAMETERS) {
+ memcpy(&priv->assoc_network->qos_data, &network->qos_data,
+ sizeof(struct ieee80211_qos_data));
+ priv->assoc_network->qos_data.active = 1;
+ if ((network->qos_data.old_param_count !=
+ network->qos_data.param_count)) {
+ set_qos_param = 1;
+ network->qos_data.old_param_count =
+ network->qos_data.param_count;
+ }
+
+ } else {
+ if ((network->mode == IEEE_B) || (priv->ieee->mode == IEEE_B))
+ memcpy(&priv->assoc_network->qos_data.parameters,
+ &def_parameters_CCK, size);
+ else
+ memcpy(&priv->assoc_network->qos_data.parameters,
+ &def_parameters_OFDM, size);
+ priv->assoc_network->qos_data.active = 0;
+ priv->assoc_network->qos_data.supported = 0;
+ set_qos_param = 1;
+ }
+
+ spin_unlock_irqrestore(&priv->ieee->lock, flags);
+
+ if (set_qos_param == 1)
+ schedule_work(&priv->qos_activate);
+
+ return ret;
+}
+
+static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv)
+{
+ u32 ret = 0;
+
+ if ((priv == NULL))
+ return 0;
+
+ if (!(priv->ieee->modulation & IEEE80211_OFDM_MODULATION))
+ ret = priv->qos_data.burst_duration_CCK;
+ else
+ ret = priv->qos_data.burst_duration_OFDM;
+
+ return ret;
+}
+
+/*
+* Initialize the setting of QoS global
+*/
+static void ipw_qos_init(struct ipw_priv *priv, int enable,
+ int burst_enable, u32 burst_duration_CCK,
+ u32 burst_duration_OFDM)
+{
+ priv->qos_data.qos_enable = enable;
+
+ if (priv->qos_data.qos_enable) {
+ priv->qos_data.def_qos_parm_CCK = &def_qos_parameters_CCK;
+ priv->qos_data.def_qos_parm_OFDM = &def_qos_parameters_OFDM;
+ IPW_DEBUG_QOS("QoS is enabled\n");
+ } else {
+ priv->qos_data.def_qos_parm_CCK = &def_parameters_CCK;
+ priv->qos_data.def_qos_parm_OFDM = &def_parameters_OFDM;
+ IPW_DEBUG_QOS("QoS is not enabled\n");
+ }
+
+ priv->qos_data.burst_enable = burst_enable;
+
+ if (burst_enable) {
+ priv->qos_data.burst_duration_CCK = burst_duration_CCK;
+ priv->qos_data.burst_duration_OFDM = burst_duration_OFDM;
+ } else {
+ priv->qos_data.burst_duration_CCK = 0;
+ priv->qos_data.burst_duration_OFDM = 0;
+ }
+}
+
+/*
+* map the packet priority to the right TX Queue
+*/
+static int ipw_get_tx_queue_number(struct ipw_priv *priv, u16 priority)
+{
+ if (priority > 7 || !priv->qos_data.qos_enable)
+ priority = 0;
+
+ return from_priority_to_tx_queue[priority] - 1;
+}
+
+/*
+* add QoS parameter to the TX command
+*/
+static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv,
+ u16 priority,
+ struct tfd_data *tfd, u8 unicast)
+{
+ int ret = 0;
+ int tx_queue_id = 0;
+ struct ieee80211_qos_data *qos_data = NULL;
+ int active, supported;
+ unsigned long flags;
+
+ if (!(priv->status & STATUS_ASSOCIATED))
+ return 0;
+
+ qos_data = &priv->assoc_network->qos_data;
+
+ spin_lock_irqsave(&priv->ieee->lock, flags);
+
+ if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+ if (unicast == 0)
+ qos_data->active = 0;
+ else
+ qos_data->active = qos_data->supported;
+ }
+
+ active = qos_data->active;
+ supported = qos_data->supported;
+
+ spin_unlock_irqrestore(&priv->ieee->lock, flags);
+
+ IPW_DEBUG_QOS("QoS %d network is QoS active %d supported %d "
+ "unicast %d\n",
+ priv->qos_data.qos_enable, active, supported, unicast);
+ if (active && priv->qos_data.qos_enable) {
+ ret = from_priority_to_tx_queue[priority];
+ tx_queue_id = ret - 1;
+ IPW_DEBUG_QOS("QoS packet priority is %d \n", priority);
+ if (priority <= 7) {
+ tfd->tx_flags_ext |= DCT_FLAG_EXT_QOS_ENABLED;
+ tfd->tfd.tfd_26.mchdr.qos_ctrl = priority;
+ tfd->tfd.tfd_26.mchdr.frame_ctl |=
+ IEEE80211_STYPE_QOS_DATA;
+
+ if (priv->qos_data.qos_no_ack_mask &
+ (1UL << tx_queue_id)) {
+ tfd->tx_flags &= ~DCT_FLAG_ACK_REQD;
+ tfd->tfd.tfd_26.mchdr.qos_ctrl |=
+ CTRL_QOS_NO_ACK;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/*
+* background support to run QoS activate functionality
+*/
+static void ipw_bg_qos_activate(void *data)
+{
+ struct ipw_priv *priv = data;
+
+ if (priv == NULL)
+ return;
+
+ down(&priv->sem);
+
+ if (priv->status & STATUS_ASSOCIATED)
+ ipw_qos_activate(priv, &(priv->assoc_network->qos_data));
+
+ up(&priv->sem);
+}
+
+static int ipw_handle_probe_response(struct net_device *dev,
+ struct ieee80211_probe_response *resp,
+ struct ieee80211_network *network)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ int active_network = ((priv->status & STATUS_ASSOCIATED) &&
+ (network == priv->assoc_network));
+
+ ipw_qos_handle_probe_response(priv, active_network, network);
+
+ return 0;
+}
+
+static int ipw_handle_beacon(struct net_device *dev,
+ struct ieee80211_beacon *resp,
+ struct ieee80211_network *network)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ int active_network = ((priv->status & STATUS_ASSOCIATED) &&
+ (network == priv->assoc_network));
+
+ ipw_qos_handle_probe_response(priv, active_network, network);
+
+ return 0;
+}
+
+static int ipw_handle_assoc_response(struct net_device *dev,
+ struct ieee80211_assoc_response *resp,
+ struct ieee80211_network *network)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ ipw_qos_association_resp(priv, network);
+ return 0;
+}
+
+static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters
+ *qos_param)
+{
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_QOS_PARAMETERS,
+ .len = (sizeof(struct ieee80211_qos_parameters) * 3)
+ };
+
+ memcpy(cmd.param, qos_param, sizeof(*qos_param) * 3);
+ return ipw_send_cmd(priv, &cmd);
+}
+
+static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element
+ *qos_param)
+{
+ struct host_cmd cmd = {
+ .cmd = IPW_CMD_WME_INFO,
+ .len = sizeof(*qos_param)
+ };
+
+ memcpy(cmd.param, qos_param, sizeof(*qos_param));
+ return ipw_send_cmd(priv, &cmd);
+}
+
+#endif /* CONFIG_IPW_QOS */
+
static int ipw_associate_network(struct ipw_priv *priv,
struct ieee80211_network *network,
struct ipw_supported_rates *rates, int roaming)
@@ -4616,7 +7042,7 @@ static int ipw_associate_network(struct ipw_priv *priv,
int err;
if (priv->config & CFG_FIXED_RATE)
- ipw_set_fixed_rate(priv, network);
+ ipw_set_fixed_rate(priv, network->mode);
if (!(priv->config & CFG_STATIC_ESSID)) {
priv->essid_len = min(network->ssid_len,
@@ -4631,14 +7057,22 @@ static int ipw_associate_network(struct ipw_priv *priv,
if ((priv->capability & CAP_PRIVACY_ON) &&
(priv->capability & CAP_SHARED_KEY)) {
priv->assoc_request.auth_type = AUTH_SHARED_KEY;
- priv->assoc_request.auth_key = priv->sec.active_key;
+ priv->assoc_request.auth_key = priv->ieee->sec.active_key;
+
+ if ((priv->capability & CAP_PRIVACY_ON) &&
+ (priv->ieee->sec.level == SEC_LEVEL_1) &&
+ !(priv->ieee->host_encrypt || priv->ieee->host_decrypt))
+ ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP);
} else {
priv->assoc_request.auth_type = AUTH_OPEN;
priv->assoc_request.auth_key = 0;
}
- if (priv->capability & CAP_PRIVACY_ON)
- ipw_send_wep_keys(priv);
+ if (priv->ieee->wpa_ie_len) {
+ priv->assoc_request.policy_support = 0x02; /* RSN active */
+ ipw_set_rsn_capa(priv, priv->ieee->wpa_ie,
+ priv->ieee->wpa_ie_len);
+ }
/*
* It is valid for our ieee device to support multiple modes, but
@@ -4652,20 +7086,41 @@ static int ipw_associate_network(struct ipw_priv *priv,
else if (network->mode & priv->ieee->mode & IEEE_B)
priv->assoc_request.ieee_mode = IPW_B_MODE;
+ priv->assoc_request.capability = network->capability;
+ if ((network->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ && !(priv->config & CFG_PREAMBLE_LONG)) {
+ priv->assoc_request.preamble_length = DCT_FLAG_SHORT_PREAMBLE;
+ } else {
+ priv->assoc_request.preamble_length = DCT_FLAG_LONG_PREAMBLE;
+
+ /* Clear the short preamble if we won't be supporting it */
+ priv->assoc_request.capability &=
+ ~WLAN_CAPABILITY_SHORT_PREAMBLE;
+ }
+
+ /* Clear capability bits that aren't used in Ad Hoc */
+ if (priv->ieee->iw_mode == IW_MODE_ADHOC)
+ priv->assoc_request.capability &=
+ ~WLAN_CAPABILITY_SHORT_SLOT_TIME;
+
IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, "
- "802.11%c [%d], enc=%s%s%s%c%c\n",
+ "802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n",
roaming ? "Rea" : "A",
escape_essid(priv->essid, priv->essid_len),
network->channel,
ipw_modes[priv->assoc_request.ieee_mode],
rates->num_rates,
+ (priv->assoc_request.preamble_length ==
+ DCT_FLAG_LONG_PREAMBLE) ? "long" : "short",
+ network->capability &
+ WLAN_CAPABILITY_SHORT_PREAMBLE ? "short" : "long",
priv->capability & CAP_PRIVACY_ON ? "on " : "off",
priv->capability & CAP_PRIVACY_ON ?
(priv->capability & CAP_SHARED_KEY ? "(shared)" :
"(open)") : "",
priv->capability & CAP_PRIVACY_ON ? " key=" : "",
priv->capability & CAP_PRIVACY_ON ?
- '1' + priv->sec.active_key : '.',
+ '1' + priv->ieee->sec.active_key : '.',
priv->capability & CAP_PRIVACY_ON ? '.' : ' ');
priv->assoc_request.beacon_interval = network->beacon_interval;
@@ -4683,17 +7138,16 @@ static int ipw_associate_network(struct ipw_priv *priv,
priv->assoc_request.assoc_tsf_lsw = network->time_stamp[0];
}
- memcpy(&priv->assoc_request.bssid, network->bssid, ETH_ALEN);
+ memcpy(priv->assoc_request.bssid, network->bssid, ETH_ALEN);
if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
memset(&priv->assoc_request.dest, 0xFF, ETH_ALEN);
priv->assoc_request.atim_window = network->atim_window;
} else {
- memcpy(&priv->assoc_request.dest, network->bssid, ETH_ALEN);
+ memcpy(priv->assoc_request.dest, network->bssid, ETH_ALEN);
priv->assoc_request.atim_window = 0;
}
- priv->assoc_request.capability = network->capability;
priv->assoc_request.listen_interval = network->listen_interval;
err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
@@ -4710,6 +7164,12 @@ static int ipw_associate_network(struct ipw_priv *priv,
priv->sys_config.dot11g_auto_detection = 1;
else
priv->sys_config.dot11g_auto_detection = 0;
+
+ if (priv->ieee->iw_mode == IW_MODE_ADHOC)
+ priv->sys_config.answer_broadcast_ssid_probe = 1;
+ else
+ priv->sys_config.answer_broadcast_ssid_probe = 0;
+
err = ipw_send_system_config(priv, &priv->sys_config);
if (err) {
IPW_DEBUG_HC("Attempt to send sys config command failed.\n");
@@ -4717,7 +7177,7 @@ static int ipw_associate_network(struct ipw_priv *priv,
}
IPW_DEBUG_ASSOC("Association sensitivity: %d\n", network->stats.rssi);
- err = ipw_set_sensitivity(priv, network->stats.rssi);
+ err = ipw_set_sensitivity(priv, network->stats.rssi + IPW_RSSI_TO_DBM);
if (err) {
IPW_DEBUG_HC("Attempt to send associate command failed.\n");
return err;
@@ -4735,6 +7195,10 @@ static int ipw_associate_network(struct ipw_priv *priv,
priv->assoc_network = network;
+#ifdef CONFIG_IPW_QOS
+ ipw_qos_association(priv, network);
+#endif
+
err = ipw_send_associate(priv, &priv->assoc_request);
if (err) {
IPW_DEBUG_HC("Attempt to send associate command failed.\n");
@@ -4782,12 +7246,15 @@ static void ipw_roam(void *data)
if (priv->status & STATUS_ASSOCIATED) {
/* First pass through ROAM process -- look for a better
* network */
+ unsigned long flags;
u8 rssi = priv->assoc_network->stats.rssi;
priv->assoc_network->stats.rssi = -128;
+ spin_lock_irqsave(&priv->ieee->lock, flags);
list_for_each_entry(network, &priv->ieee->network_list, list) {
if (network != priv->assoc_network)
ipw_best_network(priv, &match, network, 1);
}
+ spin_unlock_irqrestore(&priv->ieee->lock, flags);
priv->assoc_network->stats.rssi = rssi;
if (match.network == priv->assoc_network) {
@@ -4810,7 +7277,15 @@ static void ipw_roam(void *data)
priv->status &= ~STATUS_ROAMING;
}
-static void ipw_associate(void *data)
+static void ipw_bg_roam(void *data)
+{
+ struct ipw_priv *priv = data;
+ down(&priv->sem);
+ ipw_roam(data);
+ up(&priv->sem);
+}
+
+static int ipw_associate(void *data)
{
struct ipw_priv *priv = data;
@@ -4820,14 +7295,41 @@ static void ipw_associate(void *data)
};
struct ipw_supported_rates *rates;
struct list_head *element;
+ unsigned long flags;
+
+ if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+ IPW_DEBUG_ASSOC("Not attempting association (monitor mode)\n");
+ return 0;
+ }
+
+ if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
+ IPW_DEBUG_ASSOC("Not attempting association (already in "
+ "progress)\n");
+ return 0;
+ }
+
+ if (priv->status & STATUS_DISASSOCIATING) {
+ IPW_DEBUG_ASSOC("Not attempting association (in "
+ "disassociating)\n ");
+ queue_work(priv->workqueue, &priv->associate);
+ return 0;
+ }
+
+ if (!ipw_is_init(priv) || (priv->status & STATUS_SCANNING)) {
+ IPW_DEBUG_ASSOC("Not attempting association (scanning or not "
+ "initialized)\n");
+ return 0;
+ }
if (!(priv->config & CFG_ASSOCIATE) &&
!(priv->config & (CFG_STATIC_ESSID |
CFG_STATIC_CHANNEL | CFG_STATIC_BSSID))) {
IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n");
- return;
+ return 0;
}
+ /* Protect our use of the network_list */
+ spin_lock_irqsave(&priv->ieee->lock, flags);
list_for_each_entry(network, &priv->ieee->network_list, list)
ipw_best_network(priv, &match, network, 0);
@@ -4838,6 +7340,7 @@ static void ipw_associate(void *data)
priv->ieee->iw_mode == IW_MODE_ADHOC &&
priv->config & CFG_ADHOC_CREATE &&
priv->config & CFG_STATIC_ESSID &&
+ priv->config & CFG_STATIC_CHANNEL &&
!list_empty(&priv->ieee->network_free_list)) {
element = priv->ieee->network_free_list.next;
network = list_entry(element, struct ieee80211_network, list);
@@ -4846,25 +7349,83 @@ static void ipw_associate(void *data)
list_del(element);
list_add_tail(&network->list, &priv->ieee->network_list);
}
+ spin_unlock_irqrestore(&priv->ieee->lock, flags);
/* If we reached the end of the list, then we don't have any valid
* matching APs */
if (!network) {
ipw_debug_config(priv);
- queue_delayed_work(priv->workqueue, &priv->request_scan,
- SCAN_INTERVAL);
+ if (!(priv->status & STATUS_SCANNING)) {
+ if (!(priv->config & CFG_SPEED_SCAN))
+ queue_delayed_work(priv->workqueue,
+ &priv->request_scan,
+ SCAN_INTERVAL);
+ else
+ queue_work(priv->workqueue,
+ &priv->request_scan);
+ }
- return;
+ return 0;
}
ipw_associate_network(priv, network, rates, 0);
+
+ return 1;
}
-static inline void ipw_handle_data_packet(struct ipw_priv *priv,
- struct ipw_rx_mem_buffer *rxb,
- struct ieee80211_rx_stats *stats)
+static void ipw_bg_associate(void *data)
{
+ struct ipw_priv *priv = data;
+ down(&priv->sem);
+ ipw_associate(data);
+ up(&priv->sem);
+}
+
+static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv,
+ struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = le16_to_cpu(hdr->frame_ctl);
+ if (!(fc & IEEE80211_FCTL_PROTECTED))
+ return;
+
+ fc &= ~IEEE80211_FCTL_PROTECTED;
+ hdr->frame_ctl = cpu_to_le16(fc);
+ switch (priv->ieee->sec.level) {
+ case SEC_LEVEL_3:
+ /* Remove CCMP HDR */
+ memmove(skb->data + IEEE80211_3ADDR_LEN,
+ skb->data + IEEE80211_3ADDR_LEN + 8,
+ skb->len - IEEE80211_3ADDR_LEN - 8);
+ skb_trim(skb, skb->len - 16); /* CCMP_HDR_LEN + CCMP_MIC_LEN */
+ break;
+ case SEC_LEVEL_2:
+ break;
+ case SEC_LEVEL_1:
+ /* Remove IV */
+ memmove(skb->data + IEEE80211_3ADDR_LEN,
+ skb->data + IEEE80211_3ADDR_LEN + 4,
+ skb->len - IEEE80211_3ADDR_LEN - 4);
+ skb_trim(skb, skb->len - 8); /* IV + ICV */
+ break;
+ case SEC_LEVEL_0:
+ break;
+ default:
+ printk(KERN_ERR "Unknow security level %d\n",
+ priv->ieee->sec.level);
+ break;
+ }
+}
+
+static void ipw_handle_data_packet(struct ipw_priv *priv,
+ struct ipw_rx_mem_buffer *rxb,
+ struct ieee80211_rx_stats *stats)
+{
+ struct ieee80211_hdr_4addr *hdr;
struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
/* We received data from the HW, so stop the watchdog */
@@ -4872,7 +7433,7 @@ static inline void ipw_handle_data_packet(struct ipw_priv *priv,
/* We only process data packets if the
* interface is open */
- if (unlikely((pkt->u.frame.length + IPW_RX_FRAME_SIZE) >
+ if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) >
skb_tailroom(rxb->skb))) {
priv->ieee->stats.rx_errors++;
priv->wstats.discard.misc++;
@@ -4889,14 +7450,351 @@ static inline void ipw_handle_data_packet(struct ipw_priv *priv,
skb_reserve(rxb->skb, offsetof(struct ipw_rx_packet, u.frame.data));
/* Set the size of the skb to the size of the frame */
- skb_put(rxb->skb, pkt->u.frame.length);
+ skb_put(rxb->skb, le16_to_cpu(pkt->u.frame.length));
IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
+ /* HW decrypt will not clear the WEP bit, MIC, PN, etc. */
+ hdr = (struct ieee80211_hdr_4addr *)rxb->skb->data;
+ if (priv->ieee->iw_mode != IW_MODE_MONITOR &&
+ ((is_multicast_ether_addr(hdr->addr1) ||
+ is_broadcast_ether_addr(hdr->addr1)) ?
+ !priv->ieee->host_mc_decrypt : !priv->ieee->host_decrypt))
+ ipw_rebuild_decrypted_skb(priv, rxb->skb);
+
if (!ieee80211_rx(priv->ieee, rxb->skb, stats))
priv->ieee->stats.rx_errors++;
- else /* ieee80211_rx succeeded, so it now owns the SKB */
+ else { /* ieee80211_rx succeeded, so it now owns the SKB */
rxb->skb = NULL;
+ __ipw_led_activity_on(priv);
+ }
+}
+
+#ifdef CONFIG_IEEE80211_RADIOTAP
+static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
+ struct ipw_rx_mem_buffer *rxb,
+ struct ieee80211_rx_stats *stats)
+{
+ struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
+ struct ipw_rx_frame *frame = &pkt->u.frame;
+
+ /* initial pull of some data */
+ u16 received_channel = frame->received_channel;
+ u8 antennaAndPhy = frame->antennaAndPhy;
+ s8 antsignal = frame->rssi_dbm - IPW_RSSI_TO_DBM; /* call it signed anyhow */
+ u16 pktrate = frame->rate;
+
+ /* Magic struct that slots into the radiotap header -- no reason
+ * to build this manually element by element, we can write it much
+ * more efficiently than we can parse it. ORDER MATTERS HERE */
+ struct ipw_rt_hdr {
+ struct ieee80211_radiotap_header rt_hdr;
+ u8 rt_flags; /* radiotap packet flags */
+ u8 rt_rate; /* rate in 500kb/s */
+ u16 rt_channel; /* channel in mhz */
+ u16 rt_chbitmask; /* channel bitfield */
+ s8 rt_dbmsignal; /* signal in dbM, kluged to signed */
+ u8 rt_antenna; /* antenna number */
+ } *ipw_rt;
+
+ short len = le16_to_cpu(pkt->u.frame.length);
+
+ /* We received data from the HW, so stop the watchdog */
+ priv->net_dev->trans_start = jiffies;
+
+ /* We only process data packets if the
+ * interface is open */
+ if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) >
+ skb_tailroom(rxb->skb))) {
+ priv->ieee->stats.rx_errors++;
+ priv->wstats.discard.misc++;
+ IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
+ return;
+ } else if (unlikely(!netif_running(priv->net_dev))) {
+ priv->ieee->stats.rx_dropped++;
+ priv->wstats.discard.misc++;
+ IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
+ return;
+ }
+
+ /* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use
+ * that now */
+ if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) {
+ /* FIXME: Should alloc bigger skb instead */
+ priv->ieee->stats.rx_dropped++;
+ priv->wstats.discard.misc++;
+ IPW_DEBUG_DROP("Dropping too large packet in monitor\n");
+ return;
+ }
+
+ /* copy the frame itself */
+ memmove(rxb->skb->data + sizeof(struct ipw_rt_hdr),
+ rxb->skb->data + IPW_RX_FRAME_SIZE, len);
+
+ /* Zero the radiotap static buffer ... We only need to zero the bytes NOT
+ * part of our real header, saves a little time.
+ *
+ * No longer necessary since we fill in all our data. Purge before merging
+ * patch officially.
+ * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0,
+ * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr));
+ */
+
+ ipw_rt = (struct ipw_rt_hdr *)rxb->skb->data;
+
+ ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+ ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
+ ipw_rt->rt_hdr.it_len = sizeof(struct ipw_rt_hdr); /* total header+data */
+
+ /* Big bitfield of all the fields we provide in radiotap */
+ ipw_rt->rt_hdr.it_present =
+ ((1 << IEEE80211_RADIOTAP_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_RATE) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL) |
+ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+ (1 << IEEE80211_RADIOTAP_ANTENNA));
+
+ /* Zero the flags, we'll add to them as we go */
+ ipw_rt->rt_flags = 0;
+
+ /* Convert signal to DBM */
+ ipw_rt->rt_dbmsignal = antsignal;
+
+ /* Convert the channel data and set the flags */
+ ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel));
+ if (received_channel > 14) { /* 802.11a */
+ ipw_rt->rt_chbitmask =
+ cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
+ } else if (antennaAndPhy & 32) { /* 802.11b */
+ ipw_rt->rt_chbitmask =
+ cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
+ } else { /* 802.11g */
+ ipw_rt->rt_chbitmask =
+ (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ);
+ }
+
+ /* set the rate in multiples of 500k/s */
+ switch (pktrate) {
+ case IPW_TX_RATE_1MB:
+ ipw_rt->rt_rate = 2;
+ break;
+ case IPW_TX_RATE_2MB:
+ ipw_rt->rt_rate = 4;
+ break;
+ case IPW_TX_RATE_5MB:
+ ipw_rt->rt_rate = 10;
+ break;
+ case IPW_TX_RATE_6MB:
+ ipw_rt->rt_rate = 12;
+ break;
+ case IPW_TX_RATE_9MB:
+ ipw_rt->rt_rate = 18;
+ break;
+ case IPW_TX_RATE_11MB:
+ ipw_rt->rt_rate = 22;
+ break;
+ case IPW_TX_RATE_12MB:
+ ipw_rt->rt_rate = 24;
+ break;
+ case IPW_TX_RATE_18MB:
+ ipw_rt->rt_rate = 36;
+ break;
+ case IPW_TX_RATE_24MB:
+ ipw_rt->rt_rate = 48;
+ break;
+ case IPW_TX_RATE_36MB:
+ ipw_rt->rt_rate = 72;
+ break;
+ case IPW_TX_RATE_48MB:
+ ipw_rt->rt_rate = 96;
+ break;
+ case IPW_TX_RATE_54MB:
+ ipw_rt->rt_rate = 108;
+ break;
+ default:
+ ipw_rt->rt_rate = 0;
+ break;
+ }
+
+ /* antenna number */
+ ipw_rt->rt_antenna = (antennaAndPhy & 3); /* Is this right? */
+
+ /* set the preamble flag if we have it */
+ if ((antennaAndPhy & 64))
+ ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+ /* Set the size of the skb to the size of the frame */
+ skb_put(rxb->skb, len + sizeof(struct ipw_rt_hdr));
+
+ IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
+
+ if (!ieee80211_rx(priv->ieee, rxb->skb, stats))
+ priv->ieee->stats.rx_errors++;
+ else { /* ieee80211_rx succeeded, so it now owns the SKB */
+ rxb->skb = NULL;
+ /* no LED during capture */
+ }
+}
+#endif
+
+static inline int is_network_packet(struct ipw_priv *priv,
+ struct ieee80211_hdr_4addr *header)
+{
+ /* Filter incoming packets to determine if they are targetted toward
+ * this network, discarding packets coming from ourselves */
+ switch (priv->ieee->iw_mode) {
+ case IW_MODE_ADHOC: /* Header: Dest. | Source | BSSID */
+ /* packets from our adapter are dropped (echo) */
+ if (!memcmp(header->addr2, priv->net_dev->dev_addr, ETH_ALEN))
+ return 0;
+
+ /* {broad,multi}cast packets to our BSSID go through */
+ if (is_multicast_ether_addr(header->addr1) ||
+ is_broadcast_ether_addr(header->addr1))
+ return !memcmp(header->addr3, priv->bssid, ETH_ALEN);
+
+ /* packets to our adapter go through */
+ return !memcmp(header->addr1, priv->net_dev->dev_addr,
+ ETH_ALEN);
+
+ case IW_MODE_INFRA: /* Header: Dest. | BSSID | Source */
+ /* packets from our adapter are dropped (echo) */
+ if (!memcmp(header->addr3, priv->net_dev->dev_addr, ETH_ALEN))
+ return 0;
+
+ /* {broad,multi}cast packets to our BSS go through */
+ if (is_multicast_ether_addr(header->addr1) ||
+ is_broadcast_ether_addr(header->addr1))
+ return !memcmp(header->addr2, priv->bssid, ETH_ALEN);
+
+ /* packets to our adapter go through */
+ return !memcmp(header->addr1, priv->net_dev->dev_addr,
+ ETH_ALEN);
+ }
+
+ return 1;
+}
+
+#define IPW_PACKET_RETRY_TIME HZ
+
+static inline int is_duplicate_packet(struct ipw_priv *priv,
+ struct ieee80211_hdr_4addr *header)
+{
+ u16 sc = le16_to_cpu(header->seq_ctl);
+ u16 seq = WLAN_GET_SEQ_SEQ(sc);
+ u16 frag = WLAN_GET_SEQ_FRAG(sc);
+ u16 *last_seq, *last_frag;
+ unsigned long *last_time;
+
+ switch (priv->ieee->iw_mode) {
+ case IW_MODE_ADHOC:
+ {
+ struct list_head *p;
+ struct ipw_ibss_seq *entry = NULL;
+ u8 *mac = header->addr2;
+ int index = mac[5] % IPW_IBSS_MAC_HASH_SIZE;
+
+ __list_for_each(p, &priv->ibss_mac_hash[index]) {
+ entry =
+ list_entry(p, struct ipw_ibss_seq, list);
+ if (!memcmp(entry->mac, mac, ETH_ALEN))
+ break;
+ }
+ if (p == &priv->ibss_mac_hash[index]) {
+ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry) {
+ IPW_ERROR
+ ("Cannot malloc new mac entry\n");
+ return 0;
+ }
+ memcpy(entry->mac, mac, ETH_ALEN);
+ entry->seq_num = seq;
+ entry->frag_num = frag;
+ entry->packet_time = jiffies;
+ list_add(&entry->list,
+ &priv->ibss_mac_hash[index]);
+ return 0;
+ }
+ last_seq = &entry->seq_num;
+ last_frag = &entry->frag_num;
+ last_time = &entry->packet_time;
+ break;
+ }
+ case IW_MODE_INFRA:
+ last_seq = &priv->last_seq_num;
+ last_frag = &priv->last_frag_num;
+ last_time = &priv->last_packet_time;
+ break;
+ default:
+ return 0;
+ }
+ if ((*last_seq == seq) &&
+ time_after(*last_time + IPW_PACKET_RETRY_TIME, jiffies)) {
+ if (*last_frag == frag)
+ goto drop;
+ if (*last_frag + 1 != frag)
+ /* out-of-order fragment */
+ goto drop;
+ } else
+ *last_seq = seq;
+
+ *last_frag = frag;
+ *last_time = jiffies;
+ return 0;
+
+ drop:
+ /* Comment this line now since we observed the card receives
+ * duplicate packets but the FCTL_RETRY bit is not set in the
+ * IBSS mode with fragmentation enabled.
+ BUG_ON(!(le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_RETRY)); */
+ return 1;
+}
+
+static void ipw_handle_mgmt_packet(struct ipw_priv *priv,
+ struct ipw_rx_mem_buffer *rxb,
+ struct ieee80211_rx_stats *stats)
+{
+ struct sk_buff *skb = rxb->skb;
+ struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)skb->data;
+ struct ieee80211_hdr_4addr *header = (struct ieee80211_hdr_4addr *)
+ (skb->data + IPW_RX_FRAME_SIZE);
+
+ ieee80211_rx_mgt(priv->ieee, header, stats);
+
+ if (priv->ieee->iw_mode == IW_MODE_ADHOC &&
+ ((WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) ==
+ IEEE80211_STYPE_PROBE_RESP) ||
+ (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) ==
+ IEEE80211_STYPE_BEACON))) {
+ if (!memcmp(header->addr3, priv->bssid, ETH_ALEN))
+ ipw_add_station(priv, header->addr2);
+ }
+
+ if (priv->config & CFG_NET_STATS) {
+ IPW_DEBUG_HC("sending stat packet\n");
+
+ /* Set the size of the skb to the size of the full
+ * ipw header and 802.11 frame */
+ skb_put(skb, le16_to_cpu(pkt->u.frame.length) +
+ IPW_RX_FRAME_SIZE);
+
+ /* Advance past the ipw packet header to the 802.11 frame */
+ skb_pull(skb, IPW_RX_FRAME_SIZE);
+
+ /* Push the ieee80211_rx_stats before the 802.11 frame */
+ memcpy(skb_push(skb, sizeof(*stats)), stats, sizeof(*stats));
+
+ skb->dev = priv->ieee->dev;
+
+ /* Point raw at the ieee80211_stats */
+ skb->mac.raw = skb->data;
+
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = __constant_htons(ETH_P_80211_STATS);
+ memset(skb->cb, 0, sizeof(rxb->skb->cb));
+ netif_rx(skb);
+ rxb->skb = NULL;
+ }
}
/*
@@ -4912,8 +7810,8 @@ static void ipw_rx(struct ipw_priv *priv)
u32 r, w, i;
u8 network_packet;
- r = ipw_read32(priv, CX2_RX_READ_INDEX);
- w = ipw_read32(priv, CX2_RX_WRITE_INDEX);
+ r = ipw_read32(priv, IPW_RX_READ_INDEX);
+ w = ipw_read32(priv, IPW_RX_WRITE_INDEX);
i = (priv->rxq->processed + 1) % RX_QUEUE_SIZE;
while (i != r) {
@@ -4927,7 +7825,7 @@ static void ipw_rx(struct ipw_priv *priv)
priv->rxq->queue[i] = NULL;
pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
- CX2_RX_BUF_SIZE,
+ IPW_RX_BUF_SIZE,
PCI_DMA_FROMDEVICE);
pkt = (struct ipw_rx_packet *)rxb->skb->data;
@@ -4938,9 +7836,13 @@ static void ipw_rx(struct ipw_priv *priv)
switch (pkt->header.message_type) {
case RX_FRAME_TYPE: /* 802.11 frame */ {
struct ieee80211_rx_stats stats = {
- .rssi = pkt->u.frame.rssi_dbm -
+ .rssi =
+ le16_to_cpu(pkt->u.frame.rssi_dbm) -
IPW_RSSI_TO_DBM,
- .signal = pkt->u.frame.signal,
+ .signal =
+ le16_to_cpu(pkt->u.frame.signal),
+ .noise =
+ le16_to_cpu(pkt->u.frame.noise),
.rate = pkt->u.frame.rate,
.mac_time = jiffies,
.received_channel =
@@ -4950,22 +7852,30 @@ static void ipw_rx(struct ipw_priv *priv)
control & (1 << 0)) ?
IEEE80211_24GHZ_BAND :
IEEE80211_52GHZ_BAND,
- .len = pkt->u.frame.length,
+ .len = le16_to_cpu(pkt->u.frame.length),
};
if (stats.rssi != 0)
stats.mask |= IEEE80211_STATMASK_RSSI;
if (stats.signal != 0)
stats.mask |= IEEE80211_STATMASK_SIGNAL;
+ if (stats.noise != 0)
+ stats.mask |= IEEE80211_STATMASK_NOISE;
if (stats.rate != 0)
stats.mask |= IEEE80211_STATMASK_RATE;
priv->rx_packets++;
-#ifdef CONFIG_IPW_PROMISC
+#ifdef CONFIG_IPW2200_MONITOR
if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+#ifdef CONFIG_IEEE80211_RADIOTAP
+ ipw_handle_data_packet_monitor(priv,
+ rxb,
+ &stats);
+#else
ipw_handle_data_packet(priv, rxb,
&stats);
+#endif
break;
}
#endif
@@ -4979,35 +7889,9 @@ static void ipw_rx(struct ipw_priv *priv)
* correctly -- we should probably use the
* frame control of the packet and disregard
* the current iw_mode */
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC:
- network_packet =
- !memcmp(header->addr1,
- priv->net_dev->dev_addr,
- ETH_ALEN) ||
- !memcmp(header->addr3,
- priv->bssid, ETH_ALEN) ||
- is_broadcast_ether_addr(header->
- addr1)
- || is_multicast_ether_addr(header->
- addr1);
- break;
-
- case IW_MODE_INFRA:
- default:
- network_packet =
- !memcmp(header->addr3,
- priv->bssid, ETH_ALEN) ||
- !memcmp(header->addr1,
- priv->net_dev->dev_addr,
- ETH_ALEN) ||
- is_broadcast_ether_addr(header->
- addr1)
- || is_multicast_ether_addr(header->
- addr1);
- break;
- }
+ network_packet =
+ is_network_packet(priv, header);
if (network_packet && priv->assoc_network) {
priv->assoc_network->stats.rssi =
stats.rssi;
@@ -5017,9 +7901,10 @@ static void ipw_rx(struct ipw_priv *priv)
}
IPW_DEBUG_RX("Frame: len=%u\n",
- pkt->u.frame.length);
+ le16_to_cpu(pkt->u.frame.length));
- if (pkt->u.frame.length < frame_hdr_len(header)) {
+ if (le16_to_cpu(pkt->u.frame.length) <
+ frame_hdr_len(header)) {
IPW_DEBUG_DROP
("Received packet is too small. "
"Dropping.\n");
@@ -5028,34 +7913,22 @@ static void ipw_rx(struct ipw_priv *priv)
break;
}
- switch (WLAN_FC_GET_TYPE(header->frame_ctl)) {
+ switch (WLAN_FC_GET_TYPE
+ (le16_to_cpu(header->frame_ctl))) {
+
case IEEE80211_FTYPE_MGMT:
- ieee80211_rx_mgt(priv->ieee, header,
- &stats);
- if (priv->ieee->iw_mode == IW_MODE_ADHOC
- &&
- ((WLAN_FC_GET_STYPE
- (header->frame_ctl) ==
- IEEE80211_STYPE_PROBE_RESP)
- ||
- (WLAN_FC_GET_STYPE
- (header->frame_ctl) ==
- IEEE80211_STYPE_BEACON))
- && !memcmp(header->addr3,
- priv->bssid, ETH_ALEN))
- ipw_add_station(priv,
- header->addr2);
+ ipw_handle_mgmt_packet(priv, rxb,
+ &stats);
break;
case IEEE80211_FTYPE_CTL:
break;
case IEEE80211_FTYPE_DATA:
- if (network_packet)
- ipw_handle_data_packet(priv,
- rxb,
- &stats);
- else
+ if (unlikely(!network_packet ||
+ is_duplicate_packet(priv,
+ header)))
+ {
IPW_DEBUG_DROP("Dropping: "
MAC_FMT ", "
MAC_FMT ", "
@@ -5066,6 +7939,12 @@ static void ipw_rx(struct ipw_priv *priv)
addr2),
MAC_ARG(header->
addr3));
+ break;
+ }
+
+ ipw_handle_data_packet(priv, rxb,
+ &stats);
+
break;
}
break;
@@ -5096,7 +7975,7 @@ static void ipw_rx(struct ipw_priv *priv)
}
pci_unmap_single(priv->pci_dev, rxb->dma_addr,
- CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
list_add_tail(&rxb->list, &priv->rxq->rx_used);
i = (i + 1) % RX_QUEUE_SIZE;
@@ -5108,128 +7987,129 @@ static void ipw_rx(struct ipw_priv *priv)
ipw_rx_queue_restock(priv);
}
-static void ipw_abort_scan(struct ipw_priv *priv)
+#define DEFAULT_RTS_THRESHOLD 2304U
+#define MIN_RTS_THRESHOLD 1U
+#define MAX_RTS_THRESHOLD 2304U
+#define DEFAULT_BEACON_INTERVAL 100U
+#define DEFAULT_SHORT_RETRY_LIMIT 7U
+#define DEFAULT_LONG_RETRY_LIMIT 4U
+
+static int ipw_sw_reset(struct ipw_priv *priv, int init)
{
- int err;
+ int band, modulation;
+ int old_mode = priv->ieee->iw_mode;
- if (priv->status & STATUS_SCAN_ABORTING) {
- IPW_DEBUG_HC("Ignoring concurrent scan abort request.\n");
- return;
- }
- priv->status |= STATUS_SCAN_ABORTING;
+ /* Initialize module parameter values here */
+ priv->config = 0;
- err = ipw_send_scan_abort(priv);
- if (err)
- IPW_DEBUG_HC("Request to abort scan failed.\n");
-}
+ /* We default to disabling the LED code as right now it causes
+ * too many systems to lock up... */
+ if (!led)
+ priv->config |= CFG_NO_LED;
-static int ipw_request_scan(struct ipw_priv *priv)
-{
- struct ipw_scan_request_ext scan;
- int channel_index = 0;
- int i, err, scan_type;
+ if (associate)
+ priv->config |= CFG_ASSOCIATE;
+ else
+ IPW_DEBUG_INFO("Auto associate disabled.\n");
- if (priv->status & STATUS_EXIT_PENDING) {
- IPW_DEBUG_SCAN("Aborting scan due to device shutdown\n");
- priv->status |= STATUS_SCAN_PENDING;
- return 0;
- }
+ if (auto_create)
+ priv->config |= CFG_ADHOC_CREATE;
+ else
+ IPW_DEBUG_INFO("Auto adhoc creation disabled.\n");
- if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG_HC("Concurrent scan requested. Aborting first.\n");
- priv->status |= STATUS_SCAN_PENDING;
- ipw_abort_scan(priv);
- return 0;
+ if (disable) {
+ priv->status |= STATUS_RF_KILL_SW;
+ IPW_DEBUG_INFO("Radio disabled.\n");
}
- if (priv->status & STATUS_SCAN_ABORTING) {
- IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n");
- priv->status |= STATUS_SCAN_PENDING;
- return 0;
+ if (channel != 0) {
+ priv->config |= CFG_STATIC_CHANNEL;
+ priv->channel = channel;
+ IPW_DEBUG_INFO("Bind to static channel %d\n", channel);
+ /* TODO: Validate that provided channel is in range */
}
+#ifdef CONFIG_IPW_QOS
+ ipw_qos_init(priv, qos_enable, qos_burst_enable,
+ burst_duration_CCK, burst_duration_OFDM);
+#endif /* CONFIG_IPW_QOS */
- if (priv->status & STATUS_RF_KILL_MASK) {
- IPW_DEBUG_HC("Aborting scan due to RF Kill activation\n");
- priv->status |= STATUS_SCAN_PENDING;
- return 0;
+ switch (mode) {
+ case 1:
+ priv->ieee->iw_mode = IW_MODE_ADHOC;
+ priv->net_dev->type = ARPHRD_ETHER;
+
+ break;
+#ifdef CONFIG_IPW2200_MONITOR
+ case 2:
+ priv->ieee->iw_mode = IW_MODE_MONITOR;
+#ifdef CONFIG_IEEE80211_RADIOTAP
+ priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
+#else
+ priv->net_dev->type = ARPHRD_IEEE80211;
+#endif
+ break;
+#endif
+ default:
+ case 0:
+ priv->net_dev->type = ARPHRD_ETHER;
+ priv->ieee->iw_mode = IW_MODE_INFRA;
+ break;
}
- memset(&scan, 0, sizeof(scan));
+ if (hwcrypto) {
+ priv->ieee->host_encrypt = 0;
+ priv->ieee->host_encrypt_msdu = 0;
+ priv->ieee->host_decrypt = 0;
+ priv->ieee->host_mc_decrypt = 0;
+ }
+ IPW_DEBUG_INFO("Hardware crypto [%s]\n", hwcrypto ? "on" : "off");
- scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = 20;
- scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = 20;
- scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = 20;
-
- scan.full_scan_index = ieee80211_get_scans(priv->ieee);
- /* If we are roaming, then make this a directed scan for the current
- * network. Otherwise, ensure that every other scan is a fast
- * channel hop scan */
- if ((priv->status & STATUS_ROAMING)
- || (!(priv->status & STATUS_ASSOCIATED)
- && (priv->config & CFG_STATIC_ESSID)
- && (scan.full_scan_index % 2))) {
- err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
- if (err) {
- IPW_DEBUG_HC("Attempt to send SSID command failed.\n");
- return err;
- }
+ /* IPW2200/2915 is abled to do hardware fragmentation. */
+ priv->ieee->host_open_frag = 0;
- scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
+ if ((priv->pci_dev->device == 0x4223) ||
+ (priv->pci_dev->device == 0x4224)) {
+ if (init)
+ printk(KERN_INFO DRV_NAME
+ ": Detected Intel PRO/Wireless 2915ABG Network "
+ "Connection\n");
+ priv->ieee->abg_true = 1;
+ band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND;
+ modulation = IEEE80211_OFDM_MODULATION |
+ IEEE80211_CCK_MODULATION;
+ priv->adapter = IPW_2915ABG;
+ priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B;
} else {
- scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN;
- }
-
- if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) {
- int start = channel_index;
- for (i = 0; i < MAX_A_CHANNELS; i++) {
- if (band_a_active_channel[i] == 0)
- break;
- if ((priv->status & STATUS_ASSOCIATED) &&
- band_a_active_channel[i] == priv->channel)
- continue;
- channel_index++;
- scan.channels_list[channel_index] =
- band_a_active_channel[i];
- ipw_set_scan_type(&scan, channel_index, scan_type);
- }
+ if (init)
+ printk(KERN_INFO DRV_NAME
+ ": Detected Intel PRO/Wireless 2200BG Network "
+ "Connection\n");
- if (start != channel_index) {
- scan.channels_list[start] = (u8) (IPW_A_MODE << 6) |
- (channel_index - start);
- channel_index++;
- }
+ priv->ieee->abg_true = 0;
+ band = IEEE80211_24GHZ_BAND;
+ modulation = IEEE80211_OFDM_MODULATION |
+ IEEE80211_CCK_MODULATION;
+ priv->adapter = IPW_2200BG;
+ priv->ieee->mode = IEEE_G | IEEE_B;
}
- if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) {
- int start = channel_index;
- for (i = 0; i < MAX_B_CHANNELS; i++) {
- if (band_b_active_channel[i] == 0)
- break;
- if ((priv->status & STATUS_ASSOCIATED) &&
- band_b_active_channel[i] == priv->channel)
- continue;
- channel_index++;
- scan.channels_list[channel_index] =
- band_b_active_channel[i];
- ipw_set_scan_type(&scan, channel_index, scan_type);
- }
+ priv->ieee->freq_band = band;
+ priv->ieee->modulation = modulation;
- if (start != channel_index) {
- scan.channels_list[start] = (u8) (IPW_B_MODE << 6) |
- (channel_index - start);
- }
- }
+ priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK;
- err = ipw_send_scan_request_ext(priv, &scan);
- if (err) {
- IPW_DEBUG_HC("Sending scan command failed: %08X\n", err);
- return -EIO;
- }
+ priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT;
+ priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT;
- priv->status |= STATUS_SCANNING;
- priv->status &= ~STATUS_SCAN_PENDING;
+ priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
+ priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT;
+ priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT;
- return 0;
+ /* If power management is turned on, default to AC mode */
+ priv->power_mode = IPW_POWER_AC;
+ priv->tx_power = IPW_TX_POWER_DEFAULT;
+
+ return old_mode == priv->ieee->iw_mode;
}
/*
@@ -5247,12 +8127,16 @@ static int ipw_wx_get_name(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
- if (!(priv->status & STATUS_ASSOCIATED))
+ down(&priv->sem);
+ if (priv->status & STATUS_RF_KILL_MASK)
+ strcpy(wrqu->name, "radio off");
+ else if (!(priv->status & STATUS_ASSOCIATED))
strcpy(wrqu->name, "unassociated");
else
snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c",
ipw_modes[priv->assoc_request.ieee_mode]);
IPW_DEBUG_WX("Name: %s\n", wrqu->name);
+ up(&priv->sem);
return 0;
}
@@ -5261,13 +8145,9 @@ static int ipw_set_channel(struct ipw_priv *priv, u8 channel)
if (channel == 0) {
IPW_DEBUG_INFO("Setting channel to ANY (0)\n");
priv->config &= ~CFG_STATIC_CHANNEL;
- if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED |
- STATUS_ASSOCIATING))) {
- IPW_DEBUG_ASSOC("Attempting to associate with new "
- "parameters.\n");
- ipw_associate(priv);
- }
-
+ IPW_DEBUG_ASSOC("Attempting to associate with new "
+ "parameters.\n");
+ ipw_associate(priv);
return 0;
}
@@ -5282,14 +8162,32 @@ static int ipw_set_channel(struct ipw_priv *priv, u8 channel)
IPW_DEBUG_INFO("Setting channel to %i\n", (int)channel);
priv->channel = channel;
- /* If we are currently associated, or trying to associate
- * then see if this is a new channel (causing us to disassociate) */
- if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
- IPW_DEBUG_ASSOC("Disassociating due to channel change.\n");
- ipw_disassociate(priv);
- } else {
- ipw_associate(priv);
+#ifdef CONFIG_IPW2200_MONITOR
+ if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
+ int i;
+ if (priv->status & STATUS_SCANNING) {
+ IPW_DEBUG_SCAN("Scan abort triggered due to "
+ "channel change.\n");
+ ipw_abort_scan(priv);
+ }
+
+ for (i = 1000; i && (priv->status & STATUS_SCANNING); i--)
+ udelay(10);
+
+ if (priv->status & STATUS_SCANNING)
+ IPW_DEBUG_SCAN("Still scanning...\n");
+ else
+ IPW_DEBUG_SCAN("Took %dms to abort current scan\n",
+ 1000 - i);
+
+ return 0;
}
+#endif /* CONFIG_IPW2200_MONITOR */
+
+ /* Network configuration changed -- force [re]association */
+ IPW_DEBUG_ASSOC("[re]association triggered due to channel change.\n");
+ if (!ipw_disassociate(priv))
+ ipw_associate(priv);
return 0;
}
@@ -5299,29 +8197,48 @@ static int ipw_wx_set_freq(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
+ const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee);
struct iw_freq *fwrq = &wrqu->freq;
-
+ int ret = 0, i;
+ u8 channel, flags;
+ int band;
+
+ if (fwrq->m == 0) {
+ IPW_DEBUG_WX("SET Freq/Channel -> any\n");
+ down(&priv->sem);
+ ret = ipw_set_channel(priv, 0);
+ up(&priv->sem);
+ return ret;
+ }
/* if setting by freq convert to channel */
if (fwrq->e == 1) {
- if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) {
- int f = fwrq->m / 100000;
- int c = 0;
+ channel = ipw_freq_to_channel(priv->ieee, fwrq->m);
+ if (channel == 0)
+ return -EINVAL;
+ } else
+ channel = fwrq->m;
+
+ if (!(band = ipw_is_valid_channel(priv->ieee, channel)))
+ return -EINVAL;
- while ((c < REG_MAX_CHANNEL) &&
- (f != ipw_frequencies[c]))
- c++;
+ if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
+ i = ipw_channel_to_index(priv->ieee, channel);
+ if (i == -1)
+ return -EINVAL;
- /* hack to fall through */
- fwrq->e = 0;
- fwrq->m = c + 1;
+ flags = (band == IEEE80211_24GHZ_BAND) ?
+ geo->bg[i].flags : geo->a[i].flags;
+ if (flags & IEEE80211_CH_PASSIVE_ONLY) {
+ IPW_DEBUG_WX("Invalid Ad-Hoc channel for 802.11a\n");
+ return -EINVAL;
}
}
- if (fwrq->e > 0 || fwrq->m > 1000)
- return -EOPNOTSUPP;
-
IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m);
- return ipw_set_channel(priv, (u8) fwrq->m);
+ down(&priv->sem);
+ ret = ipw_set_channel(priv, channel);
+ up(&priv->sem);
+ return ret;
}
static int ipw_wx_get_freq(struct net_device *dev,
@@ -5334,12 +8251,14 @@ static int ipw_wx_get_freq(struct net_device *dev,
/* If we are associated, trying to associate, or have a statically
* configured CHANNEL then return that; otherwise return ANY */
+ down(&priv->sem);
if (priv->config & CFG_STATIC_CHANNEL ||
priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED))
wrqu->freq.m = priv->channel;
else
wrqu->freq.m = 0;
+ up(&priv->sem);
IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel);
return 0;
}
@@ -5353,11 +8272,8 @@ static int ipw_wx_set_mode(struct net_device *dev,
IPW_DEBUG_WX("Set MODE: %d\n", wrqu->mode);
- if (wrqu->mode == priv->ieee->iw_mode)
- return 0;
-
switch (wrqu->mode) {
-#ifdef CONFIG_IPW_PROMISC
+#ifdef CONFIG_IPW2200_MONITOR
case IW_MODE_MONITOR:
#endif
case IW_MODE_ADHOC:
@@ -5369,31 +8285,33 @@ static int ipw_wx_set_mode(struct net_device *dev,
default:
return -EINVAL;
}
+ if (wrqu->mode == priv->ieee->iw_mode)
+ return 0;
+
+ down(&priv->sem);
+
+ ipw_sw_reset(priv, 0);
-#ifdef CONFIG_IPW_PROMISC
+#ifdef CONFIG_IPW2200_MONITOR
if (priv->ieee->iw_mode == IW_MODE_MONITOR)
priv->net_dev->type = ARPHRD_ETHER;
if (wrqu->mode == IW_MODE_MONITOR)
+#ifdef CONFIG_IEEE80211_RADIOTAP
+ priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
+#else
priv->net_dev->type = ARPHRD_IEEE80211;
-#endif /* CONFIG_IPW_PROMISC */
+#endif
+#endif /* CONFIG_IPW2200_MONITOR */
-#ifdef CONFIG_PM
/* Free the existing firmware and reset the fw_loaded
* flag so ipw_load() will bring in the new firmawre */
- if (fw_loaded) {
- fw_loaded = 0;
- }
-
- release_firmware(bootfw);
- release_firmware(ucode);
- release_firmware(firmware);
- bootfw = ucode = firmware = NULL;
-#endif
+ free_firmware();
priv->ieee->iw_mode = wrqu->mode;
- ipw_adapter_restart(priv);
+ queue_work(priv->workqueue, &priv->adapter_restart);
+ up(&priv->sem);
return err;
}
@@ -5402,20 +8320,13 @@ static int ipw_wx_get_mode(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
-
+ down(&priv->sem);
wrqu->mode = priv->ieee->iw_mode;
IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode);
-
+ up(&priv->sem);
return 0;
}
-#define DEFAULT_RTS_THRESHOLD 2304U
-#define MIN_RTS_THRESHOLD 1U
-#define MAX_RTS_THRESHOLD 2304U
-#define DEFAULT_BEACON_INTERVAL 100U
-#define DEFAULT_SHORT_RETRY_LIMIT 7U
-#define DEFAULT_LONG_RETRY_LIMIT 4U
-
/* Values are in microsecond */
static const s32 timeout_duration[] = {
350000,
@@ -5439,8 +8350,8 @@ static int ipw_wx_get_range(struct net_device *dev,
{
struct ipw_priv *priv = ieee80211_priv(dev);
struct iw_range *range = (struct iw_range *)extra;
- u16 val;
- int i;
+ const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee);
+ int i = 0, j;
wrqu->data.length = sizeof(*range);
memset(range, 0, sizeof(*range));
@@ -5451,7 +8362,7 @@ static int ipw_wx_get_range(struct net_device *dev,
range->max_qual.qual = 100;
/* TODO: Find real max RSSI and stick here */
range->max_qual.level = 0;
- range->max_qual.noise = 0;
+ range->max_qual.noise = priv->ieee->worst_rssi + 0x100;
range->max_qual.updated = 7; /* Updated all three */
range->avg_qual.qual = 70;
@@ -5459,7 +8370,7 @@ static int ipw_wx_get_range(struct net_device *dev,
range->avg_qual.level = 0; /* FIXME to real average level */
range->avg_qual.noise = 0;
range->avg_qual.updated = 7; /* Updated all three */
-
+ down(&priv->sem);
range->num_bitrates = min(priv->rates.num_rates, (u8) IW_MAX_BITRATES);
for (i = 0; i < range->num_bitrates; i++)
@@ -5479,19 +8390,35 @@ static int ipw_wx_get_range(struct net_device *dev,
range->we_version_compiled = WIRELESS_EXT;
range->we_version_source = 16;
- range->num_channels = FREQ_COUNT;
-
- val = 0;
- for (i = 0; i < FREQ_COUNT; i++) {
- range->freq[val].i = i + 1;
- range->freq[val].m = ipw_frequencies[i] * 100000;
- range->freq[val].e = 1;
- val++;
+ i = 0;
+ if (priv->ieee->mode & (IEEE_B | IEEE_G)) {
+ for (j = 0; j < geo->bg_channels && i < IW_MAX_FREQUENCIES;
+ i++, j++) {
+ range->freq[i].i = geo->bg[j].channel;
+ range->freq[i].m = geo->bg[j].freq * 100000;
+ range->freq[i].e = 1;
+ }
+ }
- if (val == IW_MAX_FREQUENCIES)
- break;
+ if (priv->ieee->mode & IEEE_A) {
+ for (j = 0; j < geo->a_channels && i < IW_MAX_FREQUENCIES;
+ i++, j++) {
+ range->freq[i].i = geo->a[j].channel;
+ range->freq[i].m = geo->a[j].freq * 100000;
+ range->freq[i].e = 1;
+ }
}
- range->num_frequency = val;
+
+ range->num_channels = i;
+ range->num_frequency = i;
+
+ up(&priv->sem);
+
+ /* Event capability (kernel + driver) */
+ range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
+ IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
+ IW_EVENT_CAPA_MASK(SIOCGIWAP));
+ range->event_capa[1] = IW_EVENT_CAPA_K_1;
IPW_DEBUG_WX("GET Range\n");
return 0;
@@ -5512,25 +8439,23 @@ static int ipw_wx_set_wap(struct net_device *dev,
if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
return -EINVAL;
-
+ down(&priv->sem);
if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) ||
!memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) {
/* we disable mandatory BSSID association */
IPW_DEBUG_WX("Setting AP BSSID to ANY\n");
priv->config &= ~CFG_STATIC_BSSID;
- if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED |
- STATUS_ASSOCIATING))) {
- IPW_DEBUG_ASSOC("Attempting to associate with new "
- "parameters.\n");
- ipw_associate(priv);
- }
-
+ IPW_DEBUG_ASSOC("Attempting to associate with new "
+ "parameters.\n");
+ ipw_associate(priv);
+ up(&priv->sem);
return 0;
}
priv->config |= CFG_STATIC_BSSID;
if (!memcmp(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN)) {
IPW_DEBUG_WX("BSSID set to current BSSID.\n");
+ up(&priv->sem);
return 0;
}
@@ -5539,15 +8464,12 @@ static int ipw_wx_set_wap(struct net_device *dev,
memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
- /* If we are currently associated, or trying to associate
- * then see if this is a new BSSID (causing us to disassociate) */
- if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
- IPW_DEBUG_ASSOC("Disassociating due to BSSID change.\n");
- ipw_disassociate(priv);
- } else {
+ /* Network configuration changed -- force [re]association */
+ IPW_DEBUG_ASSOC("[re]association triggered due to BSSID change.\n");
+ if (!ipw_disassociate(priv))
ipw_associate(priv);
- }
+ up(&priv->sem);
return 0;
}
@@ -5558,15 +8480,17 @@ static int ipw_wx_get_wap(struct net_device *dev,
struct ipw_priv *priv = ieee80211_priv(dev);
/* If we are associated, trying to associate, or have a statically
* configured BSSID then return that; otherwise return ANY */
+ down(&priv->sem);
if (priv->config & CFG_STATIC_BSSID ||
priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
wrqu->ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(wrqu->ap_addr.sa_data, &priv->bssid, ETH_ALEN);
+ memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN);
} else
memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n",
MAC_ARG(wrqu->ap_addr.sa_data));
+ up(&priv->sem);
return 0;
}
@@ -5577,21 +8501,22 @@ static int ipw_wx_set_essid(struct net_device *dev,
struct ipw_priv *priv = ieee80211_priv(dev);
char *essid = ""; /* ANY */
int length = 0;
-
+ down(&priv->sem);
if (wrqu->essid.flags && wrqu->essid.length) {
length = wrqu->essid.length - 1;
essid = extra;
}
if (length == 0) {
IPW_DEBUG_WX("Setting ESSID to ANY\n");
- priv->config &= ~CFG_STATIC_ESSID;
- if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED |
+ if ((priv->config & CFG_STATIC_ESSID) &&
+ !(priv->status & (STATUS_ASSOCIATED |
STATUS_ASSOCIATING))) {
IPW_DEBUG_ASSOC("Attempting to associate with new "
"parameters.\n");
+ priv->config &= ~CFG_STATIC_ESSID;
ipw_associate(priv);
}
-
+ up(&priv->sem);
return 0;
}
@@ -5601,6 +8526,7 @@ static int ipw_wx_set_essid(struct net_device *dev,
if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
IPW_DEBUG_WX("ESSID set to current ESSID.\n");
+ up(&priv->sem);
return 0;
}
@@ -5610,15 +8536,12 @@ static int ipw_wx_set_essid(struct net_device *dev,
priv->essid_len = length;
memcpy(priv->essid, essid, priv->essid_len);
- /* If we are currently associated, or trying to associate
- * then see if this is a new ESSID (causing us to disassociate) */
- if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
- IPW_DEBUG_ASSOC("Disassociating due to ESSID change.\n");
- ipw_disassociate(priv);
- } else {
+ /* Network configuration changed -- force [re]association */
+ IPW_DEBUG_ASSOC("[re]association triggered due to ESSID change.\n");
+ if (!ipw_disassociate(priv))
ipw_associate(priv);
- }
+ up(&priv->sem);
return 0;
}
@@ -5630,6 +8553,7 @@ static int ipw_wx_get_essid(struct net_device *dev,
/* If we are associated, trying to associate, or have a statically
* configured ESSID then return that; otherwise return ANY */
+ down(&priv->sem);
if (priv->config & CFG_STATIC_ESSID ||
priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
IPW_DEBUG_WX("Getting essid: '%s'\n",
@@ -5642,7 +8566,7 @@ static int ipw_wx_get_essid(struct net_device *dev,
wrqu->essid.length = 0;
wrqu->essid.flags = 0; /* active */
}
-
+ up(&priv->sem);
return 0;
}
@@ -5655,11 +8579,12 @@ static int ipw_wx_set_nick(struct net_device *dev,
IPW_DEBUG_WX("Setting nick to '%s'\n", extra);
if (wrqu->data.length > IW_ESSID_MAX_SIZE)
return -E2BIG;
-
+ down(&priv->sem);
wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick));
memset(priv->nick, 0, sizeof(priv->nick));
memcpy(priv->nick, extra, wrqu->data.length);
IPW_DEBUG_TRACE("<<\n");
+ up(&priv->sem);
return 0;
}
@@ -5670,9 +8595,11 @@ static int ipw_wx_get_nick(struct net_device *dev,
{
struct ipw_priv *priv = ieee80211_priv(dev);
IPW_DEBUG_WX("Getting nick\n");
+ down(&priv->sem);
wrqu->data.length = strlen(priv->nick) + 1;
memcpy(extra, priv->nick, wrqu->data.length);
wrqu->data.flags = 1; /* active */
+ up(&priv->sem);
return 0;
}
@@ -5680,8 +8607,113 @@ static int ipw_wx_set_rate(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu);
- return -EOPNOTSUPP;
+ /* TODO: We should use semaphores or locks for access to priv */
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ u32 target_rate = wrqu->bitrate.value;
+ u32 fixed, mask;
+
+ /* value = -1, fixed = 0 means auto only, so we should use all rates offered by AP */
+ /* value = X, fixed = 1 means only rate X */
+ /* value = X, fixed = 0 means all rates lower equal X */
+
+ if (target_rate == -1) {
+ fixed = 0;
+ mask = IEEE80211_DEFAULT_RATES_MASK;
+ /* Now we should reassociate */
+ goto apply;
+ }
+
+ mask = 0;
+ fixed = wrqu->bitrate.fixed;
+
+ if (target_rate == 1000000 || !fixed)
+ mask |= IEEE80211_CCK_RATE_1MB_MASK;
+ if (target_rate == 1000000)
+ goto apply;
+
+ if (target_rate == 2000000 || !fixed)
+ mask |= IEEE80211_CCK_RATE_2MB_MASK;
+ if (target_rate == 2000000)
+ goto apply;
+
+ if (target_rate == 5500000 || !fixed)
+ mask |= IEEE80211_CCK_RATE_5MB_MASK;
+ if (target_rate == 5500000)
+ goto apply;
+
+ if (target_rate == 6000000 || !fixed)
+ mask |= IEEE80211_OFDM_RATE_6MB_MASK;
+ if (target_rate == 6000000)
+ goto apply;
+
+ if (target_rate == 9000000 || !fixed)
+ mask |= IEEE80211_OFDM_RATE_9MB_MASK;
+ if (target_rate == 9000000)
+ goto apply;
+
+ if (target_rate == 11000000 || !fixed)
+ mask |= IEEE80211_CCK_RATE_11MB_MASK;
+ if (target_rate == 11000000)
+ goto apply;
+
+ if (target_rate == 12000000 || !fixed)
+ mask |= IEEE80211_OFDM_RATE_12MB_MASK;
+ if (target_rate == 12000000)
+ goto apply;
+
+ if (target_rate == 18000000 || !fixed)
+ mask |= IEEE80211_OFDM_RATE_18MB_MASK;
+ if (target_rate == 18000000)
+ goto apply;
+
+ if (target_rate == 24000000 || !fixed)
+ mask |= IEEE80211_OFDM_RATE_24MB_MASK;
+ if (target_rate == 24000000)
+ goto apply;
+
+ if (target_rate == 36000000 || !fixed)
+ mask |= IEEE80211_OFDM_RATE_36MB_MASK;
+ if (target_rate == 36000000)
+ goto apply;
+
+ if (target_rate == 48000000 || !fixed)
+ mask |= IEEE80211_OFDM_RATE_48MB_MASK;
+ if (target_rate == 48000000)
+ goto apply;
+
+ if (target_rate == 54000000 || !fixed)
+ mask |= IEEE80211_OFDM_RATE_54MB_MASK;
+ if (target_rate == 54000000)
+ goto apply;
+
+ IPW_DEBUG_WX("invalid rate specified, returning error\n");
+ return -EINVAL;
+
+ apply:
+ IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n",
+ mask, fixed ? "fixed" : "sub-rates");
+ down(&priv->sem);
+ if (mask == IEEE80211_DEFAULT_RATES_MASK) {
+ priv->config &= ~CFG_FIXED_RATE;
+ ipw_set_fixed_rate(priv, priv->ieee->mode);
+ } else
+ priv->config |= CFG_FIXED_RATE;
+
+ if (priv->rates_mask == mask) {
+ IPW_DEBUG_WX("Mask set to current mask.\n");
+ up(&priv->sem);
+ return 0;
+ }
+
+ priv->rates_mask = mask;
+
+ /* Network configuration changed -- force [re]association */
+ IPW_DEBUG_ASSOC("[re]association triggered due to rates change.\n");
+ if (!ipw_disassociate(priv))
+ ipw_associate(priv);
+
+ up(&priv->sem);
+ return 0;
}
static int ipw_wx_get_rate(struct net_device *dev,
@@ -5689,8 +8721,9 @@ static int ipw_wx_get_rate(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
+ down(&priv->sem);
wrqu->bitrate.value = priv->last_rate;
-
+ up(&priv->sem);
IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value);
return 0;
}
@@ -5700,18 +8733,20 @@ static int ipw_wx_set_rts(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
-
+ down(&priv->sem);
if (wrqu->rts.disabled)
priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
else {
if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
- wrqu->rts.value > MAX_RTS_THRESHOLD)
+ wrqu->rts.value > MAX_RTS_THRESHOLD) {
+ up(&priv->sem);
return -EINVAL;
-
+ }
priv->rts_threshold = wrqu->rts.value;
}
ipw_send_rts_threshold(priv, priv->rts_threshold);
+ up(&priv->sem);
IPW_DEBUG_WX("SET RTS Threshold -> %d \n", priv->rts_threshold);
return 0;
}
@@ -5721,10 +8756,11 @@ static int ipw_wx_get_rts(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
+ down(&priv->sem);
wrqu->rts.value = priv->rts_threshold;
wrqu->rts.fixed = 0; /* no auto select */
wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
-
+ up(&priv->sem);
IPW_DEBUG_WX("GET RTS Threshold -> %d \n", wrqu->rts.value);
return 0;
}
@@ -5734,41 +8770,33 @@ static int ipw_wx_set_txpow(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
- struct ipw_tx_power tx_power;
- int i;
-
- if (ipw_radio_kill_sw(priv, wrqu->power.disabled))
- return -EINPROGRESS;
-
- if (wrqu->power.flags != IW_TXPOW_DBM)
- return -EINVAL;
+ int err = 0;
- if ((wrqu->power.value > 20) || (wrqu->power.value < -12))
- return -EINVAL;
+ down(&priv->sem);
+ if (ipw_radio_kill_sw(priv, wrqu->power.disabled)) {
+ err = -EINPROGRESS;
+ goto out;
+ }
- priv->tx_power = wrqu->power.value;
+ if (!wrqu->power.fixed)
+ wrqu->power.value = IPW_TX_POWER_DEFAULT;
- memset(&tx_power, 0, sizeof(tx_power));
-
- /* configure device for 'G' band */
- tx_power.ieee_mode = IPW_G_MODE;
- tx_power.num_channels = 11;
- for (i = 0; i < 11; i++) {
- tx_power.channels_tx_power[i].channel_number = i + 1;
- tx_power.channels_tx_power[i].tx_power = priv->tx_power;
+ if (wrqu->power.flags != IW_TXPOW_DBM) {
+ err = -EINVAL;
+ goto out;
}
- if (ipw_send_tx_power(priv, &tx_power))
- goto error;
- /* configure device to also handle 'B' band */
- tx_power.ieee_mode = IPW_B_MODE;
- if (ipw_send_tx_power(priv, &tx_power))
- goto error;
-
- return 0;
+ if ((wrqu->power.value > IPW_TX_POWER_MAX) ||
+ (wrqu->power.value < IPW_TX_POWER_MIN)) {
+ err = -EINVAL;
+ goto out;
+ }
- error:
- return -EIO;
+ priv->tx_power = wrqu->power.value;
+ err = ipw_set_tx_power(priv);
+ out:
+ up(&priv->sem);
+ return err;
}
static int ipw_wx_get_txpow(struct net_device *dev,
@@ -5776,14 +8804,15 @@ static int ipw_wx_get_txpow(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
-
+ down(&priv->sem);
wrqu->power.value = priv->tx_power;
wrqu->power.fixed = 1;
wrqu->power.flags = IW_TXPOW_DBM;
wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
+ up(&priv->sem);
IPW_DEBUG_WX("GET TX Power -> %s %d \n",
- wrqu->power.disabled ? "ON" : "OFF", wrqu->power.value);
+ wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value);
return 0;
}
@@ -5793,18 +8822,21 @@ static int ipw_wx_set_frag(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
-
+ down(&priv->sem);
if (wrqu->frag.disabled)
priv->ieee->fts = DEFAULT_FTS;
else {
if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
- wrqu->frag.value > MAX_FRAG_THRESHOLD)
+ wrqu->frag.value > MAX_FRAG_THRESHOLD) {
+ up(&priv->sem);
return -EINVAL;
+ }
priv->ieee->fts = wrqu->frag.value & ~0x1;
}
ipw_send_frag_threshold(priv, wrqu->frag.value);
+ up(&priv->sem);
IPW_DEBUG_WX("SET Frag Threshold -> %d \n", wrqu->frag.value);
return 0;
}
@@ -5814,10 +8846,11 @@ static int ipw_wx_get_frag(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
+ down(&priv->sem);
wrqu->frag.value = priv->ieee->fts;
wrqu->frag.fixed = 0; /* no auto select */
wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FTS);
-
+ up(&priv->sem);
IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value);
return 0;
@@ -5827,16 +8860,128 @@ static int ipw_wx_set_retry(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu);
- return -EOPNOTSUPP;
+ struct ipw_priv *priv = ieee80211_priv(dev);
+
+ if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
+ return -EINVAL;
+
+ if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
+ return 0;
+
+ if (wrqu->retry.value < 0 || wrqu->retry.value > 255)
+ return -EINVAL;
+
+ down(&priv->sem);
+ if (wrqu->retry.flags & IW_RETRY_MIN)
+ priv->short_retry_limit = (u8) wrqu->retry.value;
+ else if (wrqu->retry.flags & IW_RETRY_MAX)
+ priv->long_retry_limit = (u8) wrqu->retry.value;
+ else {
+ priv->short_retry_limit = (u8) wrqu->retry.value;
+ priv->long_retry_limit = (u8) wrqu->retry.value;
+ }
+
+ ipw_send_retry_limit(priv, priv->short_retry_limit,
+ priv->long_retry_limit);
+ up(&priv->sem);
+ IPW_DEBUG_WX("SET retry limit -> short:%d long:%d\n",
+ priv->short_retry_limit, priv->long_retry_limit);
+ return 0;
}
static int ipw_wx_get_retry(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu);
- return -EOPNOTSUPP;
+ struct ipw_priv *priv = ieee80211_priv(dev);
+
+ down(&priv->sem);
+ wrqu->retry.disabled = 0;
+
+ if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+ up(&priv->sem);
+ return -EINVAL;
+ }
+
+ if (wrqu->retry.flags & IW_RETRY_MAX) {
+ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ wrqu->retry.value = priv->long_retry_limit;
+ } else if (wrqu->retry.flags & IW_RETRY_MIN) {
+ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
+ wrqu->retry.value = priv->short_retry_limit;
+ } else {
+ wrqu->retry.flags = IW_RETRY_LIMIT;
+ wrqu->retry.value = priv->short_retry_limit;
+ }
+ up(&priv->sem);
+
+ IPW_DEBUG_WX("GET retry -> %d \n", wrqu->retry.value);
+
+ return 0;
+}
+
+static int ipw_request_direct_scan(struct ipw_priv *priv, char *essid,
+ int essid_len)
+{
+ struct ipw_scan_request_ext scan;
+ int err = 0, scan_type;
+
+ down(&priv->sem);
+
+ if (priv->status & STATUS_RF_KILL_MASK) {
+ IPW_DEBUG_HC("Aborting scan due to RF kill activation\n");
+ priv->status |= STATUS_SCAN_PENDING;
+ goto done;
+ }
+
+ IPW_DEBUG_HC("starting request direct scan!\n");
+
+ if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) {
+ err = wait_event_interruptible(priv->wait_state,
+ !(priv->
+ status & (STATUS_SCANNING |
+ STATUS_SCAN_ABORTING)));
+ if (err) {
+ IPW_DEBUG_HC("aborting direct scan");
+ goto done;
+ }
+ }
+ memset(&scan, 0, sizeof(scan));
+
+ if (priv->config & CFG_SPEED_SCAN)
+ scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
+ cpu_to_le16(30);
+ else
+ scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
+ cpu_to_le16(20);
+
+ scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] =
+ cpu_to_le16(20);
+ scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120);
+ scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20);
+
+ scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee));
+
+ err = ipw_send_ssid(priv, essid, essid_len);
+ if (err) {
+ IPW_DEBUG_HC("Attempt to send SSID command failed\n");
+ goto done;
+ }
+ scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
+
+ ipw_add_scan_channels(priv, &scan, scan_type);
+
+ err = ipw_send_scan_request_ext(priv, &scan);
+ if (err) {
+ IPW_DEBUG_HC("Sending scan command failed: %08X\n", err);
+ goto done;
+ }
+
+ priv->status |= STATUS_SCANNING;
+
+ done:
+ up(&priv->sem);
+ return err;
}
static int ipw_wx_set_scan(struct net_device *dev,
@@ -5844,9 +8989,21 @@ static int ipw_wx_set_scan(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
+ struct iw_scan_req *req = NULL;
+ if (wrqu->data.length
+ && wrqu->data.length == sizeof(struct iw_scan_req)) {
+ req = (struct iw_scan_req *)extra;
+ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+ ipw_request_direct_scan(priv, req->essid,
+ req->essid_len);
+ return 0;
+ }
+ }
+
IPW_DEBUG_WX("Start scan\n");
- if (ipw_request_scan(priv))
- return -EIO;
+
+ queue_work(priv->workqueue, &priv->request_scan);
+
return 0;
}
@@ -5863,7 +9020,21 @@ static int ipw_wx_set_encode(struct net_device *dev,
union iwreq_data *wrqu, char *key)
{
struct ipw_priv *priv = ieee80211_priv(dev);
- return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key);
+ int ret;
+ u32 cap = priv->capability;
+
+ down(&priv->sem);
+ ret = ieee80211_wx_set_encode(priv->ieee, info, wrqu, key);
+
+ /* In IBSS mode, we need to notify the firmware to update
+ * the beacon info after we changed the capability. */
+ if (cap != priv->capability &&
+ priv->ieee->iw_mode == IW_MODE_ADHOC &&
+ priv->status & STATUS_ASSOCIATED)
+ ipw_disassociate(priv);
+
+ up(&priv->sem);
+ return ret;
}
static int ipw_wx_get_encode(struct net_device *dev,
@@ -5880,17 +9051,17 @@ static int ipw_wx_set_power(struct net_device *dev,
{
struct ipw_priv *priv = ieee80211_priv(dev);
int err;
-
+ down(&priv->sem);
if (wrqu->power.disabled) {
priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
err = ipw_send_power_mode(priv, IPW_POWER_MODE_CAM);
if (err) {
IPW_DEBUG_WX("failed setting power mode.\n");
+ up(&priv->sem);
return err;
}
-
IPW_DEBUG_WX("SET Power Management Mode -> off\n");
-
+ up(&priv->sem);
return 0;
}
@@ -5902,6 +9073,7 @@ static int ipw_wx_set_power(struct net_device *dev,
default: /* Otherwise we don't support it */
IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
wrqu->power.flags);
+ up(&priv->sem);
return -EOPNOTSUPP;
}
@@ -5914,11 +9086,12 @@ static int ipw_wx_set_power(struct net_device *dev,
err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
if (err) {
IPW_DEBUG_WX("failed setting power mode.\n");
+ up(&priv->sem);
return err;
}
IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
-
+ up(&priv->sem);
return 0;
}
@@ -5927,13 +9100,13 @@ static int ipw_wx_get_power(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
-
- if (!(priv->power_mode & IPW_POWER_ENABLED)) {
+ down(&priv->sem);
+ if (!(priv->power_mode & IPW_POWER_ENABLED))
wrqu->power.disabled = 1;
- } else {
+ else
wrqu->power.disabled = 0;
- }
+ up(&priv->sem);
IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
return 0;
@@ -5946,7 +9119,7 @@ static int ipw_wx_set_powermode(struct net_device *dev,
struct ipw_priv *priv = ieee80211_priv(dev);
int mode = *(int *)extra;
int err;
-
+ down(&priv->sem);
if ((mode < 1) || (mode > IPW_POWER_LIMIT)) {
mode = IPW_POWER_AC;
priv->power_mode = mode;
@@ -5959,10 +9132,11 @@ static int ipw_wx_set_powermode(struct net_device *dev,
if (err) {
IPW_DEBUG_WX("failed setting power mode.\n");
+ up(&priv->sem);
return err;
}
}
-
+ up(&priv->sem);
return 0;
}
@@ -6011,7 +9185,7 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev,
IPW_WARNING("Attempt to set invalid wireless mode: %d\n", mode);
return -EINVAL;
}
-
+ down(&priv->sem);
if (priv->adapter == IPW_2915ABG) {
priv->ieee->abg_true = 1;
if (mode & IEEE_A) {
@@ -6023,6 +9197,7 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev,
if (mode & IEEE_A) {
IPW_WARNING("Attempt to set 2200BG into "
"802.11a mode\n");
+ up(&priv->sem);
return -EINVAL;
}
@@ -6046,20 +9221,20 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev,
priv->ieee->modulation = modulation;
init_supported_rates(priv, &priv->rates);
- /* If we are currently associated, or trying to associate
- * then see if this is a new configuration (causing us to
- * disassociate) */
- if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
- /* The resulting association will trigger
- * the new rates to be sent to the device */
- IPW_DEBUG_ASSOC("Disassociating due to mode change.\n");
- ipw_disassociate(priv);
- } else
+ /* Network configuration changed -- force [re]association */
+ IPW_DEBUG_ASSOC("[re]association triggered due to mode change.\n");
+ if (!ipw_disassociate(priv)) {
ipw_send_supported_rates(priv, &priv->rates);
+ ipw_associate(priv);
+ }
+
+ /* Update the band LEDs */
+ ipw_led_band_on(priv);
IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n",
mode & IEEE_A ? 'a' : '.',
mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.');
+ up(&priv->sem);
return 0;
}
@@ -6068,124 +9243,234 @@ static int ipw_wx_get_wireless_mode(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
-
- switch (priv->ieee->freq_band) {
- case IEEE80211_24GHZ_BAND:
- switch (priv->ieee->modulation) {
- case IEEE80211_CCK_MODULATION:
- strncpy(extra, "802.11b (2)", MAX_WX_STRING);
- break;
- case IEEE80211_OFDM_MODULATION:
- strncpy(extra, "802.11g (4)", MAX_WX_STRING);
- break;
- default:
- strncpy(extra, "802.11bg (6)", MAX_WX_STRING);
- break;
- }
- break;
-
- case IEEE80211_52GHZ_BAND:
+ down(&priv->sem);
+ switch (priv->ieee->mode) {
+ case IEEE_A:
strncpy(extra, "802.11a (1)", MAX_WX_STRING);
break;
-
- default: /* Mixed Band */
- switch (priv->ieee->modulation) {
- case IEEE80211_CCK_MODULATION:
- strncpy(extra, "802.11ab (3)", MAX_WX_STRING);
- break;
- case IEEE80211_OFDM_MODULATION:
- strncpy(extra, "802.11ag (5)", MAX_WX_STRING);
- break;
- default:
- strncpy(extra, "802.11abg (7)", MAX_WX_STRING);
- break;
- }
+ case IEEE_B:
+ strncpy(extra, "802.11b (2)", MAX_WX_STRING);
+ break;
+ case IEEE_A | IEEE_B:
+ strncpy(extra, "802.11ab (3)", MAX_WX_STRING);
+ break;
+ case IEEE_G:
+ strncpy(extra, "802.11g (4)", MAX_WX_STRING);
+ break;
+ case IEEE_A | IEEE_G:
+ strncpy(extra, "802.11ag (5)", MAX_WX_STRING);
+ break;
+ case IEEE_B | IEEE_G:
+ strncpy(extra, "802.11bg (6)", MAX_WX_STRING);
+ break;
+ case IEEE_A | IEEE_B | IEEE_G:
+ strncpy(extra, "802.11abg (7)", MAX_WX_STRING);
+ break;
+ default:
+ strncpy(extra, "unknown", MAX_WX_STRING);
break;
}
IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra);
wrqu->data.length = strlen(extra) + 1;
+ up(&priv->sem);
return 0;
}
-#ifdef CONFIG_IPW_PROMISC
-static int ipw_wx_set_promisc(struct net_device *dev,
+static int ipw_wx_set_preamble(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ int mode = *(int *)extra;
+ down(&priv->sem);
+ /* Switching from SHORT -> LONG requires a disassociation */
+ if (mode == 1) {
+ if (!(priv->config & CFG_PREAMBLE_LONG)) {
+ priv->config |= CFG_PREAMBLE_LONG;
+
+ /* Network configuration changed -- force [re]association */
+ IPW_DEBUG_ASSOC
+ ("[re]association triggered due to preamble change.\n");
+ if (!ipw_disassociate(priv))
+ ipw_associate(priv);
+ }
+ goto done;
+ }
+
+ if (mode == 0) {
+ priv->config &= ~CFG_PREAMBLE_LONG;
+ goto done;
+ }
+ up(&priv->sem);
+ return -EINVAL;
+
+ done:
+ up(&priv->sem);
+ return 0;
+}
+
+static int ipw_wx_get_preamble(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ down(&priv->sem);
+ if (priv->config & CFG_PREAMBLE_LONG)
+ snprintf(wrqu->name, IFNAMSIZ, "long (1)");
+ else
+ snprintf(wrqu->name, IFNAMSIZ, "auto (0)");
+ up(&priv->sem);
+ return 0;
+}
+
+#ifdef CONFIG_IPW2200_MONITOR
+static int ipw_wx_set_monitor(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
int *parms = (int *)extra;
int enable = (parms[0] > 0);
-
- IPW_DEBUG_WX("SET PROMISC: %d %d\n", enable, parms[1]);
+ down(&priv->sem);
+ IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]);
if (enable) {
if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
+#ifdef CONFIG_IEEE80211_RADIOTAP
+ priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
+#else
priv->net_dev->type = ARPHRD_IEEE80211;
- ipw_adapter_restart(priv);
+#endif
+ queue_work(priv->workqueue, &priv->adapter_restart);
}
ipw_set_channel(priv, parms[1]);
} else {
- if (priv->ieee->iw_mode != IW_MODE_MONITOR)
+ if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
+ up(&priv->sem);
return 0;
+ }
priv->net_dev->type = ARPHRD_ETHER;
- ipw_adapter_restart(priv);
+ queue_work(priv->workqueue, &priv->adapter_restart);
}
+ up(&priv->sem);
return 0;
}
+#endif // CONFIG_IPW2200_MONITOR
+
static int ipw_wx_reset(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
IPW_DEBUG_WX("RESET\n");
- ipw_adapter_restart(priv);
+ queue_work(priv->workqueue, &priv->adapter_restart);
+ return 0;
+}
+
+static int ipw_wx_sw_reset(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+ union iwreq_data wrqu_sec = {
+ .encoding = {
+ .flags = IW_ENCODE_DISABLED,
+ },
+ };
+ int ret;
+
+ IPW_DEBUG_WX("SW_RESET\n");
+
+ down(&priv->sem);
+
+ ret = ipw_sw_reset(priv, 0);
+ if (!ret) {
+ free_firmware();
+ ipw_adapter_restart(priv);
+ }
+
+ /* The SW reset bit might have been toggled on by the 'disable'
+ * module parameter, so take appropriate action */
+ ipw_radio_kill_sw(priv, priv->status & STATUS_RF_KILL_SW);
+
+ up(&priv->sem);
+ ieee80211_wx_set_encode(priv->ieee, info, &wrqu_sec, NULL);
+ down(&priv->sem);
+
+ if (!(priv->status & STATUS_RF_KILL_MASK)) {
+ /* Configuration likely changed -- force [re]association */
+ IPW_DEBUG_ASSOC("[re]association triggered due to sw "
+ "reset.\n");
+ if (!ipw_disassociate(priv))
+ ipw_associate(priv);
+ }
+
+ up(&priv->sem);
+
return 0;
}
-#endif // CONFIG_IPW_PROMISC
/* Rebase the WE IOCTLs to zero for the handler array */
#define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT]
static iw_handler ipw_wx_handlers[] = {
- IW_IOCTL(SIOCGIWNAME) = ipw_wx_get_name,
- IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq,
- IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq,
- IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode,
- IW_IOCTL(SIOCGIWMODE) = ipw_wx_get_mode,
- IW_IOCTL(SIOCGIWRANGE) = ipw_wx_get_range,
- IW_IOCTL(SIOCSIWAP) = ipw_wx_set_wap,
- IW_IOCTL(SIOCGIWAP) = ipw_wx_get_wap,
- IW_IOCTL(SIOCSIWSCAN) = ipw_wx_set_scan,
- IW_IOCTL(SIOCGIWSCAN) = ipw_wx_get_scan,
- IW_IOCTL(SIOCSIWESSID) = ipw_wx_set_essid,
- IW_IOCTL(SIOCGIWESSID) = ipw_wx_get_essid,
- IW_IOCTL(SIOCSIWNICKN) = ipw_wx_set_nick,
- IW_IOCTL(SIOCGIWNICKN) = ipw_wx_get_nick,
- IW_IOCTL(SIOCSIWRATE) = ipw_wx_set_rate,
- IW_IOCTL(SIOCGIWRATE) = ipw_wx_get_rate,
- IW_IOCTL(SIOCSIWRTS) = ipw_wx_set_rts,
- IW_IOCTL(SIOCGIWRTS) = ipw_wx_get_rts,
- IW_IOCTL(SIOCSIWFRAG) = ipw_wx_set_frag,
- IW_IOCTL(SIOCGIWFRAG) = ipw_wx_get_frag,
- IW_IOCTL(SIOCSIWTXPOW) = ipw_wx_set_txpow,
- IW_IOCTL(SIOCGIWTXPOW) = ipw_wx_get_txpow,
- IW_IOCTL(SIOCSIWRETRY) = ipw_wx_set_retry,
- IW_IOCTL(SIOCGIWRETRY) = ipw_wx_get_retry,
- IW_IOCTL(SIOCSIWENCODE) = ipw_wx_set_encode,
- IW_IOCTL(SIOCGIWENCODE) = ipw_wx_get_encode,
- IW_IOCTL(SIOCSIWPOWER) = ipw_wx_set_power,
- IW_IOCTL(SIOCGIWPOWER) = ipw_wx_get_power,
+ IW_IOCTL(SIOCGIWNAME) = ipw_wx_get_name,
+ IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq,
+ IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq,
+ IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode,
+ IW_IOCTL(SIOCGIWMODE) = ipw_wx_get_mode,
+ IW_IOCTL(SIOCGIWRANGE) = ipw_wx_get_range,
+ IW_IOCTL(SIOCSIWAP) = ipw_wx_set_wap,
+ IW_IOCTL(SIOCGIWAP) = ipw_wx_get_wap,
+ IW_IOCTL(SIOCSIWSCAN) = ipw_wx_set_scan,
+ IW_IOCTL(SIOCGIWSCAN) = ipw_wx_get_scan,
+ IW_IOCTL(SIOCSIWESSID) = ipw_wx_set_essid,
+ IW_IOCTL(SIOCGIWESSID) = ipw_wx_get_essid,
+ IW_IOCTL(SIOCSIWNICKN) = ipw_wx_set_nick,
+ IW_IOCTL(SIOCGIWNICKN) = ipw_wx_get_nick,
+ IW_IOCTL(SIOCSIWRATE) = ipw_wx_set_rate,
+ IW_IOCTL(SIOCGIWRATE) = ipw_wx_get_rate,
+ IW_IOCTL(SIOCSIWRTS) = ipw_wx_set_rts,
+ IW_IOCTL(SIOCGIWRTS) = ipw_wx_get_rts,
+ IW_IOCTL(SIOCSIWFRAG) = ipw_wx_set_frag,
+ IW_IOCTL(SIOCGIWFRAG) = ipw_wx_get_frag,
+ IW_IOCTL(SIOCSIWTXPOW) = ipw_wx_set_txpow,
+ IW_IOCTL(SIOCGIWTXPOW) = ipw_wx_get_txpow,
+ IW_IOCTL(SIOCSIWRETRY) = ipw_wx_set_retry,
+ IW_IOCTL(SIOCGIWRETRY) = ipw_wx_get_retry,
+ IW_IOCTL(SIOCSIWENCODE) = ipw_wx_set_encode,
+ IW_IOCTL(SIOCGIWENCODE) = ipw_wx_get_encode,
+ IW_IOCTL(SIOCSIWPOWER) = ipw_wx_set_power,
+ IW_IOCTL(SIOCGIWPOWER) = ipw_wx_get_power,
+ IW_IOCTL(SIOCSIWSPY) = iw_handler_set_spy,
+ IW_IOCTL(SIOCGIWSPY) = iw_handler_get_spy,
+ IW_IOCTL(SIOCSIWTHRSPY) = iw_handler_set_thrspy,
+ IW_IOCTL(SIOCGIWTHRSPY) = iw_handler_get_thrspy,
+ IW_IOCTL(SIOCSIWGENIE) = ipw_wx_set_genie,
+ IW_IOCTL(SIOCGIWGENIE) = ipw_wx_get_genie,
+ IW_IOCTL(SIOCSIWMLME) = ipw_wx_set_mlme,
+ IW_IOCTL(SIOCSIWAUTH) = ipw_wx_set_auth,
+ IW_IOCTL(SIOCGIWAUTH) = ipw_wx_get_auth,
+ IW_IOCTL(SIOCSIWENCODEEXT) = ipw_wx_set_encodeext,
+ IW_IOCTL(SIOCGIWENCODEEXT) = ipw_wx_get_encodeext,
};
-#define IPW_PRIV_SET_POWER SIOCIWFIRSTPRIV
-#define IPW_PRIV_GET_POWER SIOCIWFIRSTPRIV+1
-#define IPW_PRIV_SET_MODE SIOCIWFIRSTPRIV+2
-#define IPW_PRIV_GET_MODE SIOCIWFIRSTPRIV+3
-#define IPW_PRIV_SET_PROMISC SIOCIWFIRSTPRIV+4
-#define IPW_PRIV_RESET SIOCIWFIRSTPRIV+5
+enum {
+ IPW_PRIV_SET_POWER = SIOCIWFIRSTPRIV,
+ IPW_PRIV_GET_POWER,
+ IPW_PRIV_SET_MODE,
+ IPW_PRIV_GET_MODE,
+ IPW_PRIV_SET_PREAMBLE,
+ IPW_PRIV_GET_PREAMBLE,
+ IPW_PRIV_RESET,
+ IPW_PRIV_SW_RESET,
+#ifdef CONFIG_IPW2200_MONITOR
+ IPW_PRIV_SET_MONITOR,
+#endif
+};
static struct iw_priv_args ipw_priv_args[] = {
{
@@ -6204,14 +9489,25 @@ static struct iw_priv_args ipw_priv_args[] = {
.cmd = IPW_PRIV_GET_MODE,
.get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
.name = "get_mode"},
-#ifdef CONFIG_IPW_PROMISC
{
- IPW_PRIV_SET_PROMISC,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
+ .cmd = IPW_PRIV_SET_PREAMBLE,
+ .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ .name = "set_preamble"},
+ {
+ .cmd = IPW_PRIV_GET_PREAMBLE,
+ .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ,
+ .name = "get_preamble"},
{
IPW_PRIV_RESET,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"},
-#endif /* CONFIG_IPW_PROMISC */
+ {
+ IPW_PRIV_SW_RESET,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "sw_reset"},
+#ifdef CONFIG_IPW2200_MONITOR
+ {
+ IPW_PRIV_SET_MONITOR,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
+#endif /* CONFIG_IPW2200_MONITOR */
};
static iw_handler ipw_priv_handler[] = {
@@ -6219,19 +9515,23 @@ static iw_handler ipw_priv_handler[] = {
ipw_wx_get_powermode,
ipw_wx_set_wireless_mode,
ipw_wx_get_wireless_mode,
-#ifdef CONFIG_IPW_PROMISC
- ipw_wx_set_promisc,
+ ipw_wx_set_preamble,
+ ipw_wx_get_preamble,
ipw_wx_reset,
+ ipw_wx_sw_reset,
+#ifdef CONFIG_IPW2200_MONITOR
+ ipw_wx_set_monitor,
#endif
};
static struct iw_handler_def ipw_wx_handler_def = {
- .standard = ipw_wx_handlers,
- .num_standard = ARRAY_SIZE(ipw_wx_handlers),
- .num_private = ARRAY_SIZE(ipw_priv_handler),
- .num_private_args = ARRAY_SIZE(ipw_priv_args),
- .private = ipw_priv_handler,
- .private_args = ipw_priv_args,
+ .standard = ipw_wx_handlers,
+ .num_standard = ARRAY_SIZE(ipw_wx_handlers),
+ .num_private = ARRAY_SIZE(ipw_priv_handler),
+ .num_private_args = ARRAY_SIZE(ipw_priv_args),
+ .private = ipw_priv_handler,
+ .private_args = ipw_priv_args,
+ .get_wireless_stats = ipw_get_wireless_stats,
};
/*
@@ -6246,8 +9546,8 @@ static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev)
wstats = &priv->wstats;
- /* if hw is disabled, then ipw2100_get_ordinal() can't be called.
- * ipw2100_wx_wireless_stats seems to be called before fw is
+ /* if hw is disabled, then ipw_get_ordinal() can't be called.
+ * netdev->get_wireless_stats seems to be called before fw is
* initialized. STATUS_ASSOCIATED will only be set if the hw is up
* and associated; if not associcated, the values are all meaningless
* anyway, so set them all to NULL and INVALID */
@@ -6298,7 +9598,7 @@ static inline void init_sys_config(struct ipw_sys_config *sys_config)
sys_config->dot11g_auto_detection = 0;
sys_config->enable_cts_to_self = 0;
sys_config->bt_coexist_collision_thr = 0;
- sys_config->pass_noise_stats_to_host = 1;
+ sys_config->pass_noise_stats_to_host = 1; //1 -- fix for 256
}
static int ipw_net_open(struct net_device *dev)
@@ -6306,9 +9606,11 @@ static int ipw_net_open(struct net_device *dev)
struct ipw_priv *priv = ieee80211_priv(dev);
IPW_DEBUG_INFO("dev->open\n");
/* we should be verifying the device is ready to be opened */
+ down(&priv->sem);
if (!(priv->status & STATUS_RF_KILL_MASK) &&
(priv->status & STATUS_ASSOCIATED))
netif_start_queue(dev);
+ up(&priv->sem);
return 0;
}
@@ -6326,22 +9628,34 @@ modify to send one tfd per fragment instead of using chunking. otherwise
we need to heavily modify the ieee80211_skb_to_txb.
*/
-static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb)
+static inline int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
+ int pri)
{
struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)
txb->fragments[0]->data;
int i = 0;
struct tfd_frame *tfd;
+#ifdef CONFIG_IPW_QOS
+ int tx_id = ipw_get_tx_queue_number(priv, pri);
+ struct clx2_tx_queue *txq = &priv->txq[tx_id];
+#else
struct clx2_tx_queue *txq = &priv->txq[0];
+#endif
struct clx2_queue *q = &txq->q;
u8 id, hdr_len, unicast;
u16 remaining_bytes;
+ int fc;
+
+ /* If there isn't room in the queue, we return busy and let the
+ * network stack requeue the packet for us */
+ if (ipw_queue_space(q) < q->high_mark)
+ return NETDEV_TX_BUSY;
switch (priv->ieee->iw_mode) {
case IW_MODE_ADHOC:
hdr_len = IEEE80211_3ADDR_LEN;
- unicast = !is_broadcast_ether_addr(hdr->addr1) &&
- !is_multicast_ether_addr(hdr->addr1);
+ unicast = !(is_multicast_ether_addr(hdr->addr1) ||
+ is_broadcast_ether_addr(hdr->addr1));
id = ipw_find_station(priv, hdr->addr1);
if (id == IPW_INVALID_STATION) {
id = ipw_add_station(priv, hdr->addr1);
@@ -6356,8 +9670,8 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb)
case IW_MODE_INFRA:
default:
- unicast = !is_broadcast_ether_addr(hdr->addr3) &&
- !is_multicast_ether_addr(hdr->addr3);
+ unicast = !(is_multicast_ether_addr(hdr->addr3) ||
+ is_broadcast_ether_addr(hdr->addr3));
hdr_len = IEEE80211_3ADDR_LEN;
id = 0;
break;
@@ -6372,26 +9686,83 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb)
tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK;
tfd->u.data.cmd_id = DINO_CMD_TX;
- tfd->u.data.len = txb->payload_size;
+ tfd->u.data.len = cpu_to_le16(txb->payload_size);
remaining_bytes = txb->payload_size;
- if (unlikely(!unicast))
- tfd->u.data.tx_flags = DCT_FLAG_NO_WEP;
- else
- tfd->u.data.tx_flags = DCT_FLAG_NO_WEP | DCT_FLAG_ACK_REQD;
if (priv->assoc_request.ieee_mode == IPW_B_MODE)
- tfd->u.data.tx_flags_ext = DCT_FLAG_EXT_MODE_CCK;
+ tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_CCK;
else
- tfd->u.data.tx_flags_ext = DCT_FLAG_EXT_MODE_OFDM;
+ tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_OFDM;
- if (priv->config & CFG_PREAMBLE)
- tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREMBL;
+ if (priv->assoc_request.preamble_length == DCT_FLAG_SHORT_PREAMBLE)
+ tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREAMBLE;
+
+ fc = le16_to_cpu(hdr->frame_ctl);
+ hdr->frame_ctl = cpu_to_le16(fc & ~IEEE80211_FCTL_MOREFRAGS);
memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len);
+ if (likely(unicast))
+ tfd->u.data.tx_flags |= DCT_FLAG_ACK_REQD;
+
+ if (txb->encrypted && !priv->ieee->host_encrypt) {
+ switch (priv->ieee->sec.level) {
+ case SEC_LEVEL_3:
+ tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
+ IEEE80211_FCTL_PROTECTED;
+ /* XXX: ACK flag must be set for CCMP even if it
+ * is a multicast/broadcast packet, because CCMP
+ * group communication encrypted by GTK is
+ * actually done by the AP. */
+ if (!unicast)
+ tfd->u.data.tx_flags |= DCT_FLAG_ACK_REQD;
+
+ tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP;
+ tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_CCM;
+ tfd->u.data.key_index = 0;
+ tfd->u.data.key_index |= DCT_WEP_INDEX_USE_IMMEDIATE;
+ break;
+ case SEC_LEVEL_2:
+ tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
+ IEEE80211_FCTL_PROTECTED;
+ tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP;
+ tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_TKIP;
+ tfd->u.data.key_index = DCT_WEP_INDEX_USE_IMMEDIATE;
+ break;
+ case SEC_LEVEL_1:
+ tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
+ IEEE80211_FCTL_PROTECTED;
+ tfd->u.data.key_index = priv->ieee->tx_keyidx;
+ if (priv->ieee->sec.key_sizes[priv->ieee->tx_keyidx] <=
+ 40)
+ tfd->u.data.key_index |= DCT_WEP_KEY_64Bit;
+ else
+ tfd->u.data.key_index |= DCT_WEP_KEY_128Bit;
+ break;
+ case SEC_LEVEL_0:
+ break;
+ default:
+ printk(KERN_ERR "Unknow security level %d\n",
+ priv->ieee->sec.level);
+ break;
+ }
+ } else
+ /* No hardware encryption */
+ tfd->u.data.tx_flags |= DCT_FLAG_NO_WEP;
+
+#ifdef CONFIG_IPW_QOS
+ ipw_qos_set_tx_queue_command(priv, pri, &(tfd->u.data), unicast);
+#endif /* CONFIG_IPW_QOS */
+
/* payload */
- tfd->u.data.num_chunks = min((u8) (NUM_TFD_CHUNKS - 2), txb->nr_frags);
- for (i = 0; i < tfd->u.data.num_chunks; i++) {
+ tfd->u.data.num_chunks = cpu_to_le32(min((u8) (NUM_TFD_CHUNKS - 2),
+ txb->nr_frags));
+ IPW_DEBUG_FRAG("%i fragments being sent as %i chunks.\n",
+ txb->nr_frags, le32_to_cpu(tfd->u.data.num_chunks));
+ for (i = 0; i < le32_to_cpu(tfd->u.data.num_chunks); i++) {
+ IPW_DEBUG_FRAG("Adding fragment %i of %i (%d bytes).\n",
+ i, le32_to_cpu(tfd->u.data.num_chunks),
+ txb->fragments[i]->len - hdr_len);
IPW_DEBUG_TX("Dumping TX packet frag %i of %i (%d bytes):\n",
i, tfd->u.data.num_chunks,
txb->fragments[i]->len - hdr_len);
@@ -6399,11 +9770,13 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb)
txb->fragments[i]->len - hdr_len);
tfd->u.data.chunk_ptr[i] =
- pci_map_single(priv->pci_dev,
- txb->fragments[i]->data + hdr_len,
- txb->fragments[i]->len - hdr_len,
- PCI_DMA_TODEVICE);
- tfd->u.data.chunk_len[i] = txb->fragments[i]->len - hdr_len;
+ cpu_to_le32(pci_map_single
+ (priv->pci_dev,
+ txb->fragments[i]->data + hdr_len,
+ txb->fragments[i]->len - hdr_len,
+ PCI_DMA_TODEVICE));
+ tfd->u.data.chunk_len[i] =
+ cpu_to_le16(txb->fragments[i]->len - hdr_len);
}
if (i != txb->nr_frags) {
@@ -6418,9 +9791,10 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb)
remaining_bytes);
skb = alloc_skb(remaining_bytes, GFP_ATOMIC);
if (skb != NULL) {
- tfd->u.data.chunk_len[i] = remaining_bytes;
+ tfd->u.data.chunk_len[i] = cpu_to_le16(remaining_bytes);
for (j = i; j < txb->nr_frags; j++) {
int size = txb->fragments[j]->len - hdr_len;
+
printk(KERN_INFO "Adding frag %d %d...\n",
j, size);
memcpy(skb_put(skb, size),
@@ -6429,10 +9803,14 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb)
dev_kfree_skb_any(txb->fragments[i]);
txb->fragments[i] = skb;
tfd->u.data.chunk_ptr[i] =
- pci_map_single(priv->pci_dev, skb->data,
- tfd->u.data.chunk_len[i],
- PCI_DMA_TODEVICE);
- tfd->u.data.num_chunks++;
+ cpu_to_le32(pci_map_single
+ (priv->pci_dev, skb->data,
+ tfd->u.data.chunk_len[i],
+ PCI_DMA_TODEVICE));
+
+ tfd->u.data.num_chunks =
+ cpu_to_le32(le32_to_cpu(tfd->u.data.num_chunks) +
+ 1);
}
}
@@ -6440,14 +9818,28 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb)
q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd);
ipw_write32(priv, q->reg_w, q->first_empty);
- if (ipw_queue_space(q) < q->high_mark)
- netif_stop_queue(priv->net_dev);
-
- return;
+ return NETDEV_TX_OK;
drop:
IPW_DEBUG_DROP("Silently dropping Tx packet.\n");
ieee80211_txb_free(txb);
+ return NETDEV_TX_OK;
+}
+
+static int ipw_net_is_queue_full(struct net_device *dev, int pri)
+{
+ struct ipw_priv *priv = ieee80211_priv(dev);
+#ifdef CONFIG_IPW_QOS
+ int tx_id = ipw_get_tx_queue_number(priv, pri);
+ struct clx2_tx_queue *txq = &priv->txq[tx_id];
+#else
+ struct clx2_tx_queue *txq = &priv->txq[0];
+#endif /* CONFIG_IPW_QOS */
+
+ if (ipw_queue_space(&txq->q) < txq->q.high_mark)
+ return 1;
+
+ return 0;
}
static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb,
@@ -6455,9 +9847,9 @@ static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb,
{
struct ipw_priv *priv = ieee80211_priv(dev);
unsigned long flags;
+ int ret;
IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size);
-
spin_lock_irqsave(&priv->lock, flags);
if (!(priv->status & STATUS_ASSOCIATED)) {
@@ -6467,10 +9859,12 @@ static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb,
goto fail_unlock;
}
- ipw_tx_skb(priv, txb);
-
+ ret = ipw_tx_skb(priv, txb, pri);
+ if (ret == NETDEV_TX_OK)
+ __ipw_led_activity_on(priv);
spin_unlock_irqrestore(&priv->lock, flags);
- return 0;
+
+ return ret;
fail_unlock:
spin_unlock_irqrestore(&priv->lock, flags);
@@ -6497,11 +9891,13 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p)
struct sockaddr *addr = p;
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
+ down(&priv->sem);
priv->config |= CFG_CUSTOM_MAC;
memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n",
priv->net_dev->name, MAC_ARG(priv->mac_addr));
- ipw_adapter_restart(priv);
+ queue_work(priv->workqueue, &priv->adapter_restart);
+ up(&priv->sem);
return 0;
}
@@ -6524,7 +9920,7 @@ static void ipw_ethtool_get_drvinfo(struct net_device *dev,
snprintf(info->fw_version, sizeof(info->fw_version), "%s (%s)",
vers, date);
strcpy(info->bus_info, pci_name(p->pci_dev));
- info->eedump_len = CX2_EEPROM_IMAGE_SIZE;
+ info->eedump_len = IPW_EEPROM_IMAGE_SIZE;
}
static u32 ipw_ethtool_get_link(struct net_device *dev)
@@ -6535,7 +9931,7 @@ static u32 ipw_ethtool_get_link(struct net_device *dev)
static int ipw_ethtool_get_eeprom_len(struct net_device *dev)
{
- return CX2_EEPROM_IMAGE_SIZE;
+ return IPW_EEPROM_IMAGE_SIZE;
}
static int ipw_ethtool_get_eeprom(struct net_device *dev,
@@ -6543,10 +9939,11 @@ static int ipw_ethtool_get_eeprom(struct net_device *dev,
{
struct ipw_priv *p = ieee80211_priv(dev);
- if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE)
+ if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE)
return -EINVAL;
-
- memcpy(bytes, &((u8 *) p->eeprom)[eeprom->offset], eeprom->len);
+ down(&p->sem);
+ memcpy(bytes, &p->eeprom[eeprom->offset], eeprom->len);
+ up(&p->sem);
return 0;
}
@@ -6556,23 +9953,23 @@ static int ipw_ethtool_set_eeprom(struct net_device *dev,
struct ipw_priv *p = ieee80211_priv(dev);
int i;
- if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE)
+ if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE)
return -EINVAL;
-
- memcpy(&((u8 *) p->eeprom)[eeprom->offset], bytes, eeprom->len);
+ down(&p->sem);
+ memcpy(&p->eeprom[eeprom->offset], bytes, eeprom->len);
for (i = IPW_EEPROM_DATA;
- i < IPW_EEPROM_DATA + CX2_EEPROM_IMAGE_SIZE; i++)
+ i < IPW_EEPROM_DATA + IPW_EEPROM_IMAGE_SIZE; i++)
ipw_write8(p, i, p->eeprom[i]);
-
+ up(&p->sem);
return 0;
}
static struct ethtool_ops ipw_ethtool_ops = {
- .get_link = ipw_ethtool_get_link,
- .get_drvinfo = ipw_ethtool_get_drvinfo,
- .get_eeprom_len = ipw_ethtool_get_eeprom_len,
- .get_eeprom = ipw_ethtool_get_eeprom,
- .set_eeprom = ipw_ethtool_set_eeprom,
+ .get_link = ipw_ethtool_get_link,
+ .get_drvinfo = ipw_ethtool_get_drvinfo,
+ .get_eeprom_len = ipw_ethtool_get_eeprom_len,
+ .get_eeprom = ipw_ethtool_get_eeprom,
+ .set_eeprom = ipw_ethtool_set_eeprom,
};
static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs)
@@ -6590,8 +9987,8 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs)
goto none;
}
- inta = ipw_read32(priv, CX2_INTA_RW);
- inta_mask = ipw_read32(priv, CX2_INTA_MASK_R);
+ inta = ipw_read32(priv, IPW_INTA_RW);
+ inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
if (inta == 0xFFFFFFFF) {
/* Hardware disappeared */
@@ -6599,7 +9996,7 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs)
goto none;
}
- if (!(inta & (CX2_INTA_MASK_ALL & inta_mask))) {
+ if (!(inta & (IPW_INTA_MASK_ALL & inta_mask))) {
/* Shared interrupt */
goto none;
}
@@ -6608,8 +10005,8 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs)
ipw_disable_interrupts(priv);
/* ack current interrupts */
- inta &= (CX2_INTA_MASK_ALL & inta_mask);
- ipw_write32(priv, CX2_INTA_RW, inta);
+ inta &= (IPW_INTA_MASK_ALL & inta_mask);
+ ipw_write32(priv, IPW_INTA_RW, inta);
/* Cache INTA value for our tasklet */
priv->isr_inta = inta;
@@ -6655,28 +10052,116 @@ static void ipw_rf_kill(void *adapter)
spin_unlock_irqrestore(&priv->lock, flags);
}
+static void ipw_bg_rf_kill(void *data)
+{
+ struct ipw_priv *priv = data;
+ down(&priv->sem);
+ ipw_rf_kill(data);
+ up(&priv->sem);
+}
+
+void ipw_link_up(struct ipw_priv *priv)
+{
+ priv->last_seq_num = -1;
+ priv->last_frag_num = -1;
+ priv->last_packet_time = 0;
+
+ netif_carrier_on(priv->net_dev);
+ if (netif_queue_stopped(priv->net_dev)) {
+ IPW_DEBUG_NOTIF("waking queue\n");
+ netif_wake_queue(priv->net_dev);
+ } else {
+ IPW_DEBUG_NOTIF("starting queue\n");
+ netif_start_queue(priv->net_dev);
+ }
+
+ cancel_delayed_work(&priv->request_scan);
+ ipw_reset_stats(priv);
+ /* Ensure the rate is updated immediately */
+ priv->last_rate = ipw_get_current_rate(priv);
+ ipw_gather_stats(priv);
+ ipw_led_link_up(priv);
+ notify_wx_assoc_event(priv);
+
+ if (priv->config & CFG_BACKGROUND_SCAN)
+ queue_delayed_work(priv->workqueue, &priv->request_scan, HZ);
+}
+
+static void ipw_bg_link_up(void *data)
+{
+ struct ipw_priv *priv = data;
+ down(&priv->sem);
+ ipw_link_up(data);
+ up(&priv->sem);
+}
+
+void ipw_link_down(struct ipw_priv *priv)
+{
+ ipw_led_link_down(priv);
+ netif_carrier_off(priv->net_dev);
+ netif_stop_queue(priv->net_dev);
+ notify_wx_assoc_event(priv);
+
+ /* Cancel any queued work ... */
+ cancel_delayed_work(&priv->request_scan);
+ cancel_delayed_work(&priv->adhoc_check);
+ cancel_delayed_work(&priv->gather_stats);
+
+ ipw_reset_stats(priv);
+
+ if (!(priv->status & STATUS_EXIT_PENDING)) {
+ /* Queue up another scan... */
+ queue_work(priv->workqueue, &priv->request_scan);
+ }
+}
+
+static void ipw_bg_link_down(void *data)
+{
+ struct ipw_priv *priv = data;
+ down(&priv->sem);
+ ipw_link_down(data);
+ up(&priv->sem);
+}
+
static int ipw_setup_deferred_work(struct ipw_priv *priv)
{
int ret = 0;
priv->workqueue = create_workqueue(DRV_NAME);
init_waitqueue_head(&priv->wait_command_queue);
-
- INIT_WORK(&priv->adhoc_check, ipw_adhoc_check, priv);
- INIT_WORK(&priv->associate, ipw_associate, priv);
- INIT_WORK(&priv->disassociate, ipw_disassociate, priv);
- INIT_WORK(&priv->rx_replenish, ipw_rx_queue_replenish, priv);
- INIT_WORK(&priv->adapter_restart, ipw_adapter_restart, priv);
- INIT_WORK(&priv->rf_kill, ipw_rf_kill, priv);
- INIT_WORK(&priv->up, (void (*)(void *))ipw_up, priv);
- INIT_WORK(&priv->down, (void (*)(void *))ipw_down, priv);
+ init_waitqueue_head(&priv->wait_state);
+
+ INIT_WORK(&priv->adhoc_check, ipw_bg_adhoc_check, priv);
+ INIT_WORK(&priv->associate, ipw_bg_associate, priv);
+ INIT_WORK(&priv->disassociate, ipw_bg_disassociate, priv);
+ INIT_WORK(&priv->system_config, ipw_system_config, priv);
+ INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish, priv);
+ INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart, priv);
+ INIT_WORK(&priv->rf_kill, ipw_bg_rf_kill, priv);
+ INIT_WORK(&priv->up, (void (*)(void *))ipw_bg_up, priv);
+ INIT_WORK(&priv->down, (void (*)(void *))ipw_bg_down, priv);
INIT_WORK(&priv->request_scan,
(void (*)(void *))ipw_request_scan, priv);
INIT_WORK(&priv->gather_stats,
- (void (*)(void *))ipw_gather_stats, priv);
- INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_abort_scan, priv);
- INIT_WORK(&priv->roam, ipw_roam, priv);
- INIT_WORK(&priv->scan_check, ipw_scan_check, priv);
+ (void (*)(void *))ipw_bg_gather_stats, priv);
+ INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_bg_abort_scan, priv);
+ INIT_WORK(&priv->roam, ipw_bg_roam, priv);
+ INIT_WORK(&priv->scan_check, ipw_bg_scan_check, priv);
+ INIT_WORK(&priv->link_up, (void (*)(void *))ipw_bg_link_up, priv);
+ INIT_WORK(&priv->link_down, (void (*)(void *))ipw_bg_link_down, priv);
+ INIT_WORK(&priv->led_link_on, (void (*)(void *))ipw_bg_led_link_on,
+ priv);
+ INIT_WORK(&priv->led_link_off, (void (*)(void *))ipw_bg_led_link_off,
+ priv);
+ INIT_WORK(&priv->led_act_off, (void (*)(void *))ipw_bg_led_activity_off,
+ priv);
+ INIT_WORK(&priv->merge_networks,
+ (void (*)(void *))ipw_merge_adhoc_network, priv);
+
+#ifdef CONFIG_IPW_QOS
+ INIT_WORK(&priv->qos_activate, (void (*)(void *))ipw_bg_qos_activate,
+ priv);
+#endif /* CONFIG_IPW_QOS */
tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
ipw_irq_tasklet, (unsigned long)priv);
@@ -6689,34 +10174,36 @@ static void shim__set_security(struct net_device *dev,
{
struct ipw_priv *priv = ieee80211_priv(dev);
int i;
-
for (i = 0; i < 4; i++) {
if (sec->flags & (1 << i)) {
- priv->sec.key_sizes[i] = sec->key_sizes[i];
+ priv->ieee->sec.encode_alg[i] = sec->encode_alg[i];
+ priv->ieee->sec.key_sizes[i] = sec->key_sizes[i];
if (sec->key_sizes[i] == 0)
- priv->sec.flags &= ~(1 << i);
- else
- memcpy(priv->sec.keys[i], sec->keys[i],
+ priv->ieee->sec.flags &= ~(1 << i);
+ else {
+ memcpy(priv->ieee->sec.keys[i], sec->keys[i],
sec->key_sizes[i]);
- priv->sec.flags |= (1 << i);
+ priv->ieee->sec.flags |= (1 << i);
+ }
priv->status |= STATUS_SECURITY_UPDATED;
- }
+ } else if (sec->level != SEC_LEVEL_1)
+ priv->ieee->sec.flags &= ~(1 << i);
}
- if ((sec->flags & SEC_ACTIVE_KEY) &&
- priv->sec.active_key != sec->active_key) {
+ if (sec->flags & SEC_ACTIVE_KEY) {
if (sec->active_key <= 3) {
- priv->sec.active_key = sec->active_key;
- priv->sec.flags |= SEC_ACTIVE_KEY;
+ priv->ieee->sec.active_key = sec->active_key;
+ priv->ieee->sec.flags |= SEC_ACTIVE_KEY;
} else
- priv->sec.flags &= ~SEC_ACTIVE_KEY;
+ priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY;
priv->status |= STATUS_SECURITY_UPDATED;
- }
+ } else
+ priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY;
if ((sec->flags & SEC_AUTH_MODE) &&
- (priv->sec.auth_mode != sec->auth_mode)) {
- priv->sec.auth_mode = sec->auth_mode;
- priv->sec.flags |= SEC_AUTH_MODE;
+ (priv->ieee->sec.auth_mode != sec->auth_mode)) {
+ priv->ieee->sec.auth_mode = sec->auth_mode;
+ priv->ieee->sec.flags |= SEC_AUTH_MODE;
if (sec->auth_mode == WLAN_AUTH_SHARED_KEY)
priv->capability |= CAP_SHARED_KEY;
else
@@ -6724,9 +10211,9 @@ static void shim__set_security(struct net_device *dev,
priv->status |= STATUS_SECURITY_UPDATED;
}
- if (sec->flags & SEC_ENABLED && priv->sec.enabled != sec->enabled) {
- priv->sec.flags |= SEC_ENABLED;
- priv->sec.enabled = sec->enabled;
+ if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) {
+ priv->ieee->sec.flags |= SEC_ENABLED;
+ priv->ieee->sec.enabled = sec->enabled;
priv->status |= STATUS_SECURITY_UPDATED;
if (sec->enabled)
priv->capability |= CAP_PRIVACY_ON;
@@ -6734,12 +10221,18 @@ static void shim__set_security(struct net_device *dev,
priv->capability &= ~CAP_PRIVACY_ON;
}
- if (sec->flags & SEC_LEVEL && priv->sec.level != sec->level) {
- priv->sec.level = sec->level;
- priv->sec.flags |= SEC_LEVEL;
+ if (sec->flags & SEC_ENCRYPT)
+ priv->ieee->sec.encrypt = sec->encrypt;
+
+ if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) {
+ priv->ieee->sec.level = sec->level;
+ priv->ieee->sec.flags |= SEC_LEVEL;
priv->status |= STATUS_SECURITY_UPDATED;
}
+ if (!priv->ieee->host_encrypt && (sec->flags & SEC_ENCRYPT))
+ ipw_set_hwcrypto_keys(priv);
+
/* To match current functionality of ipw2100 (which works well w/
* various supplicants, we don't force a disassociate if the
* privacy capability changes ... */
@@ -6788,29 +10281,10 @@ static int init_supported_rates(struct ipw_priv *priv,
static int ipw_config(struct ipw_priv *priv)
{
- int i;
- struct ipw_tx_power tx_power;
-
- memset(&priv->sys_config, 0, sizeof(priv->sys_config));
- memset(&tx_power, 0, sizeof(tx_power));
-
/* This is only called from ipw_up, which resets/reloads the firmware
so, we don't need to first disable the card before we configure
it */
-
- /* configure device for 'G' band */
- tx_power.ieee_mode = IPW_G_MODE;
- tx_power.num_channels = 11;
- for (i = 0; i < 11; i++) {
- tx_power.channels_tx_power[i].channel_number = i + 1;
- tx_power.channels_tx_power[i].tx_power = priv->tx_power;
- }
- if (ipw_send_tx_power(priv, &tx_power))
- goto error;
-
- /* configure device to also handle 'B' band */
- tx_power.ieee_mode = IPW_B_MODE;
- if (ipw_send_tx_power(priv, &tx_power))
+ if (ipw_set_tx_power(priv))
goto error;
/* initialize adapter address */
@@ -6819,6 +10293,11 @@ static int ipw_config(struct ipw_priv *priv)
/* set basic system config settings */
init_sys_config(&priv->sys_config);
+ if (priv->ieee->iw_mode == IW_MODE_ADHOC)
+ priv->sys_config.answer_broadcast_ssid_probe = 1;
+ else
+ priv->sys_config.answer_broadcast_ssid_probe = 0;
+
if (ipw_send_system_config(priv, &priv->sys_config))
goto error;
@@ -6831,6 +10310,10 @@ static int ipw_config(struct ipw_priv *priv)
if (ipw_send_rts_threshold(priv, priv->rts_threshold))
goto error;
}
+#ifdef CONFIG_IPW_QOS
+ IPW_DEBUG_QOS("QoS: call ipw_qos_activate\n");
+ ipw_qos_activate(priv, NULL);
+#endif /* CONFIG_IPW_QOS */
if (ipw_set_random_seed(priv))
goto error;
@@ -6839,9 +10322,17 @@ static int ipw_config(struct ipw_priv *priv)
if (ipw_send_host_complete(priv))
goto error;
- /* If configured to try and auto-associate, kick off a scan */
- if ((priv->config & CFG_ASSOCIATE) && ipw_request_scan(priv))
- goto error;
+ priv->status |= STATUS_INIT;
+
+ ipw_led_init(priv);
+ ipw_led_radio_on(priv);
+ priv->notif_missed_beacons = 0;
+
+ /* Set hardware WEP key if it is configured. */
+ if ((priv->capability & CAP_PRIVACY_ON) &&
+ (priv->ieee->sec.level == SEC_LEVEL_1) &&
+ !(priv->ieee->host_encrypt || priv->ieee->host_decrypt))
+ ipw_set_hwcrypto_keys(priv);
return 0;
@@ -6849,20 +10340,379 @@ static int ipw_config(struct ipw_priv *priv)
return -EIO;
}
+/*
+ * NOTE:
+ *
+ * These tables have been tested in conjunction with the
+ * Intel PRO/Wireless 2200BG and 2915ABG Network Connection Adapters.
+ *
+ * Altering this values, using it on other hardware, or in geographies
+ * not intended for resale of the above mentioned Intel adapters has
+ * not been tested.
+ *
+ */
+static const struct ieee80211_geo ipw_geos[] = {
+ { /* Restricted */
+ "---",
+ .bg_channels = 11,
+ .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+ {2427, 4}, {2432, 5}, {2437, 6},
+ {2442, 7}, {2447, 8}, {2452, 9},
+ {2457, 10}, {2462, 11}},
+ },
+
+ { /* Custom US/Canada */
+ "ZZF",
+ .bg_channels = 11,
+ .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+ {2427, 4}, {2432, 5}, {2437, 6},
+ {2442, 7}, {2447, 8}, {2452, 9},
+ {2457, 10}, {2462, 11}},
+ .a_channels = 8,
+ .a = {{5180, 36},
+ {5200, 40},
+ {5220, 44},
+ {5240, 48},
+ {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
+ {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
+ {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
+ {5320, 64, IEEE80211_CH_PASSIVE_ONLY}},
+ },
+
+ { /* Rest of World */
+ "ZZD",
+ .bg_channels = 13,
+ .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+ {2427, 4}, {2432, 5}, {2437, 6},
+ {2442, 7}, {2447, 8}, {2452, 9},
+ {2457, 10}, {2462, 11}, {2467, 12},
+ {2472, 13}},
+ },
+
+ { /* Custom USA & Europe & High */
+ "ZZA",
+ .bg_channels = 11,
+ .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+ {2427, 4}, {2432, 5}, {2437, 6},
+ {2442, 7}, {2447, 8}, {2452, 9},
+ {2457, 10}, {2462, 11}},
+ .a_channels = 13,
+ .a = {{5180, 36},
+ {5200, 40},
+ {5220, 44},
+ {5240, 48},
+ {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
+ {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
+ {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
+ {5320, 64, IEEE80211_CH_PASSIVE_ONLY},
+ {5745, 149},
+ {5765, 153},
+ {5785, 157},
+ {5805, 161},
+ {5825, 165}},
+ },
+
+ { /* Custom NA & Europe */
+ "ZZB",
+ .bg_channels = 11,
+ .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+ {2427, 4}, {2432, 5}, {2437, 6},
+ {2442, 7}, {2447, 8}, {2452, 9},
+ {2457, 10}, {2462, 11}},
+ .a_channels = 13,
+ .a = {{5180, 36},
+ {5200, 40},
+ {5220, 44},
+ {5240, 48},
+ {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
+ {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
+ {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
+ {5320, 64, IEEE80211_CH_PASSIVE_ONLY},
+ {5745, 149, IEEE80211_CH_PASSIVE_ONLY},
+ {5765, 153, IEEE80211_CH_PASSIVE_ONLY},
+ {5785, 157, IEEE80211_CH_PASSIVE_ONLY},
+ {5805, 161, IEEE80211_CH_PASSIVE_ONLY},
+ {5825, 165, IEEE80211_CH_PASSIVE_ONLY}},
+ },
+
+ { /* Custom Japan */
+ "ZZC",
+ .bg_channels = 11,
+ .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+ {2427, 4}, {2432, 5}, {2437, 6},
+ {2442, 7}, {2447, 8}, {2452, 9},
+ {2457, 10}, {2462, 11}},
+ .a_channels = 4,
+ .a = {{5170, 34}, {5190, 38},
+ {5210, 42}, {5230, 46}},
+ },
+
+ { /* Custom */
+ "ZZM",
+ .bg_channels = 11,
+ .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+ {2427, 4}, {2432, 5}, {2437, 6},
+ {2442, 7}, {2447, 8}, {2452, 9},
+ {2457, 10}, {2462, 11}},
+ },
+
+ { /* Europe */
+ "ZZE",
+ .bg_channels = 13,
+ .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+ {2427, 4}, {2432, 5}, {2437, 6},
+ {2442, 7}, {2447, 8}, {2452, 9},
+ {2457, 10}, {2462, 11}, {2467, 12},
+ {2472, 13}},
+ .a_channels = 19,
+ .a = {{5180, 36},
+ {5200, 40},
+ {5220, 44},
+ {5240, 48},
+ {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
+ {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
+ {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
+ {5320, 64, IEEE80211_CH_PASSIVE_ONLY},
+ {5500, 100, IEEE80211_CH_PASSIVE_ONLY},
+ {5520, 104, IEEE80211_CH_PASSIVE_ONLY},
+ {5540, 108, IEEE80211_CH_PASSIVE_ONLY},
+ {5560, 112, IEEE80211_CH_PASSIVE_ONLY},
+ {5580, 116, IEEE80211_CH_PASSIVE_ONLY},
+ {5600, 120, IEEE80211_CH_PASSIVE_ONLY},
+ {5620, 124, IEEE80211_CH_PASSIVE_ONLY},
+ {5640, 128, IEEE80211_CH_PASSIVE_ONLY},
+ {5660, 132, IEEE80211_CH_PASSIVE_ONLY},
+ {5680, 136, IEEE80211_CH_PASSIVE_ONLY},
+ {5700, 140, IEEE80211_CH_PASSIVE_ONLY}},
+ },
+
+ { /* Custom Japan */
+ "ZZJ",
+ .bg_channels = 14,
+ .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+ {2427, 4}, {2432, 5}, {2437, 6},
+ {2442, 7}, {2447, 8}, {2452, 9},
+ {2457, 10}, {2462, 11}, {2467, 12},
+ {2472, 13}, {2484, 14, IEEE80211_CH_B_ONLY}},
+ .a_channels = 4,
+ .a = {{5170, 34}, {5190, 38},
+ {5210, 42}, {5230, 46}},
+ },
+
+ { /* Rest of World */
+ "ZZR",
+ .bg_channels = 14,
+ .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+ {2427, 4}, {2432, 5}, {2437, 6},
+ {2442, 7}, {2447, 8}, {2452, 9},
+ {2457, 10}, {2462, 11}, {2467, 12},
+ {2472, 13}, {2484, 14, IEEE80211_CH_B_ONLY |
+ IEEE80211_CH_PASSIVE_ONLY}},
+ },
+
+ { /* High Band */
+ "ZZH",
+ .bg_channels = 13,
+ .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+ {2427, 4}, {2432, 5}, {2437, 6},
+ {2442, 7}, {2447, 8}, {2452, 9},
+ {2457, 10}, {2462, 11},
+ {2467, 12, IEEE80211_CH_PASSIVE_ONLY},
+ {2472, 13, IEEE80211_CH_PASSIVE_ONLY}},
+ .a_channels = 4,
+ .a = {{5745, 149}, {5765, 153},
+ {5785, 157}, {5805, 161}},
+ },
+
+ { /* Custom Europe */
+ "ZZG",
+ .bg_channels = 13,
+ .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+ {2427, 4}, {2432, 5}, {2437, 6},
+ {2442, 7}, {2447, 8}, {2452, 9},
+ {2457, 10}, {2462, 11},
+ {2467, 12}, {2472, 13}},
+ .a_channels = 4,
+ .a = {{5180, 36}, {5200, 40},
+ {5220, 44}, {5240, 48}},
+ },
+
+ { /* Europe */
+ "ZZK",
+ .bg_channels = 13,
+ .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+ {2427, 4}, {2432, 5}, {2437, 6},
+ {2442, 7}, {2447, 8}, {2452, 9},
+ {2457, 10}, {2462, 11},
+ {2467, 12, IEEE80211_CH_PASSIVE_ONLY},
+ {2472, 13, IEEE80211_CH_PASSIVE_ONLY}},
+ .a_channels = 24,
+ .a = {{5180, 36, IEEE80211_CH_PASSIVE_ONLY},
+ {5200, 40, IEEE80211_CH_PASSIVE_ONLY},
+ {5220, 44, IEEE80211_CH_PASSIVE_ONLY},
+ {5240, 48, IEEE80211_CH_PASSIVE_ONLY},
+ {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
+ {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
+ {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
+ {5320, 64, IEEE80211_CH_PASSIVE_ONLY},
+ {5500, 100, IEEE80211_CH_PASSIVE_ONLY},
+ {5520, 104, IEEE80211_CH_PASSIVE_ONLY},
+ {5540, 108, IEEE80211_CH_PASSIVE_ONLY},
+ {5560, 112, IEEE80211_CH_PASSIVE_ONLY},
+ {5580, 116, IEEE80211_CH_PASSIVE_ONLY},
+ {5600, 120, IEEE80211_CH_PASSIVE_ONLY},
+ {5620, 124, IEEE80211_CH_PASSIVE_ONLY},
+ {5640, 128, IEEE80211_CH_PASSIVE_ONLY},
+ {5660, 132, IEEE80211_CH_PASSIVE_ONLY},
+ {5680, 136, IEEE80211_CH_PASSIVE_ONLY},
+ {5700, 140, IEEE80211_CH_PASSIVE_ONLY},
+ {5745, 149, IEEE80211_CH_PASSIVE_ONLY},
+ {5765, 153, IEEE80211_CH_PASSIVE_ONLY},
+ {5785, 157, IEEE80211_CH_PASSIVE_ONLY},
+ {5805, 161, IEEE80211_CH_PASSIVE_ONLY},
+ {5825, 165, IEEE80211_CH_PASSIVE_ONLY}},
+ },
+
+ { /* Europe */
+ "ZZL",
+ .bg_channels = 11,
+ .bg = {{2412, 1}, {2417, 2}, {2422, 3},
+ {2427, 4}, {2432, 5}, {2437, 6},
+ {2442, 7}, {2447, 8}, {2452, 9},
+ {2457, 10}, {2462, 11}},
+ .a_channels = 13,
+ .a = {{5180, 36, IEEE80211_CH_PASSIVE_ONLY},
+ {5200, 40, IEEE80211_CH_PASSIVE_ONLY},
+ {5220, 44, IEEE80211_CH_PASSIVE_ONLY},
+ {5240, 48, IEEE80211_CH_PASSIVE_ONLY},
+ {5260, 52, IEEE80211_CH_PASSIVE_ONLY},
+ {5280, 56, IEEE80211_CH_PASSIVE_ONLY},
+ {5300, 60, IEEE80211_CH_PASSIVE_ONLY},
+ {5320, 64, IEEE80211_CH_PASSIVE_ONLY},
+ {5745, 149, IEEE80211_CH_PASSIVE_ONLY},
+ {5765, 153, IEEE80211_CH_PASSIVE_ONLY},
+ {5785, 157, IEEE80211_CH_PASSIVE_ONLY},
+ {5805, 161, IEEE80211_CH_PASSIVE_ONLY},
+ {5825, 165, IEEE80211_CH_PASSIVE_ONLY}},
+ }
+};
+
+/* GEO code borrowed from ieee80211_geo.c */
+static int ipw_is_valid_channel(struct ieee80211_device *ieee, u8 channel)
+{
+ int i;
+
+ /* Driver needs to initialize the geography map before using
+ * these helper functions */
+ BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0);
+
+ if (ieee->freq_band & IEEE80211_24GHZ_BAND)
+ for (i = 0; i < ieee->geo.bg_channels; i++)
+ /* NOTE: If G mode is currently supported but
+ * this is a B only channel, we don't see it
+ * as valid. */
+ if ((ieee->geo.bg[i].channel == channel) &&
+ (!(ieee->mode & IEEE_G) ||
+ !(ieee->geo.bg[i].flags & IEEE80211_CH_B_ONLY)))
+ return IEEE80211_24GHZ_BAND;
+
+ if (ieee->freq_band & IEEE80211_52GHZ_BAND)
+ for (i = 0; i < ieee->geo.a_channels; i++)
+ if (ieee->geo.a[i].channel == channel)
+ return IEEE80211_52GHZ_BAND;
+
+ return 0;
+}
+
+static int ipw_channel_to_index(struct ieee80211_device *ieee, u8 channel)
+{
+ int i;
+
+ /* Driver needs to initialize the geography map before using
+ * these helper functions */
+ BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0);
+
+ if (ieee->freq_band & IEEE80211_24GHZ_BAND)
+ for (i = 0; i < ieee->geo.bg_channels; i++)
+ if (ieee->geo.bg[i].channel == channel)
+ return i;
+
+ if (ieee->freq_band & IEEE80211_52GHZ_BAND)
+ for (i = 0; i < ieee->geo.a_channels; i++)
+ if (ieee->geo.a[i].channel == channel)
+ return i;
+
+ return -1;
+}
+
+static u8 ipw_freq_to_channel(struct ieee80211_device *ieee, u32 freq)
+{
+ int i;
+
+ /* Driver needs to initialize the geography map before using
+ * these helper functions */
+ BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0);
+
+ freq /= 100000;
+
+ if (ieee->freq_band & IEEE80211_24GHZ_BAND)
+ for (i = 0; i < ieee->geo.bg_channels; i++)
+ if (ieee->geo.bg[i].freq == freq)
+ return ieee->geo.bg[i].channel;
+
+ if (ieee->freq_band & IEEE80211_52GHZ_BAND)
+ for (i = 0; i < ieee->geo.a_channels; i++)
+ if (ieee->geo.a[i].freq == freq)
+ return ieee->geo.a[i].channel;
+
+ return 0;
+}
+
+static int ipw_set_geo(struct ieee80211_device *ieee,
+ const struct ieee80211_geo *geo)
+{
+ memcpy(ieee->geo.name, geo->name, 3);
+ ieee->geo.name[3] = '\0';
+ ieee->geo.bg_channels = geo->bg_channels;
+ ieee->geo.a_channels = geo->a_channels;
+ memcpy(ieee->geo.bg, geo->bg, geo->bg_channels *
+ sizeof(struct ieee80211_channel));
+ memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels *
+ sizeof(struct ieee80211_channel));
+ return 0;
+}
+
+static const struct ieee80211_geo *ipw_get_geo(struct ieee80211_device *ieee)
+{
+ return &ieee->geo;
+}
+
#define MAX_HW_RESTARTS 5
static int ipw_up(struct ipw_priv *priv)
{
- int rc, i;
+ int rc, i, j;
if (priv->status & STATUS_EXIT_PENDING)
return -EIO;
+ if (cmdlog && !priv->cmdlog) {
+ priv->cmdlog = kmalloc(sizeof(*priv->cmdlog) * cmdlog,
+ GFP_KERNEL);
+ if (priv->cmdlog == NULL) {
+ IPW_ERROR("Error allocating %d command log entries.\n",
+ cmdlog);
+ } else {
+ memset(priv->cmdlog, 0, sizeof(*priv->cmdlog) * cmdlog);
+ priv->cmdlog_len = cmdlog;
+ }
+ }
+
for (i = 0; i < MAX_HW_RESTARTS; i++) {
/* Load the microcode, firmware, and eeprom.
* Also start the clocks. */
rc = ipw_load(priv);
if (rc) {
- IPW_ERROR("Unable to load firmware: 0x%08X\n", rc);
+ IPW_ERROR("Unable to load firmware: %d\n", rc);
return rc;
}
@@ -6871,20 +10721,50 @@ static int ipw_up(struct ipw_priv *priv)
eeprom_parse_mac(priv, priv->mac_addr);
memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
- if (priv->status & STATUS_RF_KILL_MASK)
+ for (j = 0; j < ARRAY_SIZE(ipw_geos); j++) {
+ if (!memcmp(&priv->eeprom[EEPROM_COUNTRY_CODE],
+ ipw_geos[j].name, 3))
+ break;
+ }
+ if (j == ARRAY_SIZE(ipw_geos)) {
+ IPW_WARNING("SKU [%c%c%c] not recognized.\n",
+ priv->eeprom[EEPROM_COUNTRY_CODE + 0],
+ priv->eeprom[EEPROM_COUNTRY_CODE + 1],
+ priv->eeprom[EEPROM_COUNTRY_CODE + 2]);
+ j = 0;
+ }
+ if (ipw_set_geo(priv->ieee, &ipw_geos[j])) {
+ IPW_WARNING("Could not set geography.");
+ return 0;
+ }
+
+ IPW_DEBUG_INFO("Geography %03d [%s] detected.\n",
+ j, priv->ieee->geo.name);
+
+ if (priv->status & STATUS_RF_KILL_SW) {
+ IPW_WARNING("Radio disabled by module parameter.\n");
+ return 0;
+ } else if (rf_kill_active(priv)) {
+ IPW_WARNING("Radio Frequency Kill Switch is On:\n"
+ "Kill switch must be turned off for "
+ "wireless networking to work.\n");
+ queue_delayed_work(priv->workqueue, &priv->rf_kill,
+ 2 * HZ);
return 0;
+ }
rc = ipw_config(priv);
if (!rc) {
IPW_DEBUG_INFO("Configured device on count %i\n", i);
- priv->notif_missed_beacons = 0;
- netif_start_queue(priv->net_dev);
+
+ /* If configure to try and auto-associate, kick
+ * off a scan. */
+ queue_work(priv->workqueue, &priv->request_scan);
+
return 0;
- } else {
- IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n",
- rc);
}
+ IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n", rc);
IPW_DEBUG_INFO("Failed to config device on retry %d of %d\n",
i, MAX_HW_RESTARTS);
@@ -6896,47 +10776,101 @@ static int ipw_up(struct ipw_priv *priv)
/* tried to restart and config the device for as long as our
* patience could withstand */
IPW_ERROR("Unable to initialize device after %d attempts.\n", i);
+
return -EIO;
}
-static void ipw_down(struct ipw_priv *priv)
+static void ipw_bg_up(void *data)
+{
+ struct ipw_priv *priv = data;
+ down(&priv->sem);
+ ipw_up(data);
+ up(&priv->sem);
+}
+
+static void ipw_deinit(struct ipw_priv *priv)
{
+ int i;
+
+ if (priv->status & STATUS_SCANNING) {
+ IPW_DEBUG_INFO("Aborting scan during shutdown.\n");
+ ipw_abort_scan(priv);
+ }
+
+ if (priv->status & STATUS_ASSOCIATED) {
+ IPW_DEBUG_INFO("Disassociating during shutdown.\n");
+ ipw_disassociate(priv);
+ }
+
+ ipw_led_shutdown(priv);
+
+ /* Wait up to 1s for status to change to not scanning and not
+ * associated (disassociation can take a while for a ful 802.11
+ * exchange */
+ for (i = 1000; i && (priv->status &
+ (STATUS_DISASSOCIATING |
+ STATUS_ASSOCIATED | STATUS_SCANNING)); i--)
+ udelay(10);
+
+ if (priv->status & (STATUS_DISASSOCIATING |
+ STATUS_ASSOCIATED | STATUS_SCANNING))
+ IPW_DEBUG_INFO("Still associated or scanning...\n");
+ else
+ IPW_DEBUG_INFO("Took %dms to de-init\n", 1000 - i);
+
/* Attempt to disable the card */
-#if 0
ipw_send_card_disable(priv, 0);
-#endif
+
+ priv->status &= ~STATUS_INIT;
+}
+
+static void ipw_down(struct ipw_priv *priv)
+{
+ int exit_pending = priv->status & STATUS_EXIT_PENDING;
+
+ priv->status |= STATUS_EXIT_PENDING;
+
+ if (ipw_is_init(priv))
+ ipw_deinit(priv);
+
+ /* Wipe out the EXIT_PENDING status bit if we are not actually
+ * exiting the module */
+ if (!exit_pending)
+ priv->status &= ~STATUS_EXIT_PENDING;
/* tell the device to stop sending interrupts */
ipw_disable_interrupts(priv);
/* Clear all bits but the RF Kill */
- priv->status &= STATUS_RF_KILL_MASK;
-
+ priv->status &= STATUS_RF_KILL_MASK | STATUS_EXIT_PENDING;
netif_carrier_off(priv->net_dev);
netif_stop_queue(priv->net_dev);
ipw_stop_nic(priv);
+
+ ipw_led_radio_off(priv);
+}
+
+static void ipw_bg_down(void *data)
+{
+ struct ipw_priv *priv = data;
+ down(&priv->sem);
+ ipw_down(data);
+ up(&priv->sem);
}
/* Called by register_netdev() */
static int ipw_net_init(struct net_device *dev)
{
struct ipw_priv *priv = ieee80211_priv(dev);
+ down(&priv->sem);
- if (priv->status & STATUS_RF_KILL_SW) {
- IPW_WARNING("Radio disabled by module parameter.\n");
- return 0;
- } else if (rf_kill_active(priv)) {
- IPW_WARNING("Radio Frequency Kill Switch is On:\n"
- "Kill switch must be turned off for "
- "wireless networking to work.\n");
- queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ);
- return 0;
- }
-
- if (ipw_up(priv))
+ if (ipw_up(priv)) {
+ up(&priv->sem);
return -EIO;
+ }
+ up(&priv->sem);
return 0;
}
@@ -6961,7 +10895,7 @@ static struct pci_device_id card_ids[] = {
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0},
{PCI_VENDOR_ID_INTEL, 0x104f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_INTEL, 0x4220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */
- {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* 2225BG */
+ {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */
{PCI_VENDOR_ID_INTEL, 0x4223, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */
{PCI_VENDOR_ID_INTEL, 0x4224, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */
@@ -6981,11 +10915,16 @@ static struct attribute *ipw_sysfs_entries[] = {
&dev_attr_nic_type.attr,
&dev_attr_status.attr,
&dev_attr_cfg.attr,
- &dev_attr_dump_errors.attr,
- &dev_attr_dump_events.attr,
+ &dev_attr_error.attr,
+ &dev_attr_event_log.attr,
+ &dev_attr_cmd_log.attr,
&dev_attr_eeprom_delay.attr,
&dev_attr_ucode_version.attr,
&dev_attr_rtc.attr,
+ &dev_attr_scan_age.attr,
+ &dev_attr_led.attr,
+ &dev_attr_speed_scan.attr,
+ &dev_attr_net_stats.attr,
NULL
};
@@ -7001,7 +10940,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
void __iomem *base;
u32 length, val;
struct ipw_priv *priv;
- int band, modulation;
+ int i;
net_dev = alloc_ieee80211(sizeof(struct ipw_priv));
if (net_dev == NULL) {
@@ -7011,13 +10950,17 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
priv = ieee80211_priv(net_dev);
priv->ieee = netdev_priv(net_dev);
+
priv->net_dev = net_dev;
priv->pci_dev = pdev;
#ifdef CONFIG_IPW_DEBUG
ipw_debug_level = debug;
#endif
spin_lock_init(&priv->lock);
+ for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++)
+ INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
+ init_MUTEX(&priv->sem);
if (pci_enable_device(pdev)) {
err = -ENODEV;
goto out_free_ieee80211;
@@ -7064,90 +11007,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_iounmap;
}
- /* Initialize module parameter values here */
- if (ifname)
- strncpy(net_dev->name, ifname, IFNAMSIZ);
-
- if (associate)
- priv->config |= CFG_ASSOCIATE;
- else
- IPW_DEBUG_INFO("Auto associate disabled.\n");
-
- if (auto_create)
- priv->config |= CFG_ADHOC_CREATE;
- else
- IPW_DEBUG_INFO("Auto adhoc creation disabled.\n");
-
- if (disable) {
- priv->status |= STATUS_RF_KILL_SW;
- IPW_DEBUG_INFO("Radio disabled.\n");
- }
-
- if (channel != 0) {
- priv->config |= CFG_STATIC_CHANNEL;
- priv->channel = channel;
- IPW_DEBUG_INFO("Bind to static channel %d\n", channel);
- IPW_DEBUG_INFO("Bind to static channel %d\n", channel);
- /* TODO: Validate that provided channel is in range */
- }
-
- switch (mode) {
- case 1:
- priv->ieee->iw_mode = IW_MODE_ADHOC;
- break;
-#ifdef CONFIG_IPW_PROMISC
- case 2:
- priv->ieee->iw_mode = IW_MODE_MONITOR;
- break;
-#endif
- default:
- case 0:
- priv->ieee->iw_mode = IW_MODE_INFRA;
- break;
- }
-
- if ((priv->pci_dev->device == 0x4223) ||
- (priv->pci_dev->device == 0x4224)) {
- printk(KERN_INFO DRV_NAME
- ": Detected Intel PRO/Wireless 2915ABG Network "
- "Connection\n");
- priv->ieee->abg_true = 1;
- band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND;
- modulation = IEEE80211_OFDM_MODULATION |
- IEEE80211_CCK_MODULATION;
- priv->adapter = IPW_2915ABG;
- priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B;
- } else {
- if (priv->pci_dev->device == 0x4221)
- printk(KERN_INFO DRV_NAME
- ": Detected Intel PRO/Wireless 2225BG Network "
- "Connection\n");
- else
- printk(KERN_INFO DRV_NAME
- ": Detected Intel PRO/Wireless 2200BG Network "
- "Connection\n");
-
- priv->ieee->abg_true = 0;
- band = IEEE80211_24GHZ_BAND;
- modulation = IEEE80211_OFDM_MODULATION |
- IEEE80211_CCK_MODULATION;
- priv->adapter = IPW_2200BG;
- priv->ieee->mode = IEEE_G | IEEE_B;
- }
-
- priv->ieee->freq_band = band;
- priv->ieee->modulation = modulation;
-
- priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK;
-
- priv->missed_beacon_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT;
- priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT;
-
- priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
-
- /* If power management is turned on, default to AC mode */
- priv->power_mode = IPW_POWER_AC;
- priv->tx_power = IPW_DEFAULT_TX_POWER;
+ ipw_sw_reset(priv, 1);
err = request_irq(pdev->irq, ipw_isr, SA_SHIRQ, DRV_NAME, priv);
if (err) {
@@ -7158,8 +11018,20 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
SET_MODULE_OWNER(net_dev);
SET_NETDEV_DEV(net_dev, &pdev->dev);
+ down(&priv->sem);
+
priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit;
priv->ieee->set_security = shim__set_security;
+ priv->ieee->is_queue_full = ipw_net_is_queue_full;
+
+#ifdef CONFIG_IPW_QOS
+ priv->ieee->handle_probe_response = ipw_handle_beacon;
+ priv->ieee->handle_beacon = ipw_handle_probe_response;
+ priv->ieee->handle_assoc_response = ipw_handle_assoc_response;
+#endif /* CONFIG_IPW_QOS */
+
+ priv->ieee->perfect_rssi = -20;
+ priv->ieee->worst_rssi = -85;
net_dev->open = ipw_net_open;
net_dev->stop = ipw_net_stop;
@@ -7167,7 +11039,9 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
net_dev->get_stats = ipw_net_get_stats;
net_dev->set_multicast_list = ipw_net_set_multicast_list;
net_dev->set_mac_address = ipw_net_set_mac_address;
- net_dev->get_wireless_stats = ipw_get_wireless_stats;
+ priv->wireless_data.spy_data = &priv->ieee->spy_data;
+ priv->wireless_data.ieee80211 = priv->ieee;
+ net_dev->wireless_data = &priv->wireless_data;
net_dev->wireless_handlers = &ipw_wx_handler_def;
net_dev->ethtool_ops = &ipw_ethtool_ops;
net_dev->irq = pdev->irq;
@@ -7178,18 +11052,19 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group);
if (err) {
IPW_ERROR("failed to create sysfs device attributes\n");
+ up(&priv->sem);
goto out_release_irq;
}
+ up(&priv->sem);
err = register_netdev(net_dev);
if (err) {
IPW_ERROR("failed to register network device\n");
- goto out_remove_group;
+ goto out_remove_sysfs;
}
-
return 0;
- out_remove_group:
+ out_remove_sysfs:
sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
out_release_irq:
free_irq(pdev->irq, priv);
@@ -7212,14 +11087,19 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
static void ipw_pci_remove(struct pci_dev *pdev)
{
struct ipw_priv *priv = pci_get_drvdata(pdev);
+ struct list_head *p, *q;
+ int i;
+
if (!priv)
return;
- priv->status |= STATUS_EXIT_PENDING;
+ down(&priv->sem);
+ priv->status |= STATUS_EXIT_PENDING;
+ ipw_down(priv);
sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
- ipw_down(priv);
+ up(&priv->sem);
unregister_netdev(priv->net_dev);
@@ -7229,16 +11109,31 @@ static void ipw_pci_remove(struct pci_dev *pdev)
}
ipw_tx_queue_free(priv);
+ if (priv->cmdlog) {
+ kfree(priv->cmdlog);
+ priv->cmdlog = NULL;
+ }
/* ipw_down will ensure that there is no more pending work
* in the workqueue's, so we can safely remove them now. */
- if (priv->workqueue) {
- cancel_delayed_work(&priv->adhoc_check);
- cancel_delayed_work(&priv->gather_stats);
- cancel_delayed_work(&priv->request_scan);
- cancel_delayed_work(&priv->rf_kill);
- cancel_delayed_work(&priv->scan_check);
- destroy_workqueue(priv->workqueue);
- priv->workqueue = NULL;
+ cancel_delayed_work(&priv->adhoc_check);
+ cancel_delayed_work(&priv->gather_stats);
+ cancel_delayed_work(&priv->request_scan);
+ cancel_delayed_work(&priv->rf_kill);
+ cancel_delayed_work(&priv->scan_check);
+ destroy_workqueue(priv->workqueue);
+ priv->workqueue = NULL;
+
+ /* Free MAC hash list for ADHOC */
+ for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) {
+ list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
+ kfree(list_entry(p, struct ipw_ibss_seq, list));
+ list_del(p);
+ }
+ }
+
+ if (priv->error) {
+ ipw_free_error_log(priv->error);
+ priv->error = NULL;
}
free_irq(pdev->irq, priv);
@@ -7247,15 +11142,7 @@ static void ipw_pci_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
free_ieee80211(priv->net_dev);
-
-#ifdef CONFIG_PM
- if (fw_loaded) {
- release_firmware(bootfw);
- release_firmware(ucode);
- release_firmware(firmware);
- fw_loaded = 0;
- }
-#endif
+ free_firmware();
}
#ifdef CONFIG_PM
@@ -7287,13 +11174,10 @@ static int ipw_pci_resume(struct pci_dev *pdev)
printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name);
- pci_set_power_state(pdev, 0);
+ pci_set_power_state(pdev, PCI_D0);
pci_enable_device(pdev);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
- pci_restore_state(pdev, priv->pm_state);
-#else
pci_restore_state(pdev);
-#endif
+
/*
* Suspend/Resume resets the PCI configuration space, so we have to
* re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
@@ -7365,16 +11249,33 @@ MODULE_PARM_DESC(associate, "auto associate when scanning (default on)");
module_param(auto_create, int, 0444);
MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)");
+module_param(led, int, 0444);
+MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)\n");
+
module_param(debug, int, 0444);
MODULE_PARM_DESC(debug, "debug output mask");
module_param(channel, int, 0444);
MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])");
-module_param(ifname, charp, 0444);
-MODULE_PARM_DESC(ifname, "network device name (default eth%d)");
+#ifdef CONFIG_IPW_QOS
+module_param(qos_enable, int, 0444);
+MODULE_PARM_DESC(qos_enable, "enable all QoS functionalitis");
+
+module_param(qos_burst_enable, int, 0444);
+MODULE_PARM_DESC(qos_burst_enable, "enable QoS burst mode");
+
+module_param(qos_no_ack_mask, int, 0444);
+MODULE_PARM_DESC(qos_no_ack_mask, "mask Tx_Queue to no ack");
-#ifdef CONFIG_IPW_PROMISC
+module_param(burst_duration_CCK, int, 0444);
+MODULE_PARM_DESC(burst_duration_CCK, "set CCK burst value");
+
+module_param(burst_duration_OFDM, int, 0444);
+MODULE_PARM_DESC(burst_duration_OFDM, "set OFDM burst value");
+#endif /* CONFIG_IPW_QOS */
+
+#ifdef CONFIG_IPW2200_MONITOR
module_param(mode, int, 0444);
MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
#else
@@ -7382,5 +11283,12 @@ module_param(mode, int, 0444);
MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)");
#endif
+module_param(hwcrypto, int, 0444);
+MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default on)");
+
+module_param(cmdlog, int, 0444);
+MODULE_PARM_DESC(cmdlog,
+ "allocate a ring buffer for logging firmware commands");
+
module_exit(ipw_exit);
module_init(ipw_init);
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index e9cf32bf3e3..1c98db0652c 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved.
+ Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
This program is free software; you can redistribute it and/or modify it
under the terms of version 2 of the GNU General Public License as
@@ -34,7 +34,6 @@
#include <linux/config.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/ethtool.h>
@@ -50,6 +49,7 @@
#include <asm/io.h>
#include <net/ieee80211.h>
+#include <net/ieee80211_radiotap.h>
#define DRV_NAME "ipw2200"
@@ -161,6 +161,16 @@ enum connection_manager_assoc_states {
* TX Queue Flag Definitions
*/
+/* tx wep key definition */
+#define DCT_WEP_KEY_NOT_IMMIDIATE 0x00
+#define DCT_WEP_KEY_64Bit 0x40
+#define DCT_WEP_KEY_128Bit 0x80
+#define DCT_WEP_KEY_128bitIV 0xC0
+#define DCT_WEP_KEY_SIZE_MASK 0xC0
+
+#define DCT_WEP_KEY_INDEX_MASK 0x0F
+#define DCT_WEP_INDEX_USE_IMMEDIATE 0x20
+
/* abort attempt if mgmt frame is rx'd */
#define DCT_FLAG_ABORT_MGMT 0x01
@@ -168,7 +178,8 @@ enum connection_manager_assoc_states {
#define DCT_FLAG_CTS_REQUIRED 0x02
/* use short preamble */
-#define DCT_FLAG_SHORT_PREMBL 0x04
+#define DCT_FLAG_LONG_PREAMBLE 0x00
+#define DCT_FLAG_SHORT_PREAMBLE 0x04
/* RTS/CTS first */
#define DCT_FLAG_RTS_REQD 0x08
@@ -185,9 +196,23 @@ enum connection_manager_assoc_states {
/* ACK rx is expected to follow */
#define DCT_FLAG_ACK_REQD 0x80
+/* TX flags extension */
#define DCT_FLAG_EXT_MODE_CCK 0x01
#define DCT_FLAG_EXT_MODE_OFDM 0x00
+#define DCT_FLAG_EXT_SECURITY_WEP 0x00
+#define DCT_FLAG_EXT_SECURITY_NO DCT_FLAG_EXT_SECURITY_WEP
+#define DCT_FLAG_EXT_SECURITY_CKIP 0x04
+#define DCT_FLAG_EXT_SECURITY_CCM 0x08
+#define DCT_FLAG_EXT_SECURITY_TKIP 0x0C
+#define DCT_FLAG_EXT_SECURITY_MASK 0x0C
+
+#define DCT_FLAG_EXT_QOS_ENABLED 0x10
+
+#define DCT_FLAG_EXT_HC_NO_SIFS_PIFS 0x00
+#define DCT_FLAG_EXT_HC_SIFS 0x20
+#define DCT_FLAG_EXT_HC_PIFS 0x40
+
#define TX_RX_TYPE_MASK 0xFF
#define TX_FRAME_TYPE 0x00
#define TX_HOST_COMMAND_TYPE 0x01
@@ -233,6 +258,117 @@ enum connection_manager_assoc_states {
#define DCR_TYPE_SNIFFER 0x06
#define DCR_TYPE_MU_BSS DCR_TYPE_MU_ESS
+/* QoS definitions */
+
+#define CW_MIN_OFDM 15
+#define CW_MAX_OFDM 1023
+#define CW_MIN_CCK 31
+#define CW_MAX_CCK 1023
+
+#define QOS_TX0_CW_MIN_OFDM CW_MIN_OFDM
+#define QOS_TX1_CW_MIN_OFDM CW_MIN_OFDM
+#define QOS_TX2_CW_MIN_OFDM ( (CW_MIN_OFDM + 1) / 2 - 1 )
+#define QOS_TX3_CW_MIN_OFDM ( (CW_MIN_OFDM + 1) / 4 - 1 )
+
+#define QOS_TX0_CW_MIN_CCK CW_MIN_CCK
+#define QOS_TX1_CW_MIN_CCK CW_MIN_CCK
+#define QOS_TX2_CW_MIN_CCK ( (CW_MIN_CCK + 1) / 2 - 1 )
+#define QOS_TX3_CW_MIN_CCK ( (CW_MIN_CCK + 1) / 4 - 1 )
+
+#define QOS_TX0_CW_MAX_OFDM CW_MAX_OFDM
+#define QOS_TX1_CW_MAX_OFDM CW_MAX_OFDM
+#define QOS_TX2_CW_MAX_OFDM CW_MIN_OFDM
+#define QOS_TX3_CW_MAX_OFDM ( (CW_MIN_OFDM + 1) / 2 - 1 )
+
+#define QOS_TX0_CW_MAX_CCK CW_MAX_CCK
+#define QOS_TX1_CW_MAX_CCK CW_MAX_CCK
+#define QOS_TX2_CW_MAX_CCK CW_MIN_CCK
+#define QOS_TX3_CW_MAX_CCK ( (CW_MIN_CCK + 1) / 2 - 1 )
+
+#define QOS_TX0_AIFS (3 - QOS_AIFSN_MIN_VALUE)
+#define QOS_TX1_AIFS (7 - QOS_AIFSN_MIN_VALUE)
+#define QOS_TX2_AIFS (2 - QOS_AIFSN_MIN_VALUE)
+#define QOS_TX3_AIFS (2 - QOS_AIFSN_MIN_VALUE)
+
+#define QOS_TX0_ACM 0
+#define QOS_TX1_ACM 0
+#define QOS_TX2_ACM 0
+#define QOS_TX3_ACM 0
+
+#define QOS_TX0_TXOP_LIMIT_CCK 0
+#define QOS_TX1_TXOP_LIMIT_CCK 0
+#define QOS_TX2_TXOP_LIMIT_CCK 6016
+#define QOS_TX3_TXOP_LIMIT_CCK 3264
+
+#define QOS_TX0_TXOP_LIMIT_OFDM 0
+#define QOS_TX1_TXOP_LIMIT_OFDM 0
+#define QOS_TX2_TXOP_LIMIT_OFDM 3008
+#define QOS_TX3_TXOP_LIMIT_OFDM 1504
+
+#define DEF_TX0_CW_MIN_OFDM CW_MIN_OFDM
+#define DEF_TX1_CW_MIN_OFDM CW_MIN_OFDM
+#define DEF_TX2_CW_MIN_OFDM CW_MIN_OFDM
+#define DEF_TX3_CW_MIN_OFDM CW_MIN_OFDM
+
+#define DEF_TX0_CW_MIN_CCK CW_MIN_CCK
+#define DEF_TX1_CW_MIN_CCK CW_MIN_CCK
+#define DEF_TX2_CW_MIN_CCK CW_MIN_CCK
+#define DEF_TX3_CW_MIN_CCK CW_MIN_CCK
+
+#define DEF_TX0_CW_MAX_OFDM CW_MAX_OFDM
+#define DEF_TX1_CW_MAX_OFDM CW_MAX_OFDM
+#define DEF_TX2_CW_MAX_OFDM CW_MAX_OFDM
+#define DEF_TX3_CW_MAX_OFDM CW_MAX_OFDM
+
+#define DEF_TX0_CW_MAX_CCK CW_MAX_CCK
+#define DEF_TX1_CW_MAX_CCK CW_MAX_CCK
+#define DEF_TX2_CW_MAX_CCK CW_MAX_CCK
+#define DEF_TX3_CW_MAX_CCK CW_MAX_CCK
+
+#define DEF_TX0_AIFS 0
+#define DEF_TX1_AIFS 0
+#define DEF_TX2_AIFS 0
+#define DEF_TX3_AIFS 0
+
+#define DEF_TX0_ACM 0
+#define DEF_TX1_ACM 0
+#define DEF_TX2_ACM 0
+#define DEF_TX3_ACM 0
+
+#define DEF_TX0_TXOP_LIMIT_CCK 0
+#define DEF_TX1_TXOP_LIMIT_CCK 0
+#define DEF_TX2_TXOP_LIMIT_CCK 0
+#define DEF_TX3_TXOP_LIMIT_CCK 0
+
+#define DEF_TX0_TXOP_LIMIT_OFDM 0
+#define DEF_TX1_TXOP_LIMIT_OFDM 0
+#define DEF_TX2_TXOP_LIMIT_OFDM 0
+#define DEF_TX3_TXOP_LIMIT_OFDM 0
+
+#define QOS_QOS_SETS 3
+#define QOS_PARAM_SET_ACTIVE 0
+#define QOS_PARAM_SET_DEF_CCK 1
+#define QOS_PARAM_SET_DEF_OFDM 2
+
+#define CTRL_QOS_NO_ACK (0x0020)
+
+#define IPW_TX_QUEUE_1 1
+#define IPW_TX_QUEUE_2 2
+#define IPW_TX_QUEUE_3 3
+#define IPW_TX_QUEUE_4 4
+
+/* QoS sturctures */
+struct ipw_qos_info {
+ int qos_enable;
+ struct ieee80211_qos_parameters *def_qos_parm_OFDM;
+ struct ieee80211_qos_parameters *def_qos_parm_CCK;
+ u32 burst_duration_CCK;
+ u32 burst_duration_OFDM;
+ u16 qos_no_ack_mask;
+ int burst_enable;
+};
+
+/**************************************************************/
/**
* Generic queue structure
*
@@ -402,9 +538,9 @@ struct clx2_tx_queue {
#define RX_FREE_BUFFERS 32
#define RX_LOW_WATERMARK 8
-#define SUP_RATE_11A_MAX_NUM_CHANNELS (8)
-#define SUP_RATE_11B_MAX_NUM_CHANNELS (4)
-#define SUP_RATE_11G_MAX_NUM_CHANNELS (12)
+#define SUP_RATE_11A_MAX_NUM_CHANNELS 8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS 4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
// Used for passing to driver number of successes and failures per rate
struct rate_histogram {
@@ -453,6 +589,9 @@ struct notif_channel_result {
u8 uReserved;
} __attribute__ ((packed));
+#define SCAN_COMPLETED_STATUS_COMPLETE 1
+#define SCAN_COMPLETED_STATUS_ABORTED 2
+
struct notif_scan_complete {
u8 scan_type;
u8 num_channels;
@@ -563,8 +702,8 @@ struct ipw_rx_packet {
} __attribute__ ((packed));
#define IPW_RX_NOTIFICATION_SIZE sizeof(struct ipw_rx_header) + 12
-#define IPW_RX_FRAME_SIZE sizeof(struct ipw_rx_header) + \
- sizeof(struct ipw_rx_frame)
+#define IPW_RX_FRAME_SIZE (unsigned int)(sizeof(struct ipw_rx_header) + \
+ sizeof(struct ipw_rx_frame))
struct ipw_rx_mem_buffer {
dma_addr_t dma_addr;
@@ -657,6 +796,19 @@ struct ipw_multicast_addr {
u8 mac4[6];
} __attribute__ ((packed));
+#define DCW_WEP_KEY_INDEX_MASK 0x03 /* bits [0:1] */
+#define DCW_WEP_KEY_SEC_TYPE_MASK 0x30 /* bits [4:5] */
+
+#define DCW_WEP_KEY_SEC_TYPE_WEP 0x00
+#define DCW_WEP_KEY_SEC_TYPE_CCM 0x20
+#define DCW_WEP_KEY_SEC_TYPE_TKIP 0x30
+
+#define DCW_WEP_KEY_INVALID_SIZE 0x00 /* 0 = Invalid key */
+#define DCW_WEP_KEY64Bit_SIZE 0x05 /* 64-bit encryption */
+#define DCW_WEP_KEY128Bit_SIZE 0x0D /* 128-bit encryption */
+#define DCW_CCM_KEY128Bit_SIZE 0x10 /* 128-bit key */
+//#define DCW_WEP_KEY128BitIV_SIZE 0x10 /* 128-bit key and 128-bit IV */
+
struct ipw_wep_key {
u8 cmd_id;
u8 seq_num;
@@ -818,14 +970,6 @@ struct ipw_tx_power {
struct ipw_channel_tx_power channels_tx_power[MAX_A_CHANNELS];
} __attribute__ ((packed));
-struct ipw_qos_parameters {
- u16 cw_min[4];
- u16 cw_max[4];
- u8 aifs[4];
- u8 flag[4];
- u16 tx_op_limit[4];
-} __attribute__ ((packed));
-
struct ipw_rsn_capabilities {
u8 id;
u8 length;
@@ -888,6 +1032,10 @@ struct ipw_cmd {
#define STATUS_SCAN_PENDING (1<<20)
#define STATUS_SCANNING (1<<21)
#define STATUS_SCAN_ABORTING (1<<22)
+#define STATUS_SCAN_FORCED (1<<23)
+
+#define STATUS_LED_LINK_ON (1<<24)
+#define STATUS_LED_ACT_ON (1<<25)
#define STATUS_INDIRECT_BYTE (1<<28) /* sysfs entry configured for access */
#define STATUS_INDIRECT_DWORD (1<<29) /* sysfs entry configured for access */
@@ -899,11 +1047,15 @@ struct ipw_cmd {
#define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */
#define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */
#define CFG_CUSTOM_MAC (1<<3)
-#define CFG_PREAMBLE (1<<4)
+#define CFG_PREAMBLE_LONG (1<<4)
#define CFG_ADHOC_PERSIST (1<<5)
#define CFG_ASSOCIATE (1<<6)
#define CFG_FIXED_RATE (1<<7)
#define CFG_ADHOC_CREATE (1<<8)
+#define CFG_NO_LED (1<<9)
+#define CFG_BACKGROUND_SCAN (1<<10)
+#define CFG_SPEED_SCAN (1<<11)
+#define CFG_NET_STATS (1<<12)
#define CAP_SHARED_KEY (1<<0) /* Off = OPEN */
#define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */
@@ -925,13 +1077,50 @@ struct average {
s32 sum;
};
+#define MAX_SPEED_SCAN 100
+#define IPW_IBSS_MAC_HASH_SIZE 31
+
+struct ipw_ibss_seq {
+ u8 mac[ETH_ALEN];
+ u16 seq_num;
+ u16 frag_num;
+ unsigned long packet_time;
+ struct list_head list;
+};
+
+struct ipw_error_elem {
+ u32 desc;
+ u32 time;
+ u32 blink1;
+ u32 blink2;
+ u32 link1;
+ u32 link2;
+ u32 data;
+};
+
+struct ipw_event {
+ u32 event;
+ u32 time;
+ u32 data;
+} __attribute__ ((packed));
+
+struct ipw_fw_error {
+ unsigned long jiffies;
+ u32 status;
+ u32 config;
+ u32 elem_len;
+ u32 log_len;
+ struct ipw_error_elem *elem;
+ struct ipw_event *log;
+ u8 payload[0];
+} __attribute__ ((packed));
+
struct ipw_priv {
/* ieee device used by generic ieee processing code */
struct ieee80211_device *ieee;
- struct ieee80211_security sec;
- /* spinlock */
spinlock_t lock;
+ struct semaphore sem;
/* basic pci-network driver stuff */
struct pci_dev *pci_dev;
@@ -966,7 +1155,7 @@ struct ipw_priv {
int rx_bufs_min; /**< minimum number of bufs in Rx queue */
int rx_pend_max; /**< maximum pending buffers for one IRQ */
u32 hcmd_seq; /**< sequence number for hcmd */
- u32 missed_beacon_threshold;
+ u32 disassociate_threshold;
u32 roaming_threshold;
struct ipw_associate assoc_request;
@@ -1007,6 +1196,8 @@ struct ipw_priv {
u8 mac_addr[ETH_ALEN];
u8 num_stations;
u8 stations[MAX_STATIONS][ETH_ALEN];
+ u8 short_retry_limit;
+ u8 long_retry_limit;
u32 notif_missed_beacons;
@@ -1024,17 +1215,29 @@ struct ipw_priv {
u32 tx_packets;
u32 quality;
+ u8 speed_scan[MAX_SPEED_SCAN];
+ u8 speed_scan_pos;
+
+ u16 last_seq_num;
+ u16 last_frag_num;
+ unsigned long last_packet_time;
+ struct list_head ibss_mac_hash[IPW_IBSS_MAC_HASH_SIZE];
+
/* eeprom */
u8 eeprom[0x100]; /* 256 bytes of eeprom */
+ u8 country[4];
int eeprom_delay;
struct iw_statistics wstats;
+ struct iw_public_data wireless_data;
+
struct workqueue_struct *workqueue;
struct work_struct adhoc_check;
struct work_struct associate;
struct work_struct disassociate;
+ struct work_struct system_config;
struct work_struct rx_replenish;
struct work_struct request_scan;
struct work_struct adapter_restart;
@@ -1045,25 +1248,51 @@ struct ipw_priv {
struct work_struct abort_scan;
struct work_struct roam;
struct work_struct scan_check;
+ struct work_struct link_up;
+ struct work_struct link_down;
struct tasklet_struct irq_tasklet;
+ /* LED related variables and work_struct */
+ u8 nic_type;
+ u32 led_activity_on;
+ u32 led_activity_off;
+ u32 led_association_on;
+ u32 led_association_off;
+ u32 led_ofdm_on;
+ u32 led_ofdm_off;
+
+ struct work_struct led_link_on;
+ struct work_struct led_link_off;
+ struct work_struct led_act_off;
+ struct work_struct merge_networks;
+
+ struct ipw_cmd_log *cmdlog;
+ int cmdlog_len;
+ int cmdlog_pos;
+
#define IPW_2200BG 1
#define IPW_2915ABG 2
u8 adapter;
-#define IPW_DEFAULT_TX_POWER 0x14
- u8 tx_power;
+ s8 tx_power;
#ifdef CONFIG_PM
u32 pm_state[16];
#endif
+ struct ipw_fw_error *error;
+
/* network state */
/* Used to pass the current INTA value from ISR to Tasklet */
u32 isr_inta;
+ /* QoS */
+ struct ipw_qos_info qos_data;
+ struct work_struct qos_activate;
+ /*********************************/
+
/* debugging info */
u32 indirect_dword;
u32 direct_dword;
@@ -1125,6 +1354,8 @@ do { if (ipw_debug_level & (level)) \
#define IPW_DL_RF_KILL (1<<17)
#define IPW_DL_FW_ERRORS (1<<18)
+#define IPW_DL_LED (1<<19)
+
#define IPW_DL_ORD (1<<20)
#define IPW_DL_FRAG (1<<21)
@@ -1137,6 +1368,8 @@ do { if (ipw_debug_level & (level)) \
#define IPW_DL_TRACE (1<<28)
#define IPW_DL_STATS (1<<29)
+#define IPW_DL_MERGE (1<<30)
+#define IPW_DL_QOS (1<<31)
#define IPW_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
#define IPW_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
@@ -1150,6 +1383,7 @@ do { if (ipw_debug_level & (level)) \
#define IPW_DEBUG_TX(f, a...) IPW_DEBUG(IPW_DL_TX, f, ## a)
#define IPW_DEBUG_ISR(f, a...) IPW_DEBUG(IPW_DL_ISR, f, ## a)
#define IPW_DEBUG_MANAGEMENT(f, a...) IPW_DEBUG(IPW_DL_MANAGE, f, ## a)
+#define IPW_DEBUG_LED(f, a...) IPW_DEBUG(IPW_DL_LED, f, ## a)
#define IPW_DEBUG_WEP(f, a...) IPW_DEBUG(IPW_DL_WEP, f, ## a)
#define IPW_DEBUG_HC(f, a...) IPW_DEBUG(IPW_DL_HOST_COMMAND, f, ## a)
#define IPW_DEBUG_FRAG(f, a...) IPW_DEBUG(IPW_DL_FRAG, f, ## a)
@@ -1163,6 +1397,8 @@ do { if (ipw_debug_level & (level)) \
#define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
#define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
#define IPW_DEBUG_STATS(f, a...) IPW_DEBUG(IPW_DL_STATS, f, ## a)
+#define IPW_DEBUG_MERGE(f, a...) IPW_DEBUG(IPW_DL_MERGE, f, ## a)
+#define IPW_DEBUG_QOS(f, a...) IPW_DEBUG(IPW_DL_QOS, f, ## a)
#include <linux/ctype.h>
@@ -1177,59 +1413,65 @@ do { if (ipw_debug_level & (level)) \
#define DINO_RXFIFO_DATA 0x01
#define DINO_CONTROL_REG 0x00200000
-#define CX2_INTA_RW 0x00000008
-#define CX2_INTA_MASK_R 0x0000000C
-#define CX2_INDIRECT_ADDR 0x00000010
-#define CX2_INDIRECT_DATA 0x00000014
-#define CX2_AUTOINC_ADDR 0x00000018
-#define CX2_AUTOINC_DATA 0x0000001C
-#define CX2_RESET_REG 0x00000020
-#define CX2_GP_CNTRL_RW 0x00000024
+#define IPW_INTA_RW 0x00000008
+#define IPW_INTA_MASK_R 0x0000000C
+#define IPW_INDIRECT_ADDR 0x00000010
+#define IPW_INDIRECT_DATA 0x00000014
+#define IPW_AUTOINC_ADDR 0x00000018
+#define IPW_AUTOINC_DATA 0x0000001C
+#define IPW_RESET_REG 0x00000020
+#define IPW_GP_CNTRL_RW 0x00000024
-#define CX2_READ_INT_REGISTER 0xFF4
+#define IPW_READ_INT_REGISTER 0xFF4
-#define CX2_GP_CNTRL_BIT_INIT_DONE 0x00000004
+#define IPW_GP_CNTRL_BIT_INIT_DONE 0x00000004
-#define CX2_REGISTER_DOMAIN1_END 0x00001000
-#define CX2_SRAM_READ_INT_REGISTER 0x00000ff4
+#define IPW_REGISTER_DOMAIN1_END 0x00001000
+#define IPW_SRAM_READ_INT_REGISTER 0x00000ff4
-#define CX2_SHARED_LOWER_BOUND 0x00000200
-#define CX2_INTERRUPT_AREA_LOWER_BOUND 0x00000f80
+#define IPW_SHARED_LOWER_BOUND 0x00000200
+#define IPW_INTERRUPT_AREA_LOWER_BOUND 0x00000f80
-#define CX2_NIC_SRAM_LOWER_BOUND 0x00000000
-#define CX2_NIC_SRAM_UPPER_BOUND 0x00030000
+#define IPW_NIC_SRAM_LOWER_BOUND 0x00000000
+#define IPW_NIC_SRAM_UPPER_BOUND 0x00030000
-#define CX2_BIT_INT_HOST_SRAM_READ_INT_REGISTER (1 << 29)
-#define CX2_GP_CNTRL_BIT_CLOCK_READY 0x00000001
-#define CX2_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY 0x00000002
+#define IPW_BIT_INT_HOST_SRAM_READ_INT_REGISTER (1 << 29)
+#define IPW_GP_CNTRL_BIT_CLOCK_READY 0x00000001
+#define IPW_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY 0x00000002
/*
* RESET Register Bit Indexes
*/
-#define CBD_RESET_REG_PRINCETON_RESET 0x00000001 /* Bit 0 (LSB) */
-#define CX2_RESET_REG_SW_RESET 0x00000080 /* Bit 7 */
-#define CX2_RESET_REG_MASTER_DISABLED 0x00000100 /* Bit 8 */
-#define CX2_RESET_REG_STOP_MASTER 0x00000200 /* Bit 9 */
-#define CX2_ARC_KESHET_CONFIG 0x08000000 /* Bit 27 */
-#define CX2_START_STANDBY 0x00000004 /* Bit 2 */
-
-#define CX2_CSR_CIS_UPPER_BOUND 0x00000200
-#define CX2_DOMAIN_0_END 0x1000
+#define CBD_RESET_REG_PRINCETON_RESET (1<<0)
+#define IPW_START_STANDBY (1<<2)
+#define IPW_ACTIVITY_LED (1<<4)
+#define IPW_ASSOCIATED_LED (1<<5)
+#define IPW_OFDM_LED (1<<6)
+#define IPW_RESET_REG_SW_RESET (1<<7)
+#define IPW_RESET_REG_MASTER_DISABLED (1<<8)
+#define IPW_RESET_REG_STOP_MASTER (1<<9)
+#define IPW_GATE_ODMA (1<<25)
+#define IPW_GATE_IDMA (1<<26)
+#define IPW_ARC_KESHET_CONFIG (1<<27)
+#define IPW_GATE_ADMA (1<<29)
+
+#define IPW_CSR_CIS_UPPER_BOUND 0x00000200
+#define IPW_DOMAIN_0_END 0x1000
#define CLX_MEM_BAR_SIZE 0x1000
-#define CX2_BASEBAND_CONTROL_STATUS 0X00200000
-#define CX2_BASEBAND_TX_FIFO_WRITE 0X00200004
-#define CX2_BASEBAND_RX_FIFO_READ 0X00200004
-#define CX2_BASEBAND_CONTROL_STORE 0X00200010
+#define IPW_BASEBAND_CONTROL_STATUS 0X00200000
+#define IPW_BASEBAND_TX_FIFO_WRITE 0X00200004
+#define IPW_BASEBAND_RX_FIFO_READ 0X00200004
+#define IPW_BASEBAND_CONTROL_STORE 0X00200010
-#define CX2_INTERNAL_CMD_EVENT 0X00300004
-#define CX2_BASEBAND_POWER_DOWN 0x00000001
+#define IPW_INTERNAL_CMD_EVENT 0X00300004
+#define IPW_BASEBAND_POWER_DOWN 0x00000001
-#define CX2_MEM_HALT_AND_RESET 0x003000e0
+#define IPW_MEM_HALT_AND_RESET 0x003000e0
/* defgroup bits_halt_reset MEM_HALT_AND_RESET register bits */
-#define CX2_BIT_HALT_RESET_ON 0x80000000
-#define CX2_BIT_HALT_RESET_OFF 0x00000000
+#define IPW_BIT_HALT_RESET_ON 0x80000000
+#define IPW_BIT_HALT_RESET_OFF 0x00000000
#define CB_LAST_VALID 0x20000000
#define CB_INT_ENABLED 0x40000000
@@ -1248,63 +1490,63 @@ do { if (ipw_debug_level & (level)) \
#define DMA_CB_STOP_AND_ABORT 0x00000C00
#define DMA_CB_START 0x00000100
-#define CX2_SHARED_SRAM_SIZE 0x00030000
-#define CX2_SHARED_SRAM_DMA_CONTROL 0x00027000
+#define IPW_SHARED_SRAM_SIZE 0x00030000
+#define IPW_SHARED_SRAM_DMA_CONTROL 0x00027000
#define CB_MAX_LENGTH 0x1FFF
-#define CX2_HOST_EEPROM_DATA_SRAM_SIZE 0xA18
-#define CX2_EEPROM_IMAGE_SIZE 0x100
+#define IPW_HOST_EEPROM_DATA_SRAM_SIZE 0xA18
+#define IPW_EEPROM_IMAGE_SIZE 0x100
/* DMA defs */
-#define CX2_DMA_I_CURRENT_CB 0x003000D0
-#define CX2_DMA_O_CURRENT_CB 0x003000D4
-#define CX2_DMA_I_DMA_CONTROL 0x003000A4
-#define CX2_DMA_I_CB_BASE 0x003000A0
-
-#define CX2_TX_CMD_QUEUE_BD_BASE (0x00000200)
-#define CX2_TX_CMD_QUEUE_BD_SIZE (0x00000204)
-#define CX2_TX_QUEUE_0_BD_BASE (0x00000208)
-#define CX2_TX_QUEUE_0_BD_SIZE (0x0000020C)
-#define CX2_TX_QUEUE_1_BD_BASE (0x00000210)
-#define CX2_TX_QUEUE_1_BD_SIZE (0x00000214)
-#define CX2_TX_QUEUE_2_BD_BASE (0x00000218)
-#define CX2_TX_QUEUE_2_BD_SIZE (0x0000021C)
-#define CX2_TX_QUEUE_3_BD_BASE (0x00000220)
-#define CX2_TX_QUEUE_3_BD_SIZE (0x00000224)
-#define CX2_RX_BD_BASE (0x00000240)
-#define CX2_RX_BD_SIZE (0x00000244)
-#define CX2_RFDS_TABLE_LOWER (0x00000500)
-
-#define CX2_TX_CMD_QUEUE_READ_INDEX (0x00000280)
-#define CX2_TX_QUEUE_0_READ_INDEX (0x00000284)
-#define CX2_TX_QUEUE_1_READ_INDEX (0x00000288)
-#define CX2_TX_QUEUE_2_READ_INDEX (0x0000028C)
-#define CX2_TX_QUEUE_3_READ_INDEX (0x00000290)
-#define CX2_RX_READ_INDEX (0x000002A0)
-
-#define CX2_TX_CMD_QUEUE_WRITE_INDEX (0x00000F80)
-#define CX2_TX_QUEUE_0_WRITE_INDEX (0x00000F84)
-#define CX2_TX_QUEUE_1_WRITE_INDEX (0x00000F88)
-#define CX2_TX_QUEUE_2_WRITE_INDEX (0x00000F8C)
-#define CX2_TX_QUEUE_3_WRITE_INDEX (0x00000F90)
-#define CX2_RX_WRITE_INDEX (0x00000FA0)
+#define IPW_DMA_I_CURRENT_CB 0x003000D0
+#define IPW_DMA_O_CURRENT_CB 0x003000D4
+#define IPW_DMA_I_DMA_CONTROL 0x003000A4
+#define IPW_DMA_I_CB_BASE 0x003000A0
+
+#define IPW_TX_CMD_QUEUE_BD_BASE 0x00000200
+#define IPW_TX_CMD_QUEUE_BD_SIZE 0x00000204
+#define IPW_TX_QUEUE_0_BD_BASE 0x00000208
+#define IPW_TX_QUEUE_0_BD_SIZE (0x0000020C)
+#define IPW_TX_QUEUE_1_BD_BASE 0x00000210
+#define IPW_TX_QUEUE_1_BD_SIZE 0x00000214
+#define IPW_TX_QUEUE_2_BD_BASE 0x00000218
+#define IPW_TX_QUEUE_2_BD_SIZE (0x0000021C)
+#define IPW_TX_QUEUE_3_BD_BASE 0x00000220
+#define IPW_TX_QUEUE_3_BD_SIZE 0x00000224
+#define IPW_RX_BD_BASE 0x00000240
+#define IPW_RX_BD_SIZE 0x00000244
+#define IPW_RFDS_TABLE_LOWER 0x00000500
+
+#define IPW_TX_CMD_QUEUE_READ_INDEX 0x00000280
+#define IPW_TX_QUEUE_0_READ_INDEX 0x00000284
+#define IPW_TX_QUEUE_1_READ_INDEX 0x00000288
+#define IPW_TX_QUEUE_2_READ_INDEX (0x0000028C)
+#define IPW_TX_QUEUE_3_READ_INDEX 0x00000290
+#define IPW_RX_READ_INDEX (0x000002A0)
+
+#define IPW_TX_CMD_QUEUE_WRITE_INDEX (0x00000F80)
+#define IPW_TX_QUEUE_0_WRITE_INDEX (0x00000F84)
+#define IPW_TX_QUEUE_1_WRITE_INDEX (0x00000F88)
+#define IPW_TX_QUEUE_2_WRITE_INDEX (0x00000F8C)
+#define IPW_TX_QUEUE_3_WRITE_INDEX (0x00000F90)
+#define IPW_RX_WRITE_INDEX (0x00000FA0)
/*
* EEPROM Related Definitions
*/
-#define IPW_EEPROM_DATA_SRAM_ADDRESS (CX2_SHARED_LOWER_BOUND + 0x814)
-#define IPW_EEPROM_DATA_SRAM_SIZE (CX2_SHARED_LOWER_BOUND + 0x818)
-#define IPW_EEPROM_LOAD_DISABLE (CX2_SHARED_LOWER_BOUND + 0x81C)
-#define IPW_EEPROM_DATA (CX2_SHARED_LOWER_BOUND + 0x820)
-#define IPW_EEPROM_UPPER_ADDRESS (CX2_SHARED_LOWER_BOUND + 0x9E0)
+#define IPW_EEPROM_DATA_SRAM_ADDRESS (IPW_SHARED_LOWER_BOUND + 0x814)
+#define IPW_EEPROM_DATA_SRAM_SIZE (IPW_SHARED_LOWER_BOUND + 0x818)
+#define IPW_EEPROM_LOAD_DISABLE (IPW_SHARED_LOWER_BOUND + 0x81C)
+#define IPW_EEPROM_DATA (IPW_SHARED_LOWER_BOUND + 0x820)
+#define IPW_EEPROM_UPPER_ADDRESS (IPW_SHARED_LOWER_BOUND + 0x9E0)
-#define IPW_STATION_TABLE_LOWER (CX2_SHARED_LOWER_BOUND + 0xA0C)
-#define IPW_STATION_TABLE_UPPER (CX2_SHARED_LOWER_BOUND + 0xB0C)
-#define IPW_REQUEST_ATIM (CX2_SHARED_LOWER_BOUND + 0xB0C)
-#define IPW_ATIM_SENT (CX2_SHARED_LOWER_BOUND + 0xB10)
-#define IPW_WHO_IS_AWAKE (CX2_SHARED_LOWER_BOUND + 0xB14)
-#define IPW_DURING_ATIM_WINDOW (CX2_SHARED_LOWER_BOUND + 0xB18)
+#define IPW_STATION_TABLE_LOWER (IPW_SHARED_LOWER_BOUND + 0xA0C)
+#define IPW_STATION_TABLE_UPPER (IPW_SHARED_LOWER_BOUND + 0xB0C)
+#define IPW_REQUEST_ATIM (IPW_SHARED_LOWER_BOUND + 0xB0C)
+#define IPW_ATIM_SENT (IPW_SHARED_LOWER_BOUND + 0xB10)
+#define IPW_WHO_IS_AWAKE (IPW_SHARED_LOWER_BOUND + 0xB14)
+#define IPW_DURING_ATIM_WINDOW (IPW_SHARED_LOWER_BOUND + 0xB18)
#define MSB 1
#define LSB 0
@@ -1326,15 +1568,15 @@ do { if (ipw_debug_level & (level)) \
#define EEPROM_HW_VERSION (GET_EEPROM_ADDR(0x72,LSB)) /* 2 bytes */
/* NIC type as found in the one byte EEPROM_NIC_TYPE offset*/
-#define EEPROM_NIC_TYPE_STANDARD 0
-#define EEPROM_NIC_TYPE_DELL 1
-#define EEPROM_NIC_TYPE_FUJITSU 2
-#define EEPROM_NIC_TYPE_IBM 3
-#define EEPROM_NIC_TYPE_HP 4
+#define EEPROM_NIC_TYPE_0 0
+#define EEPROM_NIC_TYPE_1 1
+#define EEPROM_NIC_TYPE_2 2
+#define EEPROM_NIC_TYPE_3 3
+#define EEPROM_NIC_TYPE_4 4
#define FW_MEM_REG_LOWER_BOUND 0x00300000
#define FW_MEM_REG_EEPROM_ACCESS (FW_MEM_REG_LOWER_BOUND + 0x40)
-
+#define IPW_EVENT_REG (FW_MEM_REG_LOWER_BOUND + 0x04)
#define EEPROM_BIT_SK (1<<0)
#define EEPROM_BIT_CS (1<<1)
#define EEPROM_BIT_DI (1<<2)
@@ -1343,50 +1585,47 @@ do { if (ipw_debug_level & (level)) \
#define EEPROM_CMD_READ 0x2
/* Interrupts masks */
-#define CX2_INTA_NONE 0x00000000
+#define IPW_INTA_NONE 0x00000000
-#define CX2_INTA_BIT_RX_TRANSFER 0x00000002
-#define CX2_INTA_BIT_STATUS_CHANGE 0x00000010
-#define CX2_INTA_BIT_BEACON_PERIOD_EXPIRED 0x00000020
+#define IPW_INTA_BIT_RX_TRANSFER 0x00000002
+#define IPW_INTA_BIT_STATUS_CHANGE 0x00000010
+#define IPW_INTA_BIT_BEACON_PERIOD_EXPIRED 0x00000020
//Inta Bits for CF
-#define CX2_INTA_BIT_TX_CMD_QUEUE 0x00000800
-#define CX2_INTA_BIT_TX_QUEUE_1 0x00001000
-#define CX2_INTA_BIT_TX_QUEUE_2 0x00002000
-#define CX2_INTA_BIT_TX_QUEUE_3 0x00004000
-#define CX2_INTA_BIT_TX_QUEUE_4 0x00008000
+#define IPW_INTA_BIT_TX_CMD_QUEUE 0x00000800
+#define IPW_INTA_BIT_TX_QUEUE_1 0x00001000
+#define IPW_INTA_BIT_TX_QUEUE_2 0x00002000
+#define IPW_INTA_BIT_TX_QUEUE_3 0x00004000
+#define IPW_INTA_BIT_TX_QUEUE_4 0x00008000
-#define CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE 0x00010000
+#define IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE 0x00010000
-#define CX2_INTA_BIT_PREPARE_FOR_POWER_DOWN 0x00100000
-#define CX2_INTA_BIT_POWER_DOWN 0x00200000
+#define IPW_INTA_BIT_PREPARE_FOR_POWER_DOWN 0x00100000
+#define IPW_INTA_BIT_POWER_DOWN 0x00200000
-#define CX2_INTA_BIT_FW_INITIALIZATION_DONE 0x01000000
-#define CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE 0x02000000
-#define CX2_INTA_BIT_RF_KILL_DONE 0x04000000
-#define CX2_INTA_BIT_FATAL_ERROR 0x40000000
-#define CX2_INTA_BIT_PARITY_ERROR 0x80000000
+#define IPW_INTA_BIT_FW_INITIALIZATION_DONE 0x01000000
+#define IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE 0x02000000
+#define IPW_INTA_BIT_RF_KILL_DONE 0x04000000
+#define IPW_INTA_BIT_FATAL_ERROR 0x40000000
+#define IPW_INTA_BIT_PARITY_ERROR 0x80000000
/* Interrupts enabled at init time. */
-#define CX2_INTA_MASK_ALL \
- (CX2_INTA_BIT_TX_QUEUE_1 | \
- CX2_INTA_BIT_TX_QUEUE_2 | \
- CX2_INTA_BIT_TX_QUEUE_3 | \
- CX2_INTA_BIT_TX_QUEUE_4 | \
- CX2_INTA_BIT_TX_CMD_QUEUE | \
- CX2_INTA_BIT_RX_TRANSFER | \
- CX2_INTA_BIT_FATAL_ERROR | \
- CX2_INTA_BIT_PARITY_ERROR | \
- CX2_INTA_BIT_STATUS_CHANGE | \
- CX2_INTA_BIT_FW_INITIALIZATION_DONE | \
- CX2_INTA_BIT_BEACON_PERIOD_EXPIRED | \
- CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE | \
- CX2_INTA_BIT_PREPARE_FOR_POWER_DOWN | \
- CX2_INTA_BIT_POWER_DOWN | \
- CX2_INTA_BIT_RF_KILL_DONE )
-
-#define IPWSTATUS_ERROR_LOG (CX2_SHARED_LOWER_BOUND + 0x410)
-#define IPW_EVENT_LOG (CX2_SHARED_LOWER_BOUND + 0x414)
+#define IPW_INTA_MASK_ALL \
+ (IPW_INTA_BIT_TX_QUEUE_1 | \
+ IPW_INTA_BIT_TX_QUEUE_2 | \
+ IPW_INTA_BIT_TX_QUEUE_3 | \
+ IPW_INTA_BIT_TX_QUEUE_4 | \
+ IPW_INTA_BIT_TX_CMD_QUEUE | \
+ IPW_INTA_BIT_RX_TRANSFER | \
+ IPW_INTA_BIT_FATAL_ERROR | \
+ IPW_INTA_BIT_PARITY_ERROR | \
+ IPW_INTA_BIT_STATUS_CHANGE | \
+ IPW_INTA_BIT_FW_INITIALIZATION_DONE | \
+ IPW_INTA_BIT_BEACON_PERIOD_EXPIRED | \
+ IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE | \
+ IPW_INTA_BIT_PREPARE_FOR_POWER_DOWN | \
+ IPW_INTA_BIT_POWER_DOWN | \
+ IPW_INTA_BIT_RF_KILL_DONE )
/* FW event log definitions */
#define EVENT_ELEM_SIZE (3 * sizeof(u32))
@@ -1396,6 +1635,11 @@ do { if (ipw_debug_level & (level)) \
#define ERROR_ELEM_SIZE (7 * sizeof(u32))
#define ERROR_START_OFFSET (1 * sizeof(u32))
+/* TX power level (dbm) */
+#define IPW_TX_POWER_MIN -12
+#define IPW_TX_POWER_MAX 20
+#define IPW_TX_POWER_DEFAULT IPW_TX_POWER_MAX
+
enum {
IPW_FW_ERROR_OK = 0,
IPW_FW_ERROR_FAIL,
@@ -1408,8 +1652,8 @@ enum {
IPW_FW_ERROR_ALLOC_FAIL,
IPW_FW_ERROR_DMA_UNDERRUN,
IPW_FW_ERROR_DMA_STATUS,
- IPW_FW_ERROR_DINOSTATUS_ERROR,
- IPW_FW_ERROR_EEPROMSTATUS_ERROR,
+ IPW_FW_ERROR_DINO_ERROR,
+ IPW_FW_ERROR_EEPROM_ERROR,
IPW_FW_ERROR_SYSASSERT,
IPW_FW_ERROR_FATAL_ERROR
};
@@ -1425,6 +1669,8 @@ enum {
#define HC_IBSS_RECONF 4
#define HC_DISASSOC_QUIET 5
+#define HC_QOS_SUPPORT_ASSOC 0x01
+
#define IPW_RATE_CAPABILITIES 1
#define IPW_RATE_CONNECT 0
@@ -1595,18 +1841,20 @@ enum {
IPW_ORD_TABLE_7_LAST
};
-#define IPW_ORDINALS_TABLE_LOWER (CX2_SHARED_LOWER_BOUND + 0x500)
-#define IPW_ORDINALS_TABLE_0 (CX2_SHARED_LOWER_BOUND + 0x180)
-#define IPW_ORDINALS_TABLE_1 (CX2_SHARED_LOWER_BOUND + 0x184)
-#define IPW_ORDINALS_TABLE_2 (CX2_SHARED_LOWER_BOUND + 0x188)
-#define IPW_MEM_FIXED_OVERRIDE (CX2_SHARED_LOWER_BOUND + 0x41C)
+#define IPW_ERROR_LOG (IPW_SHARED_LOWER_BOUND + 0x410)
+#define IPW_EVENT_LOG (IPW_SHARED_LOWER_BOUND + 0x414)
+#define IPW_ORDINALS_TABLE_LOWER (IPW_SHARED_LOWER_BOUND + 0x500)
+#define IPW_ORDINALS_TABLE_0 (IPW_SHARED_LOWER_BOUND + 0x180)
+#define IPW_ORDINALS_TABLE_1 (IPW_SHARED_LOWER_BOUND + 0x184)
+#define IPW_ORDINALS_TABLE_2 (IPW_SHARED_LOWER_BOUND + 0x188)
+#define IPW_MEM_FIXED_OVERRIDE (IPW_SHARED_LOWER_BOUND + 0x41C)
struct ipw_fixed_rate {
u16 tx_rates;
u16 reserved;
} __attribute__ ((packed));
-#define CX2_INDIRECT_ADDR_MASK (~0x3ul)
+#define IPW_INDIRECT_ADDR_MASK (~0x3ul)
struct host_cmd {
u8 cmd;
@@ -1615,6 +1863,12 @@ struct host_cmd {
u32 param[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH];
} __attribute__ ((packed));
+struct ipw_cmd_log {
+ unsigned long jiffies;
+ int retcode;
+ struct host_cmd cmd;
+};
+
#define CFG_BT_COEXISTENCE_MIN 0x00
#define CFG_BT_COEXISTENCE_DEFER 0x02
#define CFG_BT_COEXISTENCE_KILL 0x04
@@ -1643,15 +1897,6 @@ struct host_cmd {
#define REG_CHANNEL_MASK 0x00003FFF
#define IPW_IBSS_11B_DEFAULT_MASK 0x87ff
-static const long ipw_frequencies[] = {
- 2412, 2417, 2422, 2427,
- 2432, 2437, 2442, 2447,
- 2452, 2457, 2462, 2467,
- 2472, 2484
-};
-
-#define FREQ_COUNT ARRAY_SIZE(ipw_frequencies)
-
#define IPW_MAX_CONFIG_RETRIES 10
static inline u32 frame_hdr_len(struct ieee80211_hdr_4addr *hdr)
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
index 7a17bb31fc8..f5d856db92a 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -12,7 +12,6 @@
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
-#include <linux/version.h>
#include "hermes.h"
diff --git a/drivers/net/wireless/prism54/isl_38xx.c b/drivers/net/wireless/prism54/isl_38xx.c
index adc7499136d..109a96d9000 100644
--- a/drivers/net/wireless/prism54/isl_38xx.c
+++ b/drivers/net/wireless/prism54/isl_38xx.c
@@ -18,7 +18,6 @@
*
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/delay.h>
@@ -112,9 +111,10 @@ isl38xx_handle_wakeup(isl38xx_control_block *control_block,
void
isl38xx_trigger_device(int asleep, void __iomem *device_base)
{
- u32 reg, counter = 0;
+ u32 reg;
#if VERBOSE > SHOW_ERROR_MESSAGES
+ u32 counter = 0;
struct timeval current_time;
DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n");
#endif
@@ -131,7 +131,6 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
current_time.tv_sec, (long)current_time.tv_usec,
readl(device_base + ISL38XX_CTRL_STAT_REG));
#endif
- udelay(ISL38XX_WRITEIO_DELAY);
reg = readl(device_base + ISL38XX_INT_IDENT_REG);
if (reg == 0xabadface) {
@@ -145,7 +144,9 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG),
(reg & ISL38XX_CTRL_STAT_SLEEPMODE) == 0) {
udelay(ISL38XX_WRITEIO_DELAY);
+#if VERBOSE > SHOW_ERROR_MESSAGES
counter++;
+#endif
}
#if VERBOSE > SHOW_ERROR_MESSAGES
@@ -153,10 +154,6 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
"%08li.%08li Device register read %08x\n",
current_time.tv_sec, (long)current_time.tv_usec,
readl(device_base + ISL38XX_CTRL_STAT_REG));
-#endif
- udelay(ISL38XX_WRITEIO_DELAY);
-
-#if VERBOSE > SHOW_ERROR_MESSAGES
do_gettimeofday(&current_time);
DEBUG(SHOW_TRACING,
"%08li.%08li Device asleep counter %i\n",
@@ -171,7 +168,6 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
/* perform another read on the Device Status Register */
reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
- udelay(ISL38XX_WRITEIO_DELAY);
#if VERBOSE > SHOW_ERROR_MESSAGES
do_gettimeofday(&current_time);
@@ -187,7 +183,6 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE,
ISL38XX_DEV_INT_REG);
- udelay(ISL38XX_WRITEIO_DELAY);
}
}
diff --git a/drivers/net/wireless/prism54/isl_38xx.h b/drivers/net/wireless/prism54/isl_38xx.h
index e83e4912ab6..8af20980af8 100644
--- a/drivers/net/wireless/prism54/isl_38xx.h
+++ b/drivers/net/wireless/prism54/isl_38xx.h
@@ -20,7 +20,6 @@
#ifndef _ISL_38XX_H
#define _ISL_38XX_H
-#include <linux/version.h>
#include <asm/io.h>
#include <asm/byteorder.h>
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 5c1a1adf1ff..135a156db25 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -20,7 +20,6 @@
*
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/if_arp.h>
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index 78bdb359835..5ddf2959903 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -19,7 +19,6 @@
*
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
index efbed439795..07053165e4c 100644
--- a/drivers/net/wireless/prism54/islpci_dev.h
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -23,7 +23,6 @@
#ifndef _ISLPCI_DEV_H
#define _ISLPCI_DEV_H
-#include <linux/version.h>
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c
index fc1eb356483..33d64d2ee53 100644
--- a/drivers/net/wireless/prism54/islpci_eth.c
+++ b/drivers/net/wireless/prism54/islpci_eth.c
@@ -17,7 +17,6 @@
*
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -227,17 +226,17 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
priv->data_low_tx_full = 1;
}
+ /* set the transmission time */
+ ndev->trans_start = jiffies;
+ priv->statistics.tx_packets++;
+ priv->statistics.tx_bytes += skb->len;
+
/* trigger the device */
islpci_trigger(priv);
/* unlock the driver code */
spin_unlock_irqrestore(&priv->slock, flags);
- /* set the transmission time */
- ndev->trans_start = jiffies;
- priv->statistics.tx_packets++;
- priv->statistics.tx_bytes += skb->len;
-
return 0;
drop_free:
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index dc040caab7d..b41d666fea3 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -18,7 +18,6 @@
*
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 4b3c98f5c56..c822cad3333 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -4608,9 +4608,8 @@ wavelan_attach(void)
#endif
/* Initialize the dev_link_t structure */
- link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+ link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL);
if (!link) return NULL;
- memset(link, 0, sizeof(struct dev_link_t));
/* The io structure describes IO port mapping */
link->io.NumPorts1 = 8;
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index 3f8c27f0871..978fdc60678 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -1965,10 +1965,9 @@ static dev_link_t *wl3501_attach(void)
int ret;
/* Initialize the dev_link_t structure */
- link = kmalloc(sizeof(*link), GFP_KERNEL);
+ link = kzalloc(sizeof(*link), GFP_KERNEL);
if (!link)
goto out;
- memset(link, 0, sizeof(struct dev_link_t));
/* The io structure describes IO port mapping */
link->io.NumPorts1 = 16;
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c
index d414a3bb50b..86c0808d6a0 100644
--- a/drivers/pcmcia/au1000_pb1x00.c
+++ b/drivers/pcmcia/au1000_pb1x00.c
@@ -30,7 +30,6 @@
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
-#include <linux/version.h>
#include <linux/types.h>
#include <pcmcia/cs_types.h>
diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c
index f113b69d699..01a895bc9a4 100644
--- a/drivers/pcmcia/au1000_xxs1500.c
+++ b/drivers/pcmcia/au1000_xxs1500.c
@@ -35,7 +35,6 @@
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
-#include <linux/version.h>
#include <linux/types.h>
#include <pcmcia/cs_types.h>
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
index fe5ea36e7de..56c58831e80 100644
--- a/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -22,16 +22,20 @@
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/hardware/scoop.h>
-#ifdef CONFIG_SA1100_COLLIE
-#include <asm/arch-sa1100/collie.h>
-#else
-#include <asm/arch-pxa/pxa-regs.h>
-#endif
#include "soc_common.h"
#define NO_KEEP_VS 0x0001
+/* PCMCIA to Scoop linkage
+
+ There is no easy way to link multiple scoop devices into one
+ single entity for the pxa2xx_pcmcia device so this structure
+ is used which is setup by the platform code
+*/
+struct scoop_pcmcia_config *platform_scoop_config;
+#define SCOOP_DEV platform_scoop_config->devs
+
static void sharpsl_pcmcia_init_reset(struct scoop_pcmcia_dev *scoopdev)
{
reset_scoop(scoopdev->dev);
@@ -43,38 +47,16 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
{
int ret;
-#ifndef CONFIG_SA1100_COLLIE
- /*
- * Setup default state of GPIO outputs
- * before we enable them as outputs.
- */
- GPSR(GPIO48_nPOE) =
- GPIO_bit(GPIO48_nPOE) |
- GPIO_bit(GPIO49_nPWE) |
- GPIO_bit(GPIO50_nPIOR) |
- GPIO_bit(GPIO51_nPIOW) |
- GPIO_bit(GPIO52_nPCE_1) |
- GPIO_bit(GPIO53_nPCE_2);
-
- pxa_gpio_mode(GPIO48_nPOE_MD);
- pxa_gpio_mode(GPIO49_nPWE_MD);
- pxa_gpio_mode(GPIO50_nPIOR_MD);
- pxa_gpio_mode(GPIO51_nPIOW_MD);
- pxa_gpio_mode(GPIO52_nPCE_1_MD);
- pxa_gpio_mode(GPIO53_nPCE_2_MD);
- pxa_gpio_mode(GPIO54_pSKTSEL_MD);
- pxa_gpio_mode(GPIO55_nPREG_MD);
- pxa_gpio_mode(GPIO56_nPWAIT_MD);
- pxa_gpio_mode(GPIO57_nIOIS16_MD);
-#endif
+ if (platform_scoop_config->pcmcia_init)
+ platform_scoop_config->pcmcia_init();
/* Register interrupts */
- if (scoop_devs[skt->nr].cd_irq >= 0) {
+ if (SCOOP_DEV[skt->nr].cd_irq >= 0) {
struct pcmcia_irqs cd_irq;
cd_irq.sock = skt->nr;
- cd_irq.irq = scoop_devs[skt->nr].cd_irq;
- cd_irq.str = scoop_devs[skt->nr].cd_irq_str;
+ cd_irq.irq = SCOOP_DEV[skt->nr].cd_irq;
+ cd_irq.str = SCOOP_DEV[skt->nr].cd_irq_str;
ret = soc_pcmcia_request_irqs(skt, &cd_irq, 1);
if (ret) {
@@ -83,19 +65,19 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
}
}
- skt->irq = scoop_devs[skt->nr].irq;
+ skt->irq = SCOOP_DEV[skt->nr].irq;
return 0;
}
static void sharpsl_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
{
- if (scoop_devs[skt->nr].cd_irq >= 0) {
+ if (SCOOP_DEV[skt->nr].cd_irq >= 0) {
struct pcmcia_irqs cd_irq;
cd_irq.sock = skt->nr;
- cd_irq.irq = scoop_devs[skt->nr].cd_irq;
- cd_irq.str = scoop_devs[skt->nr].cd_irq_str;
+ cd_irq.irq = SCOOP_DEV[skt->nr].cd_irq;
+ cd_irq.str = SCOOP_DEV[skt->nr].cd_irq_str;
soc_pcmcia_free_irqs(skt, &cd_irq, 1);
}
}
@@ -105,9 +87,9 @@ static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
struct pcmcia_state *state)
{
unsigned short cpr, csr;
- struct device *scoop = scoop_devs[skt->nr].dev;
+ struct device *scoop = SCOOP_DEV[skt->nr].dev;
- cpr = read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR);
+ cpr = read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR);
write_scoop_reg(scoop, SCOOP_IRM, 0x00FF);
write_scoop_reg(scoop, SCOOP_ISR, 0x0000);
@@ -116,21 +98,25 @@ static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
if (csr & 0x0004) {
/* card eject */
write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
- scoop_devs[skt->nr].keep_vs = NO_KEEP_VS;
+ SCOOP_DEV[skt->nr].keep_vs = NO_KEEP_VS;
}
- else if (!(scoop_devs[skt->nr].keep_vs & NO_KEEP_VS)) {
+ else if (!(SCOOP_DEV[skt->nr].keep_vs & NO_KEEP_VS)) {
/* keep vs1,vs2 */
write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
- csr |= scoop_devs[skt->nr].keep_vs;
+ csr |= SCOOP_DEV[skt->nr].keep_vs;
}
else if (cpr & 0x0003) {
/* power on */
write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
- scoop_devs[skt->nr].keep_vs = (csr & 0x00C0);
+ SCOOP_DEV[skt->nr].keep_vs = (csr & 0x00C0);
}
else {
/* card detect */
- write_scoop_reg(scoop, SCOOP_CDR, 0x0002);
+ if ((machine_is_spitz() || machine_is_borzoi()) && skt->nr == 1) {
+ write_scoop_reg(scoop, SCOOP_CDR, 0x0000);
+ } else {
+ write_scoop_reg(scoop, SCOOP_CDR, 0x0002);
+ }
}
state->detect = (csr & 0x0004) ? 0 : 1;
@@ -144,7 +130,6 @@ static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
if ((cpr & 0x0080) && ((cpr & 0x8040) != 0x8040)) {
printk(KERN_ERR "sharpsl_pcmcia_socket_state(): CPR=%04X, Low voltage!\n", cpr);
}
-
}
@@ -152,7 +137,7 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
const socket_state_t *state)
{
unsigned long flags;
- struct device *scoop = scoop_devs[skt->nr].dev;
+ struct device *scoop = SCOOP_DEV[skt->nr].dev;
unsigned short cpr, ncpr, ccr, nccr, mcr, nmcr, imr, nimr;
@@ -177,8 +162,13 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
nccr = (ccr = read_scoop_reg(scoop, SCOOP_CCR)) & ~0x0080;
nimr = (imr = read_scoop_reg(scoop, SCOOP_IMR)) & ~0x003E;
- ncpr |= (state->Vcc == 33) ? 0x0001 :
- (state->Vcc == 50) ? 0x0002 : 0;
+ if ((machine_is_spitz() || machine_is_borzoi() || machine_is_akita()) && skt->nr == 0) {
+ ncpr |= (state->Vcc == 33) ? 0x0002 :
+ (state->Vcc == 50) ? 0x0002 : 0;
+ } else {
+ ncpr |= (state->Vcc == 33) ? 0x0001 :
+ (state->Vcc == 50) ? 0x0002 : 0;
+ }
nmcr |= (state->flags&SS_IOCARD) ? 0x0010 : 0;
ncpr |= (state->flags&SS_OUTPUT_ENA) ? 0x0080 : 0;
nccr |= (state->flags&SS_RESET)? 0x0080: 0;
@@ -190,18 +180,22 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
((skt->status&SS_WRPROT) ? 0x0008 : 0);
if (!(ncpr & 0x0003)) {
- scoop_devs[skt->nr].keep_rd = 0;
- } else if (!scoop_devs[skt->nr].keep_rd) {
+ SCOOP_DEV[skt->nr].keep_rd = 0;
+ } else if (!SCOOP_DEV[skt->nr].keep_rd) {
if (nccr & 0x0080)
- scoop_devs[skt->nr].keep_rd = 1;
+ SCOOP_DEV[skt->nr].keep_rd = 1;
else
nccr |= 0x0080;
}
if (mcr != nmcr)
write_scoop_reg(scoop, SCOOP_MCR, nmcr);
- if (cpr != ncpr)
- write_scoop_reg(scoop, SCOOP_CPR, ncpr);
+ if (cpr != ncpr) {
+ if (platform_scoop_config->power_ctrl)
+ platform_scoop_config->power_ctrl(scoop, ncpr , skt->nr);
+ else
+ write_scoop_reg(scoop, SCOOP_CPR, ncpr);
+ }
if (ccr != nccr)
write_scoop_reg(scoop, SCOOP_CCR, nccr);
if (imr != nimr)
@@ -214,43 +208,43 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
{
- sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]);
+ sharpsl_pcmcia_init_reset(&SCOOP_DEV[skt->nr]);
/* Enable interrupt */
- write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_IMR, 0x00C0);
- write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_MCR, 0x0101);
- scoop_devs[skt->nr].keep_vs = NO_KEEP_VS;
+ write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_IMR, 0x00C0);
+ write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_MCR, 0x0101);
+ SCOOP_DEV[skt->nr].keep_vs = NO_KEEP_VS;
if (machine_is_collie())
/* We need to disable SS_OUTPUT_ENA here. */
- write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR, read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR) & ~0x0080);
+ write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR, read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR) & ~0x0080);
}
static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
{
/* CF_BUS_OFF */
- sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]);
+ sharpsl_pcmcia_init_reset(&SCOOP_DEV[skt->nr]);
if (machine_is_collie())
/* We need to disable SS_OUTPUT_ENA here. */
- write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR, read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR) & ~0x0080);
+ write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR, read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR) & ~0x0080);
}
static struct pcmcia_low_level sharpsl_pcmcia_ops = {
- .owner = THIS_MODULE,
- .hw_init = sharpsl_pcmcia_hw_init,
- .hw_shutdown = sharpsl_pcmcia_hw_shutdown,
- .socket_state = sharpsl_pcmcia_socket_state,
- .configure_socket = sharpsl_pcmcia_configure_socket,
- .socket_init = sharpsl_pcmcia_socket_init,
- .socket_suspend = sharpsl_pcmcia_socket_suspend,
- .first = 0,
- .nr = 0,
+ .owner = THIS_MODULE,
+ .hw_init = sharpsl_pcmcia_hw_init,
+ .hw_shutdown = sharpsl_pcmcia_hw_shutdown,
+ .socket_state = sharpsl_pcmcia_socket_state,
+ .configure_socket = sharpsl_pcmcia_configure_socket,
+ .socket_init = sharpsl_pcmcia_socket_init,
+ .socket_suspend = sharpsl_pcmcia_socket_suspend,
+ .first = 0,
+ .nr = 0,
};
-static struct platform_device *sharpsl_pcmcia_device;
-
#ifdef CONFIG_SA1100_COLLIE
+#include "sa11xx_base.h"
+
int __init pcmcia_collie_init(struct device *dev)
{
int ret = -ENODEV;
@@ -263,11 +257,13 @@ int __init pcmcia_collie_init(struct device *dev)
#else
+static struct platform_device *sharpsl_pcmcia_device;
+
static int __init sharpsl_pcmcia_init(void)
{
int ret;
- sharpsl_pcmcia_ops.nr=scoop_num;
+ sharpsl_pcmcia_ops.nr=platform_scoop_config->num_devs;
sharpsl_pcmcia_device = kmalloc(sizeof(*sharpsl_pcmcia_device), GFP_KERNEL);
if (!sharpsl_pcmcia_device)
return -ENOMEM;
@@ -275,7 +271,7 @@ static int __init sharpsl_pcmcia_init(void)
memset(sharpsl_pcmcia_device, 0, sizeof(*sharpsl_pcmcia_device));
sharpsl_pcmcia_device->name = "pxa2xx-pcmcia";
sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops;
- sharpsl_pcmcia_device->dev.parent=scoop_devs[0].dev;
+ sharpsl_pcmcia_device->dev.parent=platform_scoop_config->devs[0].dev;
ret = platform_device_register(sharpsl_pcmcia_device);
if (ret)
diff --git a/drivers/s390/char/keyboard.h b/drivers/s390/char/keyboard.h
index 3b4da5a9cf7..f7bf45c6bf0 100644
--- a/drivers/s390/char/keyboard.h
+++ b/drivers/s390/char/keyboard.h
@@ -41,14 +41,14 @@ int kbd_ioctl(struct kbd_data *, struct file *, unsigned int, unsigned long);
/*
* Helper Functions.
*/
-extern inline void
+static inline void
kbd_put_queue(struct tty_struct *tty, int ch)
{
tty_insert_flip_char(tty, ch, 0);
tty_schedule_flip(tty);
}
-extern inline void
+static inline void
kbd_puts_queue(struct tty_struct *tty, char *cp)
{
while (*cp)
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index 6b8aa6a852b..328e31cc685 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -265,7 +265,7 @@ QDIO_PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
/*
* Some instructions as assembly
*/
-extern __inline__ int
+static inline int
do_siga_sync(unsigned int irq, unsigned int mask1, unsigned int mask2)
{
int cc;
@@ -300,7 +300,7 @@ do_siga_sync(unsigned int irq, unsigned int mask1, unsigned int mask2)
return cc;
}
-extern __inline__ int
+static inline int
do_siga_input(unsigned int irq, unsigned int mask)
{
int cc;
@@ -334,7 +334,7 @@ do_siga_input(unsigned int irq, unsigned int mask)
return cc;
}
-extern __inline__ int
+static inline int
do_siga_output(unsigned long irq, unsigned long mask, __u32 *bb)
{
int cc;
@@ -401,7 +401,7 @@ do_siga_output(unsigned long irq, unsigned long mask, __u32 *bb)
return cc;
}
-extern __inline__ unsigned long
+static inline unsigned long
do_clear_global_summary(void)
{
diff --git a/drivers/s390/crypto/z90main.c b/drivers/s390/crypto/z90main.c
index 04c2ef778ec..4010f2bb85a 100644
--- a/drivers/s390/crypto/z90main.c
+++ b/drivers/s390/crypto/z90main.c
@@ -37,7 +37,6 @@
#include <linux/kobject_uevent.h>
#include <linux/proc_fs.h>
#include <linux/syscalls.h>
-#include <linux/version.h>
#include "z90crypt.h"
#include "z90common.h"
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 1a1c3decea7..6b63d21612e 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -88,7 +88,6 @@
#include <linux/tcp.h>
#include <linux/timer.h>
#include <linux/types.h>
-#include <linux/version.h>
#include "cu3088.h"
#include "claw.h"
diff --git a/drivers/s390/net/fsm.h b/drivers/s390/net/fsm.h
index 1b8a7e7c34f..5b98253be7a 100644
--- a/drivers/s390/net/fsm.h
+++ b/drivers/s390/net/fsm.h
@@ -140,7 +140,7 @@ fsm_record_history(fsm_instance *fi, int state, int event);
* 1 if current state or event is out of range
* !0 if state and event in range, but no action defined.
*/
-extern __inline__ int
+static inline int
fsm_event(fsm_instance *fi, int event, void *arg)
{
fsm_function_t r;
@@ -188,7 +188,7 @@ fsm_event(fsm_instance *fi, int event, void *arg)
* @param fi Pointer to FSM
* @param state The new state for this FSM.
*/
-extern __inline__ void
+static inline void
fsm_newstate(fsm_instance *fi, int newstate)
{
atomic_set(&fi->state,newstate);
@@ -208,7 +208,7 @@ fsm_newstate(fsm_instance *fi, int newstate)
*
* @return The current state of the FSM.
*/
-extern __inline__ int
+static inline int
fsm_getstate(fsm_instance *fi)
{
return atomic_read(&fi->state);
diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h
index 4eaa7017918..d9ea7ed2e46 100644
--- a/drivers/s390/s390mach.h
+++ b/drivers/s390/s390mach.h
@@ -88,7 +88,7 @@ struct crw {
#define CRW_ERC_PERRI 0x07 /* perm. error, facility init */
#define CRW_ERC_PMOD 0x08 /* installed parameters modified */
-extern __inline__ int stcrw(struct crw *pcrw )
+static inline int stcrw(struct crw *pcrw )
{
int ccode;
diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
index 071ae24be89..fd2cc7782f7 100644
--- a/drivers/sbus/char/cpwatchdog.c
+++ b/drivers/sbus/char/cpwatchdog.c
@@ -407,7 +407,7 @@ static long wd_compat_ioctl(struct file *file, unsigned int cmd,
case WIOCGSTAT:
lock_kernel();
rval = wd_ioctl(file->f_dentry->d_inode, file, cmd, arg);
- lock_kernel();
+ unlock_kernel();
break;
/* everything else is handled by the generic compat layer */
default:
diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c
index 39f54213a6d..2c86a4b809c 100644
--- a/drivers/sbus/char/display7seg.c
+++ b/drivers/sbus/char/display7seg.c
@@ -161,7 +161,7 @@ static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
writeb(regs, d7s_regs);
break;
};
- lock_kernel();
+ unlock_kernel();
return error;
}
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index 5028ac21432..383a95f34a0 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -596,6 +596,8 @@ static long openprom_compat_ioctl(struct file *file, unsigned int cmd,
lock_kernel();
break;
}
+
+ return rval;
}
static int openprom_open(struct inode * inode, struct file * file)
@@ -623,6 +625,7 @@ static struct file_operations openprom_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = openprom_ioctl,
+ .compat_ioctl = openprom_compat_ioctl,
.open = openprom_open,
.release = openprom_release,
};
diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c
index 9b988baf0b5..5774bdd0e26 100644
--- a/drivers/sbus/char/rtc.c
+++ b/drivers/sbus/char/rtc.c
@@ -210,6 +210,27 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
}
}
+static long rtc_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int rval = -ENOIOCTLCMD;
+
+ switch (cmd) {
+ /*
+ * These two are specific to this driver, the generic rtc ioctls
+ * are hanlded elsewhere.
+ */
+ case RTCGET:
+ case RTCSET:
+ lock_kernel();
+ rval = rtc_ioctl(file->f_dentry->d_inode, file, cmd, arg);
+ unlock_kernel();
+ break;
+ }
+
+ return rval;
+}
+
static int rtc_open(struct inode *inode, struct file *file)
{
int ret;
@@ -237,6 +258,7 @@ static struct file_operations rtc_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = rtc_ioctl,
+ .compat_ioctl = rtc_compat_ioctl,
.open = rtc_open,
.release = rtc_release,
};
diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h
index 98bad773f24..4f81fc39ec5 100644
--- a/drivers/scsi/3w-xxxx.h
+++ b/drivers/scsi/3w-xxxx.h
@@ -54,7 +54,6 @@
#ifndef _3W_XXXX_H
#define _3W_XXXX_H
-#include <linux/version.h>
#include <linux/types.h>
/* AEN strings */
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index 1589007e5a2..54996eaae97 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -2,7 +2,6 @@
#include <linux/mm.h>
#include <linux/blkdev.h>
#include <linux/sched.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/interrupt.h>
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 10f90d39374..10c470e7d31 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -42,8 +42,8 @@
#include <linux/sched.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
#include <asm/io.h>
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 052c6619acc..bc44222d6cc 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -49,7 +49,6 @@
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/smp_lock.h>
-#include <linux/version.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index be9edbe26db..f2a95447142 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -66,7 +66,6 @@
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/smp_lock.h>
-#include <linux/version.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c
index e02db80cab3..c0844fa32c5 100644
--- a/drivers/scsi/amiga7xx.c
+++ b/drivers/scsi/amiga7xx.c
@@ -11,7 +11,6 @@
#include <linux/mm.h>
#include <linux/blkdev.h>
#include <linux/sched.h>
-#include <linux/version.h>
#include <linux/config.h>
#include <linux/zorro.h>
#include <linux/stat.h>
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index 7fc8873de0b..a1bd8d95623 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -46,7 +46,6 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
#include <linux/libata.h>
diff --git a/drivers/scsi/bvme6000.c b/drivers/scsi/bvme6000.c
index 3c43928ab40..2958b8c2bfb 100644
--- a/drivers/scsi/bvme6000.c
+++ b/drivers/scsi/bvme6000.c
@@ -7,7 +7,6 @@
#include <linux/mm.h>
#include <linux/blkdev.h>
#include <linux/sched.h>
-#include <linux/version.h>
#include <linux/zorro.h>
#include <asm/setup.h>
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index 4b310cb7c93..5b154498056 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -2,7 +2,6 @@
#include <linux/mm.h>
#include <linux/blkdev.h>
#include <linux/sched.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/interrupt.h>
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 05ecc911e94..b60c1b9270f 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -18,12 +18,6 @@
*/
#include <linux/config.h>
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45)
-#error "This driver works only with kernel 2.5.45 or higher!"
-#endif
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
index 179140f48a9..f46c382e559 100644
--- a/drivers/scsi/ips.h
+++ b/drivers/scsi/ips.h
@@ -50,6 +50,7 @@
#ifndef _IPS_H_
#define _IPS_H_
+#include <linux/version.h>
#include <asm/uaccess.h>
#include <asm/io.h>
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 1c1a7caf785..a74b4071a66 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -51,8 +51,8 @@
#include <linux/jiffies.h>
#include <linux/scatterlist.h>
#include <scsi/scsi.h>
-#include "scsi.h"
#include "scsi_priv.h"
+#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#include <asm/io.h>
@@ -1144,7 +1144,7 @@ retry:
* ATA software reset (SRST, the default) does not appear
* to have this problem.
*/
- if ((using_edd) && (qc->tf.command == ATA_CMD_ID_ATA)) {
+ if ((using_edd) && (dev->class == ATA_DEV_ATA)) {
u8 err = qc->tf.feature;
if (err & ATA_ABORTED) {
dev->class = ATA_DEV_ATAPI;
@@ -2713,7 +2713,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
/**
* ata_poll_qc_complete - turn irq back on and finish qc
* @qc: Command to complete
- * @drv_stat: ATA status register content
+ * @err_mask: ATA status register content
*
* LOCKING:
* None. (grabs host lock)
@@ -2747,7 +2747,6 @@ static unsigned long ata_pio_poll(struct ata_port *ap)
u8 status;
unsigned int poll_state = HSM_ST_UNKNOWN;
unsigned int reg_state = HSM_ST_UNKNOWN;
- const unsigned int tmout_state = HSM_ST_TMOUT;
switch (ap->hsm_task_state) {
case HSM_ST:
@@ -2768,7 +2767,7 @@ static unsigned long ata_pio_poll(struct ata_port *ap)
status = ata_chk_status(ap);
if (status & ATA_BUSY) {
if (time_after(jiffies, ap->pio_task_timeout)) {
- ap->hsm_task_state = tmout_state;
+ ap->hsm_task_state = HSM_ST_TMOUT;
return 0;
}
ap->hsm_task_state = poll_state;
@@ -3478,7 +3477,7 @@ void ata_qc_free(struct ata_queued_cmd *qc)
/**
* ata_qc_complete - Complete an active ATA command
* @qc: Command to complete
- * @drv_stat: ATA Status register contents
+ * @err_mask: ATA Status register contents
*
* Indicate to the mid and upper layers that an ATA
* command has completed, with either an ok or not-ok status.
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index eb604b0a899..bb30fcdc929 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -37,9 +37,9 @@
#include <linux/blkdev.h>
#include <linux/spinlock.h>
#include <scsi/scsi.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
+#include <scsi/scsi_request.h>
#include <linux/libata.h>
#include <linux/hdreg.h>
#include <asm/uaccess.h>
@@ -131,7 +131,7 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
/**
* ata_cmd_ioctl - Handler for HDIO_DRIVE_CMD ioctl
- * @dev: Device to whom we are issuing command
+ * @scsidev: Device to which we are issuing command
* @arg: User provided data for issuing command
*
* LOCKING:
@@ -217,7 +217,7 @@ error:
/**
* ata_task_ioctl - Handler for HDIO_DRIVE_TASK ioctl
- * @dev: Device to whom we are issuing command
+ * @scsidev: Device to which we are issuing command
* @arg: User provided data for issuing command
*
* LOCKING:
@@ -416,6 +416,7 @@ void ata_dump_status(unsigned id, struct ata_taskfile *tf)
/**
* ata_to_sense_error - convert ATA error to SCSI error
+ * @id: ATA device number
* @drv_stat: value contained in ATA status register
* @drv_err: value contained in ATA error register
* @sk: the sense key we'll fill out
@@ -2231,7 +2232,7 @@ ata_scsi_map_proto(u8 byte1)
/**
* ata_scsi_pass_thru - convert ATA pass-thru CDB to taskfile
* @qc: command structure to be initialized
- * @cmd: SCSI command to convert
+ * @scsicmd: SCSI command to convert
*
* Handles either 12 or 16-byte versions of the CDB.
*
diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h
index 5accdee9bbf..4675343228a 100644
--- a/drivers/scsi/megaraid/mega_common.h
+++ b/drivers/scsi/megaraid/mega_common.h
@@ -25,7 +25,6 @@
#include <linux/delay.h>
#include <linux/blkdev.h>
#include <linux/list.h>
-#include <linux/version.h>
#include <linux/moduleparam.h>
#include <linux/dma-mapping.h>
#include <asm/semaphore.h>
diff --git a/drivers/scsi/megaraid/megaraid_mm.h b/drivers/scsi/megaraid/megaraid_mm.h
index 7e36c46e7c4..eb8c390a0fa 100644
--- a/drivers/scsi/megaraid/megaraid_mm.h
+++ b/drivers/scsi/megaraid/megaraid_mm.h
@@ -18,7 +18,6 @@
#include <linux/spinlock.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 2463f47adfd..3c32e69afcd 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -26,7 +26,6 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/list.h>
-#include <linux/version.h>
#include <linux/moduleparam.h>
#include <linux/module.h>
#include <linux/spinlock.h>
diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c
index c44382d6ae5..cb367c2c5c7 100644
--- a/drivers/scsi/mvme147.c
+++ b/drivers/scsi/mvme147.c
@@ -2,7 +2,6 @@
#include <linux/mm.h>
#include <linux/blkdev.h>
#include <linux/sched.h>
-#include <linux/version.h>
#include <linux/interrupt.h>
#include <asm/page.h>
diff --git a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c
index 9b43dc4148f..890e9e232da 100644
--- a/drivers/scsi/mvme16x.c
+++ b/drivers/scsi/mvme16x.c
@@ -7,7 +7,6 @@
#include <linux/mm.h>
#include <linux/blkdev.h>
#include <linux/sched.h>
-#include <linux/version.h>
#include <asm/page.h>
#include <asm/pgtable.h>
diff --git a/drivers/scsi/nsp32.h b/drivers/scsi/nsp32.h
index 5664398fa0a..5addf9fb1e1 100644
--- a/drivers/scsi/nsp32.h
+++ b/drivers/scsi/nsp32.h
@@ -16,6 +16,7 @@
#ifndef _NSP32_H
#define _NSP32_H
+#include <linux/version.h>
//#define NSP32_DEBUG 9
/*
diff --git a/drivers/scsi/pci2000.h b/drivers/scsi/pci2000.h
index f945a4232e5..0ebd8ce9e1d 100644
--- a/drivers/scsi/pci2000.h
+++ b/drivers/scsi/pci2000.h
@@ -26,9 +26,6 @@
#ifndef PSI_EIDE_SCSIOP
#define PSI_EIDE_SCSIOP 1
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
#define LINUXVERSION(v,p,s) (((v)<<16) + ((p)<<8) + (s))
/************************************************/
diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c
index 340ef38b452..78b4ff117af 100644
--- a/drivers/scsi/pdc_adma.c
+++ b/drivers/scsi/pdc_adma.c
@@ -41,7 +41,6 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/device.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
#include <asm/io.h>
#include <linux/libata.h>
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
index 1066c2610eb..93d55233af7 100644
--- a/drivers/scsi/sata_mv.c
+++ b/drivers/scsi/sata_mv.c
@@ -30,8 +30,8 @@
#include <linux/sched.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
#include <asm/io.h>
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index f57aa260791..37a4fae95ed 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -62,7 +62,6 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/device.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
#include <linux/libata.h>
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
index 0bfb82b669d..9edc9d91efc 100644
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/scsi/sata_promise.c
@@ -39,8 +39,8 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/device.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
#include <asm/io.h>
#include "sata_promise.h"
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
index c9aed15c8f4..d274ab23578 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -36,7 +36,6 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/device.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
#include <asm/io.h>
#include <linux/libata.h>
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index 6c986a0824b..d0e3c3c6c25 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -42,7 +42,6 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/device.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
#include <linux/libata.h>
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index 0c2d2fd0ec7..4682a50650b 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -37,7 +37,7 @@
#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <scsi/scsi_host.h>
-#include "scsi.h"
+#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
#include <asm/io.h>
diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c
index 223c835842e..42d7c4e9250 100644
--- a/drivers/scsi/sata_sis.c
+++ b/drivers/scsi/sata_sis.c
@@ -39,7 +39,6 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/device.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
#include <linux/libata.h>
diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c
index 86644f91f89..9895d1caefc 100644
--- a/drivers/scsi/sata_svw.c
+++ b/drivers/scsi/sata_svw.c
@@ -45,7 +45,6 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/device.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
#include <linux/libata.h>
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
index 8e79745e4e9..d5a38784352 100644
--- a/drivers/scsi/sata_sx4.c
+++ b/drivers/scsi/sata_sx4.c
@@ -39,8 +39,8 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/device.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
#include <asm/io.h>
#include "sata_promise.h"
diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c
index 8c1d71495bd..cf0baaa4e04 100644
--- a/drivers/scsi/sata_uli.c
+++ b/drivers/scsi/sata_uli.c
@@ -33,7 +33,6 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/device.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
#include <linux/libata.h>
diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c
index 09d3d96de0c..ab19d2ba2a4 100644
--- a/drivers/scsi/sata_via.c
+++ b/drivers/scsi/sata_via.c
@@ -42,7 +42,6 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#include <asm/io.h>
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
index bbc3d8abbd6..ce8a2fd7da8 100644
--- a/drivers/scsi/sata_vsc.c
+++ b/drivers/scsi/sata_vsc.c
@@ -43,7 +43,6 @@
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
#include <linux/libata.h>
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 9eb08b15c0b..3ded9daaf4a 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -48,10 +48,6 @@
#include <linux/stat.h>
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
#include "scsi_logging.h"
#include "scsi_debug.h"
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 62e3f340cc5..72ec59456e6 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -68,10 +68,6 @@ static int sg_proc_init(void);
static void sg_proc_cleanup(void);
#endif
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif /* LINUX_VERSION_CODE */
-
#define SG_ALLOW_DIO_DEF 0
#define SG_ALLOW_DIO_CODE /* compile out by commenting this define */
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index 0a0d8a908c7..bf2ceb54354 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -15,7 +15,6 @@
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/blkdev.h>
-#include <linux/version.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/spinlock.h>
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index 5754445fb36..fd63add6a57 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -77,7 +77,6 @@
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/delay.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include <asm/irq.h>
diff --git a/drivers/telephony/ixj.h b/drivers/telephony/ixj.h
index 51e3f7f6597..fbea4541c23 100644
--- a/drivers/telephony/ixj.h
+++ b/drivers/telephony/ixj.h
@@ -40,7 +40,6 @@
*****************************************************************************/
#define IXJ_VERSION 3031
-#include <linux/version.h>
#include <linux/types.h>
#include <linux/ixjuser.h>
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 975ace3f5b1..90451908533 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -49,7 +49,6 @@
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
-#include <linux/version.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
#include <linux/usb_gadget.h>
diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h
index 1bb455c045a..9b2e6f7cbb8 100644
--- a/drivers/usb/gadget/lh7a40x_udc.h
+++ b/drivers/usb/gadget/lh7a40x_udc.h
@@ -29,7 +29,6 @@
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/types.h>
-#include <linux/version.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/sched.h>
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index ee9cd7869d9..510d28a924d 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -32,7 +32,6 @@
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/types.h>
-#include <linux/version.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/sched.h>
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 06b6eba925b..9689efeb364 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -28,7 +28,6 @@
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/proc_fs.h>
diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c
index a8267cf17db..0eaabeb37ac 100644
--- a/drivers/usb/host/hc_crisv10.c
+++ b/drivers/usb/host/hc_crisv10.c
@@ -14,7 +14,6 @@
#include <linux/unistd.h>
#include <linux/interrupt.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/list.h>
#include <linux/spinlock.h>
diff --git a/drivers/usb/media/pwc/pwc-if.c b/drivers/usb/media/pwc/pwc-if.c
index b77e65c0365..5524fd70210 100644
--- a/drivers/usb/media/pwc/pwc-if.c
+++ b/drivers/usb/media/pwc/pwc-if.c
@@ -62,6 +62,7 @@
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+#include <linux/version.h>
#include <asm/io.h>
#include "pwc.h"
diff --git a/drivers/usb/media/pwc/pwc.h b/drivers/usb/media/pwc/pwc.h
index 267869dab18..6dd76bb3dff 100644
--- a/drivers/usb/media/pwc/pwc.h
+++ b/drivers/usb/media/pwc/pwc.h
@@ -25,8 +25,6 @@
#ifndef PWC_H
#define PWC_H
-#include <linux/version.h>
-
#include <linux/config.h>
#include <linux/module.h>
#include <linux/usb.h>
diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c
index f36c0b6c6e3..67612c81cb9 100644
--- a/drivers/usb/media/w9968cf.c
+++ b/drivers/usb/media/w9968cf.c
@@ -25,7 +25,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kmod.h>
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index c946c9a538a..41ef2b60675 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -37,7 +37,6 @@
*/
#include <linux/config.h>
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/signal.h>
diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h
index 401ff21d788..1d7a77cc7c4 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.h
+++ b/drivers/usb/misc/sisusbvga/sisusb.h
@@ -37,6 +37,7 @@
#ifndef _SISUSB_H_
#define _SISUSB_H_
+#include <linux/version.h>
#ifdef CONFIG_COMPAT
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10)
#include <linux/ioctl32.h>
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index 24584463553..be5c1a25ae2 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -48,7 +48,6 @@
*/
#include <linux/config.h>
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/signal.h>
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c
index f28bc240f9b..044fa4482f9 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_init.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.c
@@ -37,7 +37,6 @@
*/
#include <linux/config.h>
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 44b6ca290ce..25b6ca6ad08 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -593,38 +593,6 @@ config FB_EPSON1355
framebuffer. Product specs at
<http://www.erd.epson.com/vdc/html/products.htm>.
-config FB_E1356
- tristate "Epson SED1356 framebuffer support"
- depends on FB && EXPERIMENTAL && PCI && MIPS
-
-config PB1000_CRT
- bool "Use CRT on Pb1000 (J65)"
- depends on MIPS_PB1000=y && FB_E1356
-
-config PB1000_NTSC
- bool "Use Compsite NTSC on Pb1000 (J63)"
- depends on MIPS_PB1000=y && FB_E1356
-
-config PB1000_TFT
- bool "Use TFT Panel on Pb1000 (J64)"
- depends on MIPS_PB1000=y && FB_E1356
-
-config PB1500_CRT
- bool "Use CRT on Pb1500 " if MIPS_PB1500=y
- depends on FB_E1356
-
-config PB1500_CRT
- prompt "Use CRT on Pb1100 "
- depends on FB_E1356 && MIPS_PB1100=y
-
-config PB1500_TFT
- bool "Use TFT Panel on Pb1500 " if MIPS_PB1500=y
- depends on FB_E1356
-
-config PB1500_TFT
- prompt "Use TFT Panel on Pb1100 "
- depends on FB_E1356 && MIPS_PB1100=y
-
config FB_S1D13XXX
tristate "Epson S1D13XXX framebuffer support"
depends on FB
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
index 467a1d7ebbd..a3c2c45e29e 100644
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -518,7 +518,7 @@ static struct amba_driver clcd_driver = {
.id_table = clcdfb_id_table,
};
-int __init amba_clcdfb_init(void)
+static int __init amba_clcdfb_init(void)
{
if (fb_get_options("ambafb", NULL))
return -ENODEV;
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index acc81cb01d5..9d5015e9937 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -5,7 +5,6 @@
*
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index 470e6f0ee4d..68c690605aa 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -5,7 +5,6 @@
*
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c
index da664cea7ec..a7770c4f17d 100644
--- a/drivers/video/cfbimgblt.c
+++ b/drivers/video/cfbimgblt.c
@@ -80,10 +80,12 @@ static u32 cfb_tab32[] = {
#define LEFT_POS(bpp) (32 - bpp)
#define SHIFT_HIGH(val, bits) ((val) >> (bits))
#define SHIFT_LOW(val, bits) ((val) << (bits))
+#define BIT_NR(b) (7 - (b))
#else
#define LEFT_POS(bpp) (0)
#define SHIFT_HIGH(val, bits) ((val) << (bits))
#define SHIFT_LOW(val, bits) ((val) >> (bits))
+#define BIT_NR(b) (b)
#endif
static inline void color_imageblit(const struct fb_image *image,
@@ -177,7 +179,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
while (j--) {
l--;
- color = (*s & (1 << l)) ? fgcolor : bgcolor;
+ color = (*s & 1 << (BIT_NR(l))) ? fgcolor : bgcolor;
color <<= LEFT_POS(bpp);
val |= SHIFT_HIGH(color, shift);
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index fadf7c5d216..94c5f1392cc 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -101,6 +101,16 @@ config FRAMEBUFFER_CONSOLE
help
Low-level framebuffer-based console driver.
+config FRAMEBUFFER_CONSOLE_ROTATION
+ bool "Framebuffer Console Rotation"
+ depends on FRAMEBUFFER_CONSOLE
+ help
+ Enable display rotation for the framebuffer console. This is done
+ in software and may be significantly slower than a normally oriented
+ display. Note that the rotation is done at the console level only
+ such that other users of the framebuffer will remain normally
+ oriented.
+
config STI_CONSOLE
tristate "STI text console"
depends on PARISC
diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile
index 5222628accc..fed600c9ca5 100644
--- a/drivers/video/console/Makefile
+++ b/drivers/video/console/Makefile
@@ -31,6 +31,10 @@ obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o softcursor.o
ifeq ($(CONFIG_FB_TILEBLITTING),y)
obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += tileblit.o
endif
+ifeq ($(CONFIG_FRAMEBUFFER_CONSOLE_ROTATION),y)
+obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon_rotate.o fbcon_cw.o fbcon_ud.o \
+ fbcon_ccw.o
+endif
obj-$(CONFIG_FB_STI) += sticore.o font.o
diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c
index 67857b3cfc8..e65fc3ef763 100644
--- a/drivers/video/console/bitblit.c
+++ b/drivers/video/console/bitblit.c
@@ -22,35 +22,6 @@
/*
* Accelerated handlers.
*/
-#define FBCON_ATTRIBUTE_UNDERLINE 1
-#define FBCON_ATTRIBUTE_REVERSE 2
-#define FBCON_ATTRIBUTE_BOLD 4
-
-static inline int real_y(struct display *p, int ypos)
-{
- int rows = p->vrows;
-
- ypos += p->yscroll;
- return ypos < rows ? ypos : ypos - rows;
-}
-
-
-static inline int get_attribute(struct fb_info *info, u16 c)
-{
- int attribute = 0;
-
- if (fb_get_color_depth(&info->var, &info->fix) == 1) {
- if (attr_underline(c))
- attribute |= FBCON_ATTRIBUTE_UNDERLINE;
- if (attr_reverse(c))
- attribute |= FBCON_ATTRIBUTE_REVERSE;
- if (attr_bold(c))
- attribute |= FBCON_ATTRIBUTE_BOLD;
- }
-
- return attribute;
-}
-
static inline void update_attr(u8 *dst, u8 *src, int attribute,
struct vc_data *vc)
{
@@ -418,6 +389,18 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info,
ops->cursor_reset = 0;
}
+static int bit_update_start(struct fb_info *info)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+ int err;
+
+ err = fb_pan_display(info, &ops->var);
+ ops->var.xoffset = info->var.xoffset;
+ ops->var.yoffset = info->var.yoffset;
+ ops->var.vmode = info->var.vmode;
+ return err;
+}
+
void fbcon_set_bitops(struct fbcon_ops *ops)
{
ops->bmove = bit_bmove;
@@ -425,6 +408,11 @@ void fbcon_set_bitops(struct fbcon_ops *ops)
ops->putcs = bit_putcs;
ops->clear_margins = bit_clear_margins;
ops->cursor = bit_cursor;
+ ops->update_start = bit_update_start;
+ ops->rotate_font = NULL;
+
+ if (ops->rotate)
+ fbcon_set_rotate(ops);
}
EXPORT_SYMBOL(fbcon_set_bitops);
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 3cf1b61ff1f..e7802ffe549 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -107,6 +107,8 @@ enum {
};
struct display fb_display[MAX_NR_CONSOLES];
+EXPORT_SYMBOL(fb_display);
+
static signed char con2fb_map[MAX_NR_CONSOLES];
static signed char con2fb_map_boot[MAX_NR_CONSOLES];
static int logo_height;
@@ -130,6 +132,9 @@ static char fontname[40];
/* current fb_info */
static int info_idx = -1;
+/* console rotation */
+static int rotate;
+
static const struct consw fb_con;
#define CM_SOFTBACK (8)
@@ -176,7 +181,6 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines);
/*
* Internal routines
*/
-static __inline__ int real_y(struct display *p, int ypos);
static __inline__ void ywrap_up(struct vc_data *vc, int count);
static __inline__ void ywrap_down(struct vc_data *vc, int count);
static __inline__ void ypan_up(struct vc_data *vc, int count);
@@ -189,6 +193,8 @@ static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *va
int unit);
static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
int line, int count, int dy);
+static void fbcon_modechanged(struct fb_info *info);
+static void fbcon_set_all_vcs(struct fb_info *info);
#ifdef CONFIG_MAC
/*
@@ -203,6 +209,88 @@ static irqreturn_t fb_vbl_detect(int irq, void *dummy, struct pt_regs *fp)
}
#endif
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
+static inline void fbcon_set_rotation(struct fb_info *info, struct display *p)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+
+ if (!(info->flags & FBINFO_MISC_TILEBLITTING) &&
+ p->con_rotate < 4)
+ ops->rotate = p->con_rotate;
+ else
+ ops->rotate = 0;
+}
+
+static void fbcon_rotate(struct fb_info *info, u32 rotate)
+{
+ struct fbcon_ops *ops= info->fbcon_par;
+ struct fb_info *fb_info;
+
+ if (!ops || ops->currcon == -1)
+ return;
+
+ fb_info = registered_fb[con2fb_map[ops->currcon]];
+
+ if (info == fb_info) {
+ struct display *p = &fb_display[ops->currcon];
+
+ if (rotate < 4)
+ p->con_rotate = rotate;
+ else
+ p->con_rotate = 0;
+
+ fbcon_modechanged(info);
+ }
+}
+
+static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+ struct vc_data *vc;
+ struct display *p;
+ int i;
+
+ if (!ops || ops->currcon < 0 || rotate > 3)
+ return;
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ vc = vc_cons[i].d;
+ if (!vc || vc->vc_mode != KD_TEXT ||
+ registered_fb[con2fb_map[i]] != info)
+ continue;
+
+ p = &fb_display[vc->vc_num];
+ p->con_rotate = rotate;
+ }
+
+ fbcon_set_all_vcs(info);
+}
+#else
+static inline void fbcon_set_rotation(struct fb_info *info, struct display *p)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+
+ ops->rotate = FB_ROTATE_UR;
+}
+
+static void fbcon_rotate(struct fb_info *info, u32 rotate)
+{
+ return;
+}
+
+static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
+{
+ return;
+}
+#endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */
+
+static int fbcon_get_rotate(struct fb_info *info)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+
+ return (ops) ? ops->rotate : 0;
+}
+
static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info)
{
struct fbcon_ops *ops = info->fbcon_par;
@@ -422,6 +510,14 @@ static int __init fb_console_setup(char *this_opt)
last_fb_vc = simple_strtoul(options, &options, 10) - 1;
fbcon_is_default = 0;
}
+
+ if (!strncmp(options, "rotate:", 7)) {
+ options += 7;
+ if (*options)
+ rotate = simple_strtoul(options, &options, 0);
+ if (rotate > 3)
+ rotate = 0;
+ }
}
return 0;
}
@@ -480,6 +576,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
int cols, int rows, int new_cols, int new_rows)
{
/* Need to make room for the logo */
+ struct fbcon_ops *ops = info->fbcon_par;
int cnt, erase = vc->vc_video_erase_char, step;
unsigned short *save = NULL, *r, *q;
@@ -489,7 +586,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
*/
if (fb_get_color_depth(&info->var, &info->fix) == 1)
erase &= ~0x400;
- logo_height = fb_prepare_logo(info);
+ logo_height = fb_prepare_logo(info, ops->rotate);
logo_lines = (logo_height + vc->vc_font.height - 1) /
vc->vc_font.height;
q = (unsigned short *) (vc->vc_origin +
@@ -558,16 +655,24 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info,
if ((info->flags & FBINFO_MISC_TILEBLITTING))
fbcon_set_tileops(vc, info, p, ops);
- else
+ else {
+ struct display *disp;
+
+ disp = (p) ? p : &fb_display[vc->vc_num];
+ fbcon_set_rotation(info, disp);
fbcon_set_bitops(ops);
+ }
}
#else
static void set_blitting_type(struct vc_data *vc, struct fb_info *info,
struct display *p)
{
struct fbcon_ops *ops = info->fbcon_par;
+ struct display *disp;
info->flags &= ~FBINFO_MISC_TILEBLITTING;
+ disp = (p) ? p : &fb_display[vc->vc_num];
+ fbcon_set_rotation(info, disp);
fbcon_set_bitops(ops);
}
#endif /* CONFIG_MISC_TILEBLITTING */
@@ -627,6 +732,7 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
fbcon_del_cursor_timer(oldinfo);
kfree(ops->cursor_state.mask);
kfree(ops->cursor_data);
+ kfree(ops->fontbuffer);
kfree(oldinfo->fbcon_par);
oldinfo->fbcon_par = NULL;
module_put(oldinfo->fbops->owner);
@@ -827,7 +933,9 @@ static const char *fbcon_startup(void)
memset(ops, 0, sizeof(struct fbcon_ops));
ops->currcon = -1;
ops->graphics = 1;
+ ops->cur_rotate = -1;
info->fbcon_par = ops;
+ p->con_rotate = rotate;
set_blitting_type(vc, info, NULL);
if (info->fix.type != FB_TYPE_TEXT) {
@@ -866,8 +974,10 @@ static const char *fbcon_startup(void)
vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */
}
- cols = info->var.xres / vc->vc_font.width;
- rows = info->var.yres / vc->vc_font.height;
+ cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+ rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+ cols /= vc->vc_font.width;
+ rows /= vc->vc_font.height;
vc_resize(vc, cols, rows);
DPRINTK("mode: %s\n", info->fix.id);
@@ -953,8 +1063,6 @@ static void fbcon_init(struct vc_data *vc, int init)
(info->fix.type == FB_TYPE_TEXT))
logo = 0;
- info->var.xoffset = info->var.yoffset = p->yscroll = 0; /* reset wrap/pan */
-
if (var_to_display(p, &info->var, info))
return;
@@ -986,13 +1094,18 @@ static void fbcon_init(struct vc_data *vc, int init)
if (!*vc->vc_uni_pagedir_loc)
con_copy_unimap(vc, svc);
+ ops = info->fbcon_par;
+ p->con_rotate = rotate;
+ set_blitting_type(vc, info, NULL);
+
cols = vc->vc_cols;
rows = vc->vc_rows;
- new_cols = info->var.xres / vc->vc_font.width;
- new_rows = info->var.yres / vc->vc_font.height;
+ new_cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+ new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+ new_cols /= vc->vc_font.width;
+ new_rows /= vc->vc_font.height;
vc_resize(vc, new_cols, new_rows);
- ops = info->fbcon_par;
/*
* We must always set the mode. The mode of the previous console
* driver could be in the same resolution but we are using different
@@ -1030,6 +1143,12 @@ static void fbcon_init(struct vc_data *vc, int init)
if (vc == svc && softback_buf)
fbcon_update_softback(vc);
+
+ if (ops->rotate_font && ops->rotate_font(info, vc, p)) {
+ ops->rotate = FB_ROTATE_UR;
+ set_blitting_type(vc, info, p);
+ }
+
}
static void fbcon_deinit(struct vc_data *vc)
@@ -1066,15 +1185,6 @@ static void fbcon_deinit(struct vc_data *vc)
* restriction is simplicity & efficiency at the moment.
*/
-static __inline__ int real_y(struct display *p, int ypos)
-{
- int rows = p->vrows;
-
- ypos += p->yscroll;
- return ypos < rows ? ypos : ypos - rows;
-}
-
-
static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
int width)
{
@@ -1162,13 +1272,6 @@ static int scrollback_phys_max = 0;
static int scrollback_max = 0;
static int scrollback_current = 0;
-static int update_var(int con, struct fb_info *info)
-{
- if (con == ((struct fbcon_ops *)info->fbcon_par)->currcon)
- return fb_pan_display(info, &info->var);
- return 0;
-}
-
/*
* If no vc is existent yet, just set struct display
*/
@@ -1178,7 +1281,6 @@ static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *va
struct display *p = &fb_display[unit];
struct display *t = &fb_display[fg_console];
- var->xoffset = var->yoffset = p->yscroll = 0;
if (var_to_display(p, var, info))
return;
@@ -1194,9 +1296,9 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
struct display *p = &fb_display[vc->vc_num], *t;
struct vc_data **default_mode = vc->vc_display_fg;
struct vc_data *svc = *default_mode;
+ struct fbcon_ops *ops = info->fbcon_par;
int rows, cols, charcnt = 256;
- var->xoffset = var->yoffset = p->yscroll = 0;
if (var_to_display(p, var, info))
return;
t = &fb_display[svc->vc_num];
@@ -1213,9 +1315,10 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
var->activate = FB_ACTIVATE_NOW;
info->var.activate = var->activate;
- info->var.yoffset = info->var.xoffset = 0;
+ var->yoffset = info->var.yoffset;
+ var->xoffset = info->var.xoffset;
fb_set_var(info, var);
-
+ ops->var = info->var;
vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
if (charcnt == 256) {
@@ -1231,9 +1334,12 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
if (!*vc->vc_uni_pagedir_loc)
con_copy_unimap(vc, svc);
- cols = var->xres / vc->vc_font.width;
- rows = var->yres / vc->vc_font.height;
+ cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+ rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+ cols /= vc->vc_font.width;
+ rows /= vc->vc_font.height;
vc_resize(vc, cols, rows);
+
if (CON_IS_VISIBLE(vc)) {
update_screen(vc);
if (softback_buf)
@@ -1244,15 +1350,16 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
static __inline__ void ywrap_up(struct vc_data *vc, int count)
{
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fbcon_ops *ops = info->fbcon_par;
struct display *p = &fb_display[vc->vc_num];
p->yscroll += count;
if (p->yscroll >= p->vrows) /* Deal with wrap */
p->yscroll -= p->vrows;
- info->var.xoffset = 0;
- info->var.yoffset = p->yscroll * vc->vc_font.height;
- info->var.vmode |= FB_VMODE_YWRAP;
- update_var(vc->vc_num, info);
+ ops->var.xoffset = 0;
+ ops->var.yoffset = p->yscroll * vc->vc_font.height;
+ ops->var.vmode |= FB_VMODE_YWRAP;
+ ops->update_start(info);
scrollback_max += count;
if (scrollback_max > scrollback_phys_max)
scrollback_max = scrollback_phys_max;
@@ -1262,15 +1369,16 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count)
static __inline__ void ywrap_down(struct vc_data *vc, int count)
{
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fbcon_ops *ops = info->fbcon_par;
struct display *p = &fb_display[vc->vc_num];
p->yscroll -= count;
if (p->yscroll < 0) /* Deal with wrap */
p->yscroll += p->vrows;
- info->var.xoffset = 0;
- info->var.yoffset = p->yscroll * vc->vc_font.height;
- info->var.vmode |= FB_VMODE_YWRAP;
- update_var(vc->vc_num, info);
+ ops->var.xoffset = 0;
+ ops->var.yoffset = p->yscroll * vc->vc_font.height;
+ ops->var.vmode |= FB_VMODE_YWRAP;
+ ops->update_start(info);
scrollback_max -= count;
if (scrollback_max < 0)
scrollback_max = 0;
@@ -1289,10 +1397,11 @@ static __inline__ void ypan_up(struct vc_data *vc, int count)
0, 0, 0, vc->vc_rows, vc->vc_cols);
p->yscroll -= p->vrows - vc->vc_rows;
}
- info->var.xoffset = 0;
- info->var.yoffset = p->yscroll * vc->vc_font.height;
- info->var.vmode &= ~FB_VMODE_YWRAP;
- update_var(vc->vc_num, info);
+
+ ops->var.xoffset = 0;
+ ops->var.yoffset = p->yscroll * vc->vc_font.height;
+ ops->var.vmode &= ~FB_VMODE_YWRAP;
+ ops->update_start(info);
fbcon_clear_margins(vc, 1);
scrollback_max += count;
if (scrollback_max > scrollback_phys_max)
@@ -1303,6 +1412,7 @@ static __inline__ void ypan_up(struct vc_data *vc, int count)
static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
{
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fbcon_ops *ops = info->fbcon_par;
struct display *p = &fb_display[vc->vc_num];
int redraw = 0;
@@ -1312,12 +1422,13 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
redraw = 1;
}
- info->var.xoffset = 0;
- info->var.yoffset = p->yscroll * vc->vc_font.height;
- info->var.vmode &= ~FB_VMODE_YWRAP;
if (redraw)
fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t);
- update_var(vc->vc_num, info);
+
+ ops->var.xoffset = 0;
+ ops->var.yoffset = p->yscroll * vc->vc_font.height;
+ ops->var.vmode &= ~FB_VMODE_YWRAP;
+ ops->update_start(info);
fbcon_clear_margins(vc, 1);
scrollback_max += count;
if (scrollback_max > scrollback_phys_max)
@@ -1337,10 +1448,11 @@ static __inline__ void ypan_down(struct vc_data *vc, int count)
0, vc->vc_rows, vc->vc_cols);
p->yscroll += p->vrows - vc->vc_rows;
}
- info->var.xoffset = 0;
- info->var.yoffset = p->yscroll * vc->vc_font.height;
- info->var.vmode &= ~FB_VMODE_YWRAP;
- update_var(vc->vc_num, info);
+
+ ops->var.xoffset = 0;
+ ops->var.yoffset = p->yscroll * vc->vc_font.height;
+ ops->var.vmode &= ~FB_VMODE_YWRAP;
+ ops->update_start(info);
fbcon_clear_margins(vc, 1);
scrollback_max -= count;
if (scrollback_max < 0)
@@ -1351,6 +1463,7 @@ static __inline__ void ypan_down(struct vc_data *vc, int count)
static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
{
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fbcon_ops *ops = info->fbcon_par;
struct display *p = &fb_display[vc->vc_num];
int redraw = 0;
@@ -1359,12 +1472,14 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
p->yscroll += p->vrows - vc->vc_rows;
redraw = 1;
}
- info->var.xoffset = 0;
- info->var.yoffset = p->yscroll * vc->vc_font.height;
- info->var.vmode &= ~FB_VMODE_YWRAP;
+
if (redraw)
fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count);
- update_var(vc->vc_num, info);
+
+ ops->var.xoffset = 0;
+ ops->var.yoffset = p->yscroll * vc->vc_font.height;
+ ops->var.vmode &= ~FB_VMODE_YWRAP;
+ ops->update_start(info);
fbcon_clear_margins(vc, 1);
scrollback_max -= count;
if (scrollback_max < 0)
@@ -1838,31 +1953,41 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int s
height, width);
}
-static __inline__ void updatescrollmode(struct display *p, struct fb_info *info,
+static __inline__ void updatescrollmode(struct display *p,
+ struct fb_info *info,
struct vc_data *vc)
{
+ struct fbcon_ops *ops = info->fbcon_par;
int fh = vc->vc_font.height;
int cap = info->flags;
- int good_pan = (cap & FBINFO_HWACCEL_YPAN)
- && divides(info->fix.ypanstep, vc->vc_font.height)
- && info->var.yres_virtual > info->var.yres;
- int good_wrap = (cap & FBINFO_HWACCEL_YWRAP)
- && divides(info->fix.ywrapstep, vc->vc_font.height)
- && divides(vc->vc_font.height, info->var.yres_virtual);
+ u16 t = 0;
+ int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
+ info->fix.xpanstep);
+ int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t);
+ int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+ int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
+ info->var.xres_virtual);
+ int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&
+ divides(ypan, vc->vc_font.height) && vyres > yres;
+ int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
+ divides(ywrap, vc->vc_font.height) &&
+ divides(vc->vc_font.height, vyres);
int reading_fast = cap & FBINFO_READS_FAST;
- int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) && !(cap & FBINFO_HWACCEL_DISABLED);
- int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) && !(cap & FBINFO_HWACCEL_DISABLED);
-
- p->vrows = info->var.yres_virtual/fh;
- if (info->var.yres > (fh * (vc->vc_rows + 1)))
- p->vrows -= (info->var.yres - (fh * vc->vc_rows)) / fh;
- if ((info->var.yres % fh) && (info->var.yres_virtual % fh <
- info->var.yres % fh))
+ int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) &&
+ !(cap & FBINFO_HWACCEL_DISABLED);
+ int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) &&
+ !(cap & FBINFO_HWACCEL_DISABLED);
+
+ p->vrows = vyres/fh;
+ if (yres > (fh * (vc->vc_rows + 1)))
+ p->vrows -= (yres - (fh * vc->vc_rows)) / fh;
+ if ((yres % fh) && (vyres % fh < yres % fh))
p->vrows--;
if (good_wrap || good_pan) {
if (reading_fast || fast_copyarea)
- p->scrollmode = good_wrap ? SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
+ p->scrollmode = good_wrap ?
+ SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
else
p->scrollmode = good_wrap ? SCROLL_REDRAW :
SCROLL_PAN_REDRAW;
@@ -1878,17 +2003,23 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
unsigned int height)
{
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fbcon_ops *ops = info->fbcon_par;
struct display *p = &fb_display[vc->vc_num];
struct fb_var_screeninfo var = info->var;
- int x_diff, y_diff;
- int fw = vc->vc_font.width;
- int fh = vc->vc_font.height;
-
- var.xres = width * fw;
- var.yres = height * fh;
+ int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
+
+ virt_w = FBCON_SWAP(ops->rotate, width, height);
+ virt_h = FBCON_SWAP(ops->rotate, height, width);
+ virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width,
+ vc->vc_font.height);
+ virt_fh = FBCON_SWAP(ops->rotate, vc->vc_font.height,
+ vc->vc_font.width);
+ var.xres = virt_w * virt_fw;
+ var.yres = virt_h * virt_fh;
x_diff = info->var.xres - var.xres;
y_diff = info->var.yres - var.yres;
- if (x_diff < 0 || x_diff > fw || (y_diff < 0 || y_diff > fh)) {
+ if (x_diff < 0 || x_diff > virt_fw ||
+ y_diff < 0 || y_diff > virt_fh) {
struct fb_videomode *mode;
DPRINTK("attempting resize %ix%i\n", var.xres, var.yres);
@@ -1898,7 +2029,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
display_to_var(&var, p);
fb_videomode_to_var(&var, mode);
- if (width > var.xres/fw || height > var.yres/fh)
+ if (virt_w > var.xres/virt_fw || virt_h > var.yres/virt_fh)
return -EINVAL;
DPRINTK("resize now %ix%i\n", var.xres, var.yres);
@@ -1908,6 +2039,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
fb_set_var(info, &var);
}
var_to_display(p, &info->var, info);
+ ops->var = info->var;
}
updatescrollmode(p, info, vc);
return 0;
@@ -1916,11 +2048,13 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
static int fbcon_switch(struct vc_data *vc)
{
struct fb_info *info, *old_info = NULL;
+ struct fbcon_ops *ops;
struct display *p = &fb_display[vc->vc_num];
struct fb_var_screeninfo var;
int i, prev_console;
info = registered_fb[con2fb_map[vc->vc_num]];
+ ops = info->fbcon_par;
if (softback_top) {
if (softback_lines)
@@ -1939,7 +2073,7 @@ static int fbcon_switch(struct vc_data *vc)
logo_shown = FBCON_LOGO_CANSHOW;
}
- prev_console = ((struct fbcon_ops *)info->fbcon_par)->currcon;
+ prev_console = ops->currcon;
if (prev_console != -1)
old_info = registered_fb[con2fb_map[prev_console]];
/*
@@ -1952,9 +2086,9 @@ static int fbcon_switch(struct vc_data *vc)
*/
for (i = 0; i < FB_MAX; i++) {
if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) {
- struct fbcon_ops *ops = registered_fb[i]->fbcon_par;
+ struct fbcon_ops *o = registered_fb[i]->fbcon_par;
- ops->currcon = vc->vc_num;
+ o->currcon = vc->vc_num;
}
}
memset(&var, 0, sizeof(struct fb_var_screeninfo));
@@ -1966,8 +2100,11 @@ static int fbcon_switch(struct vc_data *vc)
* in fb_set_var()
*/
info->var.activate = var.activate;
- info->var.yoffset = info->var.xoffset = p->yscroll = 0;
+ var.yoffset = info->var.yoffset;
+ var.xoffset = info->var.xoffset;
+ var.vmode = info->var.vmode;
fb_set_var(info, &var);
+ ops->var = info->var;
if (old_info != NULL && old_info != info) {
if (info->fbops->fb_set_par)
@@ -1977,7 +2114,12 @@ static int fbcon_switch(struct vc_data *vc)
}
set_blitting_type(vc, info, p);
- ((struct fbcon_ops *)info->fbcon_par)->cursor_reset = 1;
+ ops->cursor_reset = 1;
+
+ if (ops->rotate_font && ops->rotate_font(info, vc, p)) {
+ ops->rotate = FB_ROTATE_UR;
+ set_blitting_type(vc, info, p);
+ }
vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
@@ -1997,10 +2139,11 @@ static int fbcon_switch(struct vc_data *vc)
scrollback_phys_max = 0;
break;
}
+
scrollback_max = 0;
scrollback_current = 0;
-
- update_var(vc->vc_num, info);
+ ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
+ ops->update_start(info);
fbcon_set_palette(vc, color_table);
fbcon_clear_margins(vc, 0);
@@ -2008,7 +2151,7 @@ static int fbcon_switch(struct vc_data *vc)
logo_shown = fg_console;
/* This is protected above by initmem_freed */
- fb_show_logo(info);
+ fb_show_logo(info, ops->rotate);
update_region(vc,
vc->vc_origin + vc->vc_size_row * vc->vc_top,
vc->vc_size_row * (vc->vc_bottom -
@@ -2047,6 +2190,7 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
fb_set_var(info, &var);
ops->graphics = 0;
+ ops->var = info->var;
}
}
@@ -2135,6 +2279,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
const u8 * data, int userfont)
{
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fbcon_ops *ops = info->fbcon_par;
struct display *p = &fb_display[vc->vc_num];
int resize;
int cnt;
@@ -2214,9 +2359,13 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
}
if (resize) {
- /* reset wrap/pan */
- info->var.xoffset = info->var.yoffset = p->yscroll = 0;
- vc_resize(vc, info->var.xres / w, info->var.yres / h);
+ int cols, rows;
+
+ cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+ rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+ cols /= w;
+ rows /= h;
+ vc_resize(vc, cols, rows);
if (CON_IS_VISIBLE(vc) && softback_buf)
fbcon_update_softback(vc);
} else if (CON_IS_VISIBLE(vc)
@@ -2444,6 +2593,7 @@ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt)
static int fbcon_scrolldelta(struct vc_data *vc, int lines)
{
struct fb_info *info = registered_fb[con2fb_map[fg_console]];
+ struct fbcon_ops *ops = info->fbcon_par;
struct display *p = &fb_display[fg_console];
int offset, limit, scrollback_old;
@@ -2520,9 +2670,11 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
offset += limit;
else if (offset >= limit)
offset -= limit;
- info->var.xoffset = 0;
- info->var.yoffset = offset * vc->vc_font.height;
- update_var(vc->vc_num, info);
+
+ ops->var.xoffset = 0;
+ ops->var.yoffset = offset * vc->vc_font.height;
+ ops->update_start(info);
+
if (!scrollback_current)
fbcon_cursor(vc, CM_DRAW);
return 0;
@@ -2570,22 +2722,25 @@ static void fbcon_modechanged(struct fb_info *info)
if (!ops || ops->currcon < 0)
return;
vc = vc_cons[ops->currcon].d;
- if (vc->vc_mode != KD_TEXT || registered_fb[con2fb_map[ops->currcon]] != info)
+ if (vc->vc_mode != KD_TEXT ||
+ registered_fb[con2fb_map[ops->currcon]] != info)
return;
p = &fb_display[vc->vc_num];
-
- info->var.xoffset = info->var.yoffset = p->yscroll = 0;
+ set_blitting_type(vc, info, p);
if (CON_IS_VISIBLE(vc)) {
var_to_display(p, &info->var, info);
- cols = info->var.xres / vc->vc_font.width;
- rows = info->var.yres / vc->vc_font.height;
+ cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+ rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+ cols /= vc->vc_font.width;
+ rows /= vc->vc_font.height;
vc_resize(vc, cols, rows);
updatescrollmode(p, info, vc);
scrollback_max = 0;
scrollback_current = 0;
- update_var(vc->vc_num, info);
+ ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
+ ops->update_start(info);
fbcon_set_palette(vc, color_table);
update_screen(vc);
if (softback_buf)
@@ -2610,18 +2765,20 @@ static void fbcon_set_all_vcs(struct fb_info *info)
continue;
p = &fb_display[vc->vc_num];
-
- info->var.xoffset = info->var.yoffset = p->yscroll = 0;
+ set_blitting_type(vc, info, p);
var_to_display(p, &info->var, info);
- cols = info->var.xres / vc->vc_font.width;
- rows = info->var.yres / vc->vc_font.height;
+ cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+ rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+ cols /= vc->vc_font.width;
+ rows /= vc->vc_font.height;
vc_resize(vc, cols, rows);
if (CON_IS_VISIBLE(vc)) {
updatescrollmode(p, info, vc);
scrollback_max = 0;
scrollback_current = 0;
- update_var(vc->vc_num, info);
+ ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
+ ops->update_start(info);
fbcon_set_palette(vc, color_table);
update_screen(vc);
if (softback_buf)
@@ -2771,6 +2928,14 @@ static int fbcon_event_notify(struct notifier_block *self,
case FB_EVENT_NEW_MODELIST:
fbcon_new_modelist(info);
break;
+ case FB_EVENT_SET_CON_ROTATE:
+ fbcon_rotate(info, *(int *)event->data);
+ break;
+ case FB_EVENT_GET_CON_ROTATE:
+ ret = fbcon_get_rotate(info);
+ break;
+ case FB_EVENT_SET_CON_ROTATE_ALL:
+ fbcon_rotate_all(info, *(int *)event->data);
}
return ret;
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index b68e0e2c2d1..accfd7bd8e9 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -27,15 +27,15 @@
*/
struct display {
- /* Filled in by the frame buffer device */
- u_short inverse; /* != 0 text black on white as default */
/* Filled in by the low-level console driver */
const u_char *fontdata;
int userfont; /* != 0 if fontdata kmalloc()ed */
u_short scrollmode; /* Scroll Method */
+ u_short inverse; /* != 0 text black on white as default */
short yscroll; /* Hardware scrolling */
int vrows; /* number of virtual rows */
int cursor_shape;
+ int con_rotate;
u32 xres_virtual;
u32 yres_virtual;
u32 height;
@@ -52,6 +52,8 @@ struct display {
struct fb_videomode *mode;
};
+extern struct display fb_display[];
+
struct fbcon_ops {
void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy,
int sx, int dy, int dx, int height, int width);
@@ -63,8 +65,12 @@ struct fbcon_ops {
void (*clear_margins)(struct vc_data *vc, struct fb_info *info,
int bottom_only);
void (*cursor)(struct vc_data *vc, struct fb_info *info,
- struct display *p, int mode, int softback_lines, int fg, int bg);
-
+ struct display *p, int mode, int softback_lines,
+ int fg, int bg);
+ int (*update_start)(struct fb_info *info);
+ int (*rotate_font)(struct fb_info *info, struct vc_data *vc,
+ struct display *p);
+ struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */
struct timer_list cursor_timer; /* Cursor timer */
struct fb_cursor cursor_state;
int currcon; /* Current VC. */
@@ -73,7 +79,12 @@ struct fbcon_ops {
int blank_state;
int graphics;
int flags;
+ int rotate;
+ int cur_rotate;
char *cursor_data;
+ u8 *fontbuffer;
+ u8 *fontdata;
+ u32 fd_size;
};
/*
* Attribute Decoding
@@ -168,4 +179,47 @@ extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info,
#endif
extern void fbcon_set_bitops(struct fbcon_ops *ops);
extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor);
+
+#define FBCON_ATTRIBUTE_UNDERLINE 1
+#define FBCON_ATTRIBUTE_REVERSE 2
+#define FBCON_ATTRIBUTE_BOLD 4
+
+static inline int real_y(struct display *p, int ypos)
+{
+ int rows = p->vrows;
+
+ ypos += p->yscroll;
+ return ypos < rows ? ypos : ypos - rows;
+}
+
+
+static inline int get_attribute(struct fb_info *info, u16 c)
+{
+ int attribute = 0;
+
+ if (fb_get_color_depth(&info->var, &info->fix) == 1) {
+ if (attr_underline(c))
+ attribute |= FBCON_ATTRIBUTE_UNDERLINE;
+ if (attr_reverse(c))
+ attribute |= FBCON_ATTRIBUTE_REVERSE;
+ if (attr_bold(c))
+ attribute |= FBCON_ATTRIBUTE_BOLD;
+ }
+
+ return attribute;
+}
+
+#define FBCON_SWAP(i,r,v) ({ \
+ typeof(r) _r = (r); \
+ typeof(v) _v = (v); \
+ (void) (&_r == &_v); \
+ (i == FB_ROTATE_UR || i == FB_ROTATE_UD) ? _r : _v; })
+
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
+extern void fbcon_set_rotate(struct fbcon_ops *ops);
+#else
+#define fbcon_set_rotate(x) do {} while(0)
+#endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */
+
#endif /* _VIDEO_FBCON_H */
+
diff --git a/drivers/video/console/fbcon_ccw.c b/drivers/video/console/fbcon_ccw.c
new file mode 100644
index 00000000000..680aabab73c
--- /dev/null
+++ b/drivers/video/console/fbcon_ccw.c
@@ -0,0 +1,428 @@
+/*
+ * linux/drivers/video/console/fbcon_ccw.c -- Software Rotation - 270 degrees
+ *
+ * Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <asm/types.h>
+#include "fbcon.h"
+#include "fbcon_rotate.h"
+
+/*
+ * Rotation 270 degrees
+ */
+
+static inline void ccw_update_attr(u8 *dst, u8 *src, int attribute,
+ struct vc_data *vc)
+{
+ int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
+ int width = (vc->vc_font.height + 7) >> 3;
+ int mod = vc->vc_font.height % 8;
+ u8 c, msk = ~(0xff << offset), msk1 = 0;
+
+ if (mod)
+ msk <<= (8 - mod);
+
+ if (offset > mod)
+ set_bit(FBCON_BIT(7), (void *)&msk1);
+
+ for (i = 0; i < vc->vc_font.width; i++) {
+ for (j = 0; j < width; j++) {
+ c = *src;
+
+ if (attribute & FBCON_ATTRIBUTE_UNDERLINE) {
+ if (j == width - 1)
+ c |= msk;
+
+ if (msk1 && j == width - 2)
+ c |= msk1;
+ }
+
+ if (attribute & FBCON_ATTRIBUTE_BOLD && i)
+ *(dst - width) |= c;
+
+ if (attribute & FBCON_ATTRIBUTE_REVERSE)
+ c = ~c;
+ src++;
+ *dst++ = c;
+ }
+ }
+}
+
+
+static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ int sx, int dy, int dx, int height, int width)
+{
+ struct display *p = &fb_display[vc->vc_num];
+ struct fb_copyarea area;
+ u32 vyres = GETVYRES(p->scrollmode, info);
+
+ area.sx = sy * vc->vc_font.height;
+ area.sy = vyres - ((sx + width) * vc->vc_font.width);
+ area.dx = dy * vc->vc_font.height;
+ area.dy = vyres - ((dx + width) * vc->vc_font.width);
+ area.width = height * vc->vc_font.height;
+ area.height = width * vc->vc_font.width;
+
+ info->fbops->fb_copyarea(info, &area);
+}
+
+static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
+ int sx, int height, int width)
+{
+ struct display *p = &fb_display[vc->vc_num];
+ struct fb_fillrect region;
+ int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+ u32 vyres = GETVYRES(p->scrollmode, info);
+
+ region.color = attr_bgcol_ec(bgshift,vc);
+ region.dx = sy * vc->vc_font.height;
+ region.dy = vyres - ((sx + width) * vc->vc_font.width);
+ region.height = width * vc->vc_font.width;
+ region.width = height * vc->vc_font.height;
+ region.rop = ROP_COPY;
+
+ info->fbops->fb_fillrect(info, &region);
+}
+
+static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
+ const u16 *s, u32 attr, u32 cnt,
+ u32 d_pitch, u32 s_pitch, u32 cellsize,
+ struct fb_image *image, u8 *buf, u8 *dst)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+ u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+ u32 idx = (vc->vc_font.height + 7) >> 3;
+ u8 *src;
+
+ while (cnt--) {
+ src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
+
+ if (attr) {
+ ccw_update_attr(buf, src, attr, vc);
+ src = buf;
+ }
+
+ if (likely(idx == 1))
+ __fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+ vc->vc_font.width);
+ else
+ fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+ vc->vc_font.width);
+
+ dst += d_pitch * vc->vc_font.width;
+ }
+
+ info->fbops->fb_imageblit(info, image);
+}
+
+static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
+ const unsigned short *s, int count, int yy, int xx,
+ int fg, int bg)
+{
+ struct fb_image image;
+ struct display *p = &fb_display[vc->vc_num];
+ struct fbcon_ops *ops = info->fbcon_par;
+ u32 width = (vc->vc_font.height + 7)/8;
+ u32 cellsize = width * vc->vc_font.width;
+ u32 maxcnt = info->pixmap.size/cellsize;
+ u32 scan_align = info->pixmap.scan_align - 1;
+ u32 buf_align = info->pixmap.buf_align - 1;
+ u32 cnt, pitch, size;
+ u32 attribute = get_attribute(info, scr_readw(s));
+ u8 *dst, *buf = NULL;
+ u32 vyres = GETVYRES(p->scrollmode, info);
+
+ if (!ops->fontbuffer)
+ return;
+
+ image.fg_color = fg;
+ image.bg_color = bg;
+ image.dx = yy * vc->vc_font.height;
+ image.dy = vyres - ((xx + count) * vc->vc_font.width);
+ image.width = vc->vc_font.height;
+ image.depth = 1;
+
+ if (attribute) {
+ buf = kmalloc(cellsize, GFP_KERNEL);
+ if (!buf)
+ return;
+ }
+
+ s += count - 1;
+
+ while (count) {
+ if (count > maxcnt)
+ cnt = maxcnt;
+ else
+ cnt = count;
+
+ image.height = vc->vc_font.width * cnt;
+ pitch = ((image.width + 7) >> 3) + scan_align;
+ pitch &= ~scan_align;
+ size = pitch * image.height + buf_align;
+ size &= ~buf_align;
+ dst = fb_get_buffer_offset(info, &info->pixmap, size);
+ image.data = dst;
+ ccw_putcs_aligned(vc, info, s, attribute, cnt, pitch,
+ width, cellsize, &image, buf, dst);
+ image.dy += image.height;
+ count -= cnt;
+ s -= cnt;
+ }
+
+ /* buf is always NULL except when in monochrome mode, so in this case
+ it's a gain to check buf against NULL even though kfree() handles
+ NULL pointers just fine */
+ if (unlikely(buf))
+ kfree(buf);
+
+}
+
+static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info,
+ int bottom_only)
+{
+ unsigned int cw = vc->vc_font.width;
+ unsigned int ch = vc->vc_font.height;
+ unsigned int rw = info->var.yres - (vc->vc_cols*cw);
+ unsigned int bh = info->var.xres - (vc->vc_rows*ch);
+ unsigned int bs = vc->vc_rows*ch;
+ struct fb_fillrect region;
+ int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+
+ region.color = attr_bgcol_ec(bgshift,vc);
+ region.rop = ROP_COPY;
+
+ if (rw && !bottom_only) {
+ region.dx = 0;
+ region.dy = info->var.yoffset;
+ region.height = rw;
+ region.width = info->var.xres_virtual;
+ info->fbops->fb_fillrect(info, &region);
+ }
+
+ if (bh) {
+ region.dx = info->var.xoffset + bs;
+ region.dy = 0;
+ region.height = info->var.yres_virtual;
+ region.width = bh;
+ info->fbops->fb_fillrect(info, &region);
+ }
+}
+
+static void ccw_cursor(struct vc_data *vc, struct fb_info *info,
+ struct display *p, int mode, int softback_lines,
+ int fg, int bg)
+{
+ struct fb_cursor cursor;
+ struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par;
+ unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+ int w = (vc->vc_font.height + 7) >> 3, c;
+ int y = real_y(p, vc->vc_y);
+ int attribute, use_sw = (vc->vc_cursor_type & 0x10);
+ int err = 1, dx, dy;
+ char *src;
+ u32 vyres = GETVYRES(p->scrollmode, info);
+
+ if (!ops->fontbuffer)
+ return;
+
+ cursor.set = 0;
+
+ if (softback_lines) {
+ if (y + softback_lines >= vc->vc_rows) {
+ mode = CM_ERASE;
+ ops->cursor_flash = 0;
+ return;
+ } else
+ y += softback_lines;
+ }
+
+ c = scr_readw((u16 *) vc->vc_pos);
+ attribute = get_attribute(info, c);
+ src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
+
+ if (ops->cursor_state.image.data != src ||
+ ops->cursor_reset) {
+ ops->cursor_state.image.data = src;
+ cursor.set |= FB_CUR_SETIMAGE;
+ }
+
+ if (attribute) {
+ u8 *dst;
+
+ dst = kmalloc(w * vc->vc_font.width, GFP_ATOMIC);
+ if (!dst)
+ return;
+ kfree(ops->cursor_data);
+ ops->cursor_data = dst;
+ ccw_update_attr(dst, src, attribute, vc);
+ src = dst;
+ }
+
+ if (ops->cursor_state.image.fg_color != fg ||
+ ops->cursor_state.image.bg_color != bg ||
+ ops->cursor_reset) {
+ ops->cursor_state.image.fg_color = fg;
+ ops->cursor_state.image.bg_color = bg;
+ cursor.set |= FB_CUR_SETCMAP;
+ }
+
+ if (ops->cursor_state.image.height != vc->vc_font.width ||
+ ops->cursor_state.image.width != vc->vc_font.height ||
+ ops->cursor_reset) {
+ ops->cursor_state.image.height = vc->vc_font.width;
+ ops->cursor_state.image.width = vc->vc_font.height;
+ cursor.set |= FB_CUR_SETSIZE;
+ }
+
+ dx = y * vc->vc_font.height;
+ dy = vyres - ((vc->vc_x + 1) * vc->vc_font.width);
+
+ if (ops->cursor_state.image.dx != dx ||
+ ops->cursor_state.image.dy != dy ||
+ ops->cursor_reset) {
+ ops->cursor_state.image.dx = dx;
+ ops->cursor_state.image.dy = dy;
+ cursor.set |= FB_CUR_SETPOS;
+ }
+
+ if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
+ ops->cursor_reset) {
+ ops->cursor_state.hot.x = cursor.hot.y = 0;
+ cursor.set |= FB_CUR_SETHOT;
+ }
+
+ if (cursor.set & FB_CUR_SETSIZE ||
+ vc->vc_cursor_type != p->cursor_shape ||
+ ops->cursor_state.mask == NULL ||
+ ops->cursor_reset) {
+ char *tmp, *mask = kmalloc(w*vc->vc_font.width, GFP_ATOMIC);
+ int cur_height, size, i = 0;
+ int width = (vc->vc_font.width + 7)/8;
+
+ if (!mask)
+ return;
+
+ tmp = kmalloc(width * vc->vc_font.height, GFP_ATOMIC);
+
+ if (!tmp) {
+ kfree(mask);
+ return;
+ }
+
+ kfree(ops->cursor_state.mask);
+ ops->cursor_state.mask = mask;
+
+ p->cursor_shape = vc->vc_cursor_type;
+ cursor.set |= FB_CUR_SETSHAPE;
+
+ switch (p->cursor_shape & CUR_HWMASK) {
+ case CUR_NONE:
+ cur_height = 0;
+ break;
+ case CUR_UNDERLINE:
+ cur_height = (vc->vc_font.height < 10) ? 1 : 2;
+ break;
+ case CUR_LOWER_THIRD:
+ cur_height = vc->vc_font.height/3;
+ break;
+ case CUR_LOWER_HALF:
+ cur_height = vc->vc_font.height >> 1;
+ break;
+ case CUR_TWO_THIRDS:
+ cur_height = (vc->vc_font.height << 1)/3;
+ break;
+ case CUR_BLOCK:
+ default:
+ cur_height = vc->vc_font.height;
+ break;
+ }
+
+ size = (vc->vc_font.height - cur_height) * width;
+ while (size--)
+ tmp[i++] = 0;
+ size = cur_height * width;
+ while (size--)
+ tmp[i++] = 0xff;
+ memset(mask, 0, w * vc->vc_font.width);
+ rotate_ccw(tmp, mask, vc->vc_font.width, vc->vc_font.height);
+ kfree(tmp);
+ }
+
+ switch (mode) {
+ case CM_ERASE:
+ ops->cursor_state.enable = 0;
+ break;
+ case CM_DRAW:
+ case CM_MOVE:
+ default:
+ ops->cursor_state.enable = (use_sw) ? 0 : 1;
+ break;
+ }
+
+ cursor.image.data = src;
+ cursor.image.fg_color = ops->cursor_state.image.fg_color;
+ cursor.image.bg_color = ops->cursor_state.image.bg_color;
+ cursor.image.dx = ops->cursor_state.image.dx;
+ cursor.image.dy = ops->cursor_state.image.dy;
+ cursor.image.height = ops->cursor_state.image.height;
+ cursor.image.width = ops->cursor_state.image.width;
+ cursor.hot.x = ops->cursor_state.hot.x;
+ cursor.hot.y = ops->cursor_state.hot.y;
+ cursor.mask = ops->cursor_state.mask;
+ cursor.enable = ops->cursor_state.enable;
+ cursor.image.depth = 1;
+ cursor.rop = ROP_XOR;
+
+ if (info->fbops->fb_cursor)
+ err = info->fbops->fb_cursor(info, &cursor);
+
+ if (err)
+ soft_cursor(info, &cursor);
+
+ ops->cursor_reset = 0;
+}
+
+int ccw_update_start(struct fb_info *info)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+ struct display *p = &fb_display[ops->currcon];
+ u32 yoffset;
+ u32 vyres = GETVYRES(p->scrollmode, info);
+ int err;
+
+ yoffset = (vyres - info->var.yres) - ops->var.xoffset;
+ ops->var.xoffset = ops->var.yoffset;
+ ops->var.yoffset = yoffset;
+ err = fb_pan_display(info, &ops->var);
+ ops->var.xoffset = info->var.xoffset;
+ ops->var.yoffset = info->var.yoffset;
+ ops->var.vmode = info->var.vmode;
+ return err;
+}
+
+void fbcon_rotate_ccw(struct fbcon_ops *ops)
+{
+ ops->bmove = ccw_bmove;
+ ops->clear = ccw_clear;
+ ops->putcs = ccw_putcs;
+ ops->clear_margins = ccw_clear_margins;
+ ops->cursor = ccw_cursor;
+ ops->update_start = ccw_update_start;
+}
+EXPORT_SYMBOL(fbcon_rotate_ccw);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Console Rotation (270 degrees) Support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c
new file mode 100644
index 00000000000..6c6f3b6dd17
--- /dev/null
+++ b/drivers/video/console/fbcon_cw.c
@@ -0,0 +1,412 @@
+/*
+ * linux/drivers/video/console/fbcon_ud.c -- Software Rotation - 90 degrees
+ *
+ * Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <asm/types.h>
+#include "fbcon.h"
+#include "fbcon_rotate.h"
+
+/*
+ * Rotation 90 degrees
+ */
+
+static inline void cw_update_attr(u8 *dst, u8 *src, int attribute,
+ struct vc_data *vc)
+{
+ int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
+ int width = (vc->vc_font.height + 7) >> 3;
+ u8 c, t = 0, msk = ~(0xff >> offset);
+
+ for (i = 0; i < vc->vc_font.width; i++) {
+ for (j = 0; j < width; j++) {
+ c = *src;
+ if (attribute & FBCON_ATTRIBUTE_UNDERLINE && !j)
+ c |= msk;
+ if (attribute & FBCON_ATTRIBUTE_BOLD && i)
+ c |= *(src-width);
+ if (attribute & FBCON_ATTRIBUTE_REVERSE)
+ c = ~c;
+ src++;
+ *dst++ = c;
+ t = c;
+ }
+ }
+}
+
+
+static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ int sx, int dy, int dx, int height, int width)
+{
+ struct display *p = &fb_display[vc->vc_num];
+ struct fb_copyarea area;
+ u32 vxres = GETVXRES(p->scrollmode, info);
+
+ area.sx = vxres - ((sy + height) * vc->vc_font.height);
+ area.sy = sx * vc->vc_font.width;
+ area.dx = vxres - ((dy + height) * vc->vc_font.height);
+ area.dy = dx * vc->vc_font.width;
+ area.width = height * vc->vc_font.height;
+ area.height = width * vc->vc_font.width;
+
+ info->fbops->fb_copyarea(info, &area);
+}
+
+static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
+ int sx, int height, int width)
+{
+ struct display *p = &fb_display[vc->vc_num];
+ struct fb_fillrect region;
+ int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+ u32 vxres = GETVXRES(p->scrollmode, info);
+
+ region.color = attr_bgcol_ec(bgshift,vc);
+ region.dx = vxres - ((sy + height) * vc->vc_font.height);
+ region.dy = sx * vc->vc_font.width;
+ region.height = width * vc->vc_font.width;
+ region.width = height * vc->vc_font.height;
+ region.rop = ROP_COPY;
+
+ info->fbops->fb_fillrect(info, &region);
+}
+
+static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
+ const u16 *s, u32 attr, u32 cnt,
+ u32 d_pitch, u32 s_pitch, u32 cellsize,
+ struct fb_image *image, u8 *buf, u8 *dst)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+ u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+ u32 idx = (vc->vc_font.height + 7) >> 3;
+ u8 *src;
+
+ while (cnt--) {
+ src = ops->fontbuffer + (scr_readw(s++) & charmask)*cellsize;
+
+ if (attr) {
+ cw_update_attr(buf, src, attr, vc);
+ src = buf;
+ }
+
+ if (likely(idx == 1))
+ __fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+ vc->vc_font.width);
+ else
+ fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+ vc->vc_font.width);
+
+ dst += d_pitch * vc->vc_font.width;
+ }
+
+ info->fbops->fb_imageblit(info, image);
+}
+
+static void cw_putcs(struct vc_data *vc, struct fb_info *info,
+ const unsigned short *s, int count, int yy, int xx,
+ int fg, int bg)
+{
+ struct fb_image image;
+ struct display *p = &fb_display[vc->vc_num];
+ struct fbcon_ops *ops = info->fbcon_par;
+ u32 width = (vc->vc_font.height + 7)/8;
+ u32 cellsize = width * vc->vc_font.width;
+ u32 maxcnt = info->pixmap.size/cellsize;
+ u32 scan_align = info->pixmap.scan_align - 1;
+ u32 buf_align = info->pixmap.buf_align - 1;
+ u32 cnt, pitch, size;
+ u32 attribute = get_attribute(info, scr_readw(s));
+ u8 *dst, *buf = NULL;
+ u32 vxres = GETVXRES(p->scrollmode, info);
+
+ if (!ops->fontbuffer)
+ return;
+
+ image.fg_color = fg;
+ image.bg_color = bg;
+ image.dx = vxres - ((yy + 1) * vc->vc_font.height);
+ image.dy = xx * vc->vc_font.width;
+ image.width = vc->vc_font.height;
+ image.depth = 1;
+
+ if (attribute) {
+ buf = kmalloc(cellsize, GFP_KERNEL);
+ if (!buf)
+ return;
+ }
+
+ while (count) {
+ if (count > maxcnt)
+ cnt = maxcnt;
+ else
+ cnt = count;
+
+ image.height = vc->vc_font.width * cnt;
+ pitch = ((image.width + 7) >> 3) + scan_align;
+ pitch &= ~scan_align;
+ size = pitch * image.height + buf_align;
+ size &= ~buf_align;
+ dst = fb_get_buffer_offset(info, &info->pixmap, size);
+ image.data = dst;
+ cw_putcs_aligned(vc, info, s, attribute, cnt, pitch,
+ width, cellsize, &image, buf, dst);
+ image.dy += image.height;
+ count -= cnt;
+ s += cnt;
+ }
+
+ /* buf is always NULL except when in monochrome mode, so in this case
+ it's a gain to check buf against NULL even though kfree() handles
+ NULL pointers just fine */
+ if (unlikely(buf))
+ kfree(buf);
+
+}
+
+static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
+ int bottom_only)
+{
+ unsigned int cw = vc->vc_font.width;
+ unsigned int ch = vc->vc_font.height;
+ unsigned int rw = info->var.yres - (vc->vc_cols*cw);
+ unsigned int bh = info->var.xres - (vc->vc_rows*ch);
+ unsigned int rs = info->var.yres - rw;
+ struct fb_fillrect region;
+ int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+
+ region.color = attr_bgcol_ec(bgshift,vc);
+ region.rop = ROP_COPY;
+
+ if (rw && !bottom_only) {
+ region.dx = 0;
+ region.dy = info->var.yoffset + rs;
+ region.height = rw;
+ region.width = info->var.xres_virtual;
+ info->fbops->fb_fillrect(info, &region);
+ }
+
+ if (bh) {
+ region.dx = info->var.xoffset;
+ region.dy = info->var.yoffset;
+ region.height = info->var.yres;
+ region.width = bh;
+ info->fbops->fb_fillrect(info, &region);
+ }
+}
+
+static void cw_cursor(struct vc_data *vc, struct fb_info *info,
+ struct display *p, int mode, int softback_lines,
+ int fg, int bg)
+{
+ struct fb_cursor cursor;
+ struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par;
+ unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+ int w = (vc->vc_font.height + 7) >> 3, c;
+ int y = real_y(p, vc->vc_y);
+ int attribute, use_sw = (vc->vc_cursor_type & 0x10);
+ int err = 1, dx, dy;
+ char *src;
+ u32 vxres = GETVXRES(p->scrollmode, info);
+
+ if (!ops->fontbuffer)
+ return;
+
+ cursor.set = 0;
+
+ if (softback_lines) {
+ if (y + softback_lines >= vc->vc_rows) {
+ mode = CM_ERASE;
+ ops->cursor_flash = 0;
+ return;
+ } else
+ y += softback_lines;
+ }
+
+ c = scr_readw((u16 *) vc->vc_pos);
+ attribute = get_attribute(info, c);
+ src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
+
+ if (ops->cursor_state.image.data != src ||
+ ops->cursor_reset) {
+ ops->cursor_state.image.data = src;
+ cursor.set |= FB_CUR_SETIMAGE;
+ }
+
+ if (attribute) {
+ u8 *dst;
+
+ dst = kmalloc(w * vc->vc_font.width, GFP_ATOMIC);
+ if (!dst)
+ return;
+ kfree(ops->cursor_data);
+ ops->cursor_data = dst;
+ cw_update_attr(dst, src, attribute, vc);
+ src = dst;
+ }
+
+ if (ops->cursor_state.image.fg_color != fg ||
+ ops->cursor_state.image.bg_color != bg ||
+ ops->cursor_reset) {
+ ops->cursor_state.image.fg_color = fg;
+ ops->cursor_state.image.bg_color = bg;
+ cursor.set |= FB_CUR_SETCMAP;
+ }
+
+ if (ops->cursor_state.image.height != vc->vc_font.width ||
+ ops->cursor_state.image.width != vc->vc_font.height ||
+ ops->cursor_reset) {
+ ops->cursor_state.image.height = vc->vc_font.width;
+ ops->cursor_state.image.width = vc->vc_font.height;
+ cursor.set |= FB_CUR_SETSIZE;
+ }
+
+ dx = vxres - ((y * vc->vc_font.height) + vc->vc_font.height);
+ dy = vc->vc_x * vc->vc_font.width;
+
+ if (ops->cursor_state.image.dx != dx ||
+ ops->cursor_state.image.dy != dy ||
+ ops->cursor_reset) {
+ ops->cursor_state.image.dx = dx;
+ ops->cursor_state.image.dy = dy;
+ cursor.set |= FB_CUR_SETPOS;
+ }
+
+ if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
+ ops->cursor_reset) {
+ ops->cursor_state.hot.x = cursor.hot.y = 0;
+ cursor.set |= FB_CUR_SETHOT;
+ }
+
+ if (cursor.set & FB_CUR_SETSIZE ||
+ vc->vc_cursor_type != p->cursor_shape ||
+ ops->cursor_state.mask == NULL ||
+ ops->cursor_reset) {
+ char *tmp, *mask = kmalloc(w*vc->vc_font.width, GFP_ATOMIC);
+ int cur_height, size, i = 0;
+ int width = (vc->vc_font.width + 7)/8;
+
+ if (!mask)
+ return;
+
+ tmp = kmalloc(width * vc->vc_font.height, GFP_ATOMIC);
+
+ if (!tmp) {
+ kfree(mask);
+ return;
+ }
+
+ kfree(ops->cursor_state.mask);
+ ops->cursor_state.mask = mask;
+
+ p->cursor_shape = vc->vc_cursor_type;
+ cursor.set |= FB_CUR_SETSHAPE;
+
+ switch (p->cursor_shape & CUR_HWMASK) {
+ case CUR_NONE:
+ cur_height = 0;
+ break;
+ case CUR_UNDERLINE:
+ cur_height = (vc->vc_font.height < 10) ? 1 : 2;
+ break;
+ case CUR_LOWER_THIRD:
+ cur_height = vc->vc_font.height/3;
+ break;
+ case CUR_LOWER_HALF:
+ cur_height = vc->vc_font.height >> 1;
+ break;
+ case CUR_TWO_THIRDS:
+ cur_height = (vc->vc_font.height << 1)/3;
+ break;
+ case CUR_BLOCK:
+ default:
+ cur_height = vc->vc_font.height;
+ break;
+ }
+
+ size = (vc->vc_font.height - cur_height) * width;
+ while (size--)
+ tmp[i++] = 0;
+ size = cur_height * width;
+ while (size--)
+ tmp[i++] = 0xff;
+ memset(mask, 0, w * vc->vc_font.width);
+ rotate_cw(tmp, mask, vc->vc_font.width, vc->vc_font.height);
+ kfree(tmp);
+ }
+
+ switch (mode) {
+ case CM_ERASE:
+ ops->cursor_state.enable = 0;
+ break;
+ case CM_DRAW:
+ case CM_MOVE:
+ default:
+ ops->cursor_state.enable = (use_sw) ? 0 : 1;
+ break;
+ }
+
+ cursor.image.data = src;
+ cursor.image.fg_color = ops->cursor_state.image.fg_color;
+ cursor.image.bg_color = ops->cursor_state.image.bg_color;
+ cursor.image.dx = ops->cursor_state.image.dx;
+ cursor.image.dy = ops->cursor_state.image.dy;
+ cursor.image.height = ops->cursor_state.image.height;
+ cursor.image.width = ops->cursor_state.image.width;
+ cursor.hot.x = ops->cursor_state.hot.x;
+ cursor.hot.y = ops->cursor_state.hot.y;
+ cursor.mask = ops->cursor_state.mask;
+ cursor.enable = ops->cursor_state.enable;
+ cursor.image.depth = 1;
+ cursor.rop = ROP_XOR;
+
+ if (info->fbops->fb_cursor)
+ err = info->fbops->fb_cursor(info, &cursor);
+
+ if (err)
+ soft_cursor(info, &cursor);
+
+ ops->cursor_reset = 0;
+}
+
+int cw_update_start(struct fb_info *info)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+ struct display *p = &fb_display[ops->currcon];
+ u32 vxres = GETVXRES(p->scrollmode, info);
+ u32 xoffset;
+ int err;
+
+ xoffset = vxres - (info->var.xres + ops->var.yoffset);
+ ops->var.yoffset = ops->var.xoffset;
+ ops->var.xoffset = xoffset;
+ err = fb_pan_display(info, &ops->var);
+ ops->var.xoffset = info->var.xoffset;
+ ops->var.yoffset = info->var.yoffset;
+ ops->var.vmode = info->var.vmode;
+ return err;
+}
+
+void fbcon_rotate_cw(struct fbcon_ops *ops)
+{
+ ops->bmove = cw_bmove;
+ ops->clear = cw_clear;
+ ops->putcs = cw_putcs;
+ ops->clear_margins = cw_clear_margins;
+ ops->cursor = cw_cursor;
+ ops->update_start = cw_update_start;
+}
+EXPORT_SYMBOL(fbcon_rotate_cw);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Console Rotation (90 degrees) Support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/fbcon_rotate.c b/drivers/video/console/fbcon_rotate.c
new file mode 100644
index 00000000000..ec0dd8fe241
--- /dev/null
+++ b/drivers/video/console/fbcon_rotate.c
@@ -0,0 +1,117 @@
+/*
+ * linux/drivers/video/console/fbcon_rotate.c -- Software Rotation
+ *
+ * Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <asm/types.h>
+#include "fbcon.h"
+#include "fbcon_rotate.h"
+
+static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc,
+ struct display *p)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+ int len, err = 0;
+ int s_cellsize, d_cellsize, i;
+ const u8 *src;
+ u8 *dst;
+
+ if (vc->vc_font.data == ops->fontdata &&
+ p->con_rotate == ops->cur_rotate)
+ goto finished;
+
+ src = ops->fontdata = vc->vc_font.data;
+ ops->cur_rotate = p->con_rotate;
+ len = (!p->userfont) ? 256 : FNTCHARCNT(src);
+ s_cellsize = ((vc->vc_font.width + 7)/8) *
+ vc->vc_font.height;
+ d_cellsize = s_cellsize;
+
+ if (ops->rotate == FB_ROTATE_CW ||
+ ops->rotate == FB_ROTATE_CCW)
+ d_cellsize = ((vc->vc_font.height + 7)/8) *
+ vc->vc_font.width;
+
+ if (info->fbops->fb_sync)
+ info->fbops->fb_sync(info);
+
+ if (ops->fd_size < d_cellsize * len) {
+ dst = kmalloc(d_cellsize * len, GFP_KERNEL);
+
+ if (dst == NULL) {
+ err = -ENOMEM;
+ goto finished;
+ }
+
+ ops->fd_size = d_cellsize * len;
+ kfree(ops->fontbuffer);
+ ops->fontbuffer = dst;
+ }
+
+ dst = ops->fontbuffer;
+ memset(dst, 0, ops->fd_size);
+
+ switch (ops->rotate) {
+ case FB_ROTATE_UD:
+ for (i = len; i--; ) {
+ rotate_ud(src, dst, vc->vc_font.width,
+ vc->vc_font.height);
+
+ src += s_cellsize;
+ dst += d_cellsize;
+ }
+ break;
+ case FB_ROTATE_CW:
+ for (i = len; i--; ) {
+ rotate_cw(src, dst, vc->vc_font.width,
+ vc->vc_font.height);
+ src += s_cellsize;
+ dst += d_cellsize;
+ }
+ break;
+ case FB_ROTATE_CCW:
+ for (i = len; i--; ) {
+ rotate_ccw(src, dst, vc->vc_font.width,
+ vc->vc_font.height);
+ src += s_cellsize;
+ dst += d_cellsize;
+ }
+ break;
+ }
+
+finished:
+ return err;
+}
+
+void fbcon_set_rotate(struct fbcon_ops *ops)
+{
+ ops->rotate_font = fbcon_rotate_font;
+
+ switch(ops->rotate) {
+ case FB_ROTATE_CW:
+ fbcon_rotate_cw(ops);
+ break;
+ case FB_ROTATE_UD:
+ fbcon_rotate_ud(ops);
+ break;
+ case FB_ROTATE_CCW:
+ fbcon_rotate_ccw(ops);
+ break;
+ }
+}
+EXPORT_SYMBOL(fbcon_set_rotate);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Console Rotation Support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/fbcon_rotate.h b/drivers/video/console/fbcon_rotate.h
new file mode 100644
index 00000000000..90c672096c2
--- /dev/null
+++ b/drivers/video/console/fbcon_rotate.h
@@ -0,0 +1,105 @@
+/*
+ * linux/drivers/video/console/fbcon_rotate.h -- Software Display Rotation
+ *
+ * Copyright (C) 2005 Antonino Daplas <adaplas@pol.net>
+ *
+ * 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.
+ */
+
+#ifndef _FBCON_ROTATE_H
+#define _FBCON_ROTATE_H
+
+#define FNTCHARCNT(fd) (((int *)(fd))[-3])
+
+#define GETVYRES(s,i) ({ \
+ (s == SCROLL_REDRAW || s == SCROLL_MOVE) ? \
+ (i)->var.yres : (i)->var.yres_virtual; })
+
+#define GETVXRES(s,i) ({ \
+ (s == SCROLL_REDRAW || s == SCROLL_MOVE || !(i)->fix.xpanstep) ? \
+ (i)->var.xres : (i)->var.xres_virtual; })
+
+/*
+ * The bitmap is always big endian
+ */
+#if defined(__LITTLE_ENDIAN)
+#define FBCON_BIT(b) (7 - (b))
+#else
+#define FBCON_BIT(b) (b)
+#endif
+
+static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat)
+{
+ u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8;
+
+ pat +=index;
+ return (test_bit(FBCON_BIT(bit), (void *)pat));
+}
+
+static inline void pattern_set_bit(u32 x, u32 y, u32 pitch, char *pat)
+{
+ u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8;
+
+ pat += index;
+ set_bit(FBCON_BIT(bit), (void *)pat);
+}
+
+static inline void rotate_ud(const char *in, char *out, u32 width, u32 height)
+{
+ int i, j;
+ int shift = width % 8;
+
+ width = (width + 7) & ~7;
+
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j++) {
+ if (pattern_test_bit(j, i, width, in))
+ pattern_set_bit(width - (1 + j + shift),
+ height - (1 + i),
+ width, out);
+ }
+
+ }
+}
+
+static inline void rotate_cw(const char *in, char *out, u32 width, u32 height)
+{
+ int i, j, h = height, w = width;
+ int shift = (8 - (height % 8)) & 7;
+
+ width = (width + 7) & ~7;
+ height = (height + 7) & ~7;
+
+ for (i = 0; i < h; i++) {
+ for (j = 0; j < w; j++) {
+ if (pattern_test_bit(j, i, width, in))
+ pattern_set_bit(height - 1 - i - shift, j,
+ height, out);
+
+ }
+ }
+}
+
+static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height)
+{
+ int i, j, h = height, w = width;
+ int shift = width % 8;
+
+ width = (width + 7) & ~7;
+ height = (height + 7) & ~7;
+
+ for (i = 0; i < h; i++) {
+ for (j = 0; j < w; j++) {
+ if (pattern_test_bit(j, i, width, in))
+ pattern_set_bit(i, width - 1 - j - shift,
+ height, out);
+ }
+ }
+}
+
+extern void fbcon_rotate_cw(struct fbcon_ops *ops);
+extern void fbcon_rotate_ud(struct fbcon_ops *ops);
+extern void fbcon_rotate_ccw(struct fbcon_ops *ops);
+#endif
diff --git a/drivers/video/console/fbcon_ud.c b/drivers/video/console/fbcon_ud.c
new file mode 100644
index 00000000000..2e1d9d4249c
--- /dev/null
+++ b/drivers/video/console/fbcon_ud.c
@@ -0,0 +1,454 @@
+/*
+ * linux/drivers/video/console/fbcon_ud.c -- Software Rotation - 180 degrees
+ *
+ * Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <asm/types.h>
+#include "fbcon.h"
+#include "fbcon_rotate.h"
+
+/*
+ * Rotation 180 degrees
+ */
+
+static inline void ud_update_attr(u8 *dst, u8 *src, int attribute,
+ struct vc_data *vc)
+{
+ int i, offset = (vc->vc_font.height < 10) ? 1 : 2;
+ int width = (vc->vc_font.width + 7) >> 3;
+ unsigned int cellsize = vc->vc_font.height * width;
+ u8 c;
+
+ offset = offset * width;
+
+ for (i = 0; i < cellsize; i++) {
+ c = src[i];
+ if (attribute & FBCON_ATTRIBUTE_UNDERLINE && i < offset)
+ c = 0xff;
+ if (attribute & FBCON_ATTRIBUTE_BOLD)
+ c |= c << 1;
+ if (attribute & FBCON_ATTRIBUTE_REVERSE)
+ c = ~c;
+ dst[i] = c;
+ }
+}
+
+
+static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ int sx, int dy, int dx, int height, int width)
+{
+ struct display *p = &fb_display[vc->vc_num];
+ struct fb_copyarea area;
+ u32 vyres = GETVYRES(p->scrollmode, info);
+ u32 vxres = GETVXRES(p->scrollmode, info);
+
+ area.sy = vyres - ((sy + height) * vc->vc_font.height);
+ area.sx = vxres - ((sx + width) * vc->vc_font.width);
+ area.dy = vyres - ((dy + height) * vc->vc_font.height);
+ area.dx = vxres - ((dx + width) * vc->vc_font.width);
+ area.height = height * vc->vc_font.height;
+ area.width = width * vc->vc_font.width;
+
+ info->fbops->fb_copyarea(info, &area);
+}
+
+static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
+ int sx, int height, int width)
+{
+ struct display *p = &fb_display[vc->vc_num];
+ struct fb_fillrect region;
+ int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+ u32 vyres = GETVYRES(p->scrollmode, info);
+ u32 vxres = GETVXRES(p->scrollmode, info);
+
+ region.color = attr_bgcol_ec(bgshift,vc);
+ region.dy = vyres - ((sy + height) * vc->vc_font.height);
+ region.dx = vxres - ((sx + width) * vc->vc_font.width);
+ region.width = width * vc->vc_font.width;
+ region.height = height * vc->vc_font.height;
+ region.rop = ROP_COPY;
+
+ info->fbops->fb_fillrect(info, &region);
+}
+
+static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info,
+ const u16 *s, u32 attr, u32 cnt,
+ u32 d_pitch, u32 s_pitch, u32 cellsize,
+ struct fb_image *image, u8 *buf, u8 *dst)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+ u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+ u32 idx = vc->vc_font.width >> 3;
+ u8 *src;
+
+ while (cnt--) {
+ src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
+
+ if (attr) {
+ ud_update_attr(buf, src, attr, vc);
+ src = buf;
+ }
+
+ if (likely(idx == 1))
+ __fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+ image->height);
+ else
+ fb_pad_aligned_buffer(dst, d_pitch, src, idx,
+ image->height);
+
+ dst += s_pitch;
+ }
+
+ info->fbops->fb_imageblit(info, image);
+}
+
+static inline void ud_putcs_unaligned(struct vc_data *vc,
+ struct fb_info *info, const u16 *s,
+ u32 attr, u32 cnt, u32 d_pitch,
+ u32 s_pitch, u32 cellsize,
+ struct fb_image *image, u8 *buf,
+ u8 *dst)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+ u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+ u32 shift_low = 0, mod = vc->vc_font.width % 8;
+ u32 shift_high = 8;
+ u32 idx = vc->vc_font.width >> 3;
+ u8 *src;
+
+ while (cnt--) {
+ src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
+
+ if (attr) {
+ ud_update_attr(buf, src, attr, vc);
+ src = buf;
+ }
+
+ fb_pad_unaligned_buffer(dst, d_pitch, src, idx,
+ image->height, shift_high,
+ shift_low, mod);
+ shift_low += mod;
+ dst += (shift_low >= 8) ? s_pitch : s_pitch - 1;
+ shift_low &= 7;
+ shift_high = 8 - shift_low;
+ }
+
+ info->fbops->fb_imageblit(info, image);
+
+}
+
+static void ud_putcs(struct vc_data *vc, struct fb_info *info,
+ const unsigned short *s, int count, int yy, int xx,
+ int fg, int bg)
+{
+ struct fb_image image;
+ struct display *p = &fb_display[vc->vc_num];
+ struct fbcon_ops *ops = info->fbcon_par;
+ u32 width = (vc->vc_font.width + 7)/8;
+ u32 cellsize = width * vc->vc_font.height;
+ u32 maxcnt = info->pixmap.size/cellsize;
+ u32 scan_align = info->pixmap.scan_align - 1;
+ u32 buf_align = info->pixmap.buf_align - 1;
+ u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
+ u32 attribute = get_attribute(info, scr_readw(s));
+ u8 *dst, *buf = NULL;
+ u32 vyres = GETVYRES(p->scrollmode, info);
+ u32 vxres = GETVXRES(p->scrollmode, info);
+
+ if (!ops->fontbuffer)
+ return;
+
+ image.fg_color = fg;
+ image.bg_color = bg;
+ image.dy = vyres - ((yy * vc->vc_font.height) + vc->vc_font.height);
+ image.dx = vxres - ((xx + count) * vc->vc_font.width);
+ image.height = vc->vc_font.height;
+ image.depth = 1;
+
+ if (attribute) {
+ buf = kmalloc(cellsize, GFP_KERNEL);
+ if (!buf)
+ return;
+ }
+
+ s += count - 1;
+
+ while (count) {
+ if (count > maxcnt)
+ cnt = maxcnt;
+ else
+ cnt = count;
+
+ image.width = vc->vc_font.width * cnt;
+ pitch = ((image.width + 7) >> 3) + scan_align;
+ pitch &= ~scan_align;
+ size = pitch * image.height + buf_align;
+ size &= ~buf_align;
+ dst = fb_get_buffer_offset(info, &info->pixmap, size);
+ image.data = dst;
+
+ if (!mod)
+ ud_putcs_aligned(vc, info, s, attribute, cnt, pitch,
+ width, cellsize, &image, buf, dst);
+ else
+ ud_putcs_unaligned(vc, info, s, attribute, cnt, pitch,
+ width, cellsize, &image,
+ buf, dst);
+
+ image.dx += image.width;
+ count -= cnt;
+ s -= cnt;
+ xx += cnt;
+ }
+
+ /* buf is always NULL except when in monochrome mode, so in this case
+ it's a gain to check buf against NULL even though kfree() handles
+ NULL pointers just fine */
+ if (unlikely(buf))
+ kfree(buf);
+
+}
+
+static void ud_clear_margins(struct vc_data *vc, struct fb_info *info,
+ int bottom_only)
+{
+ unsigned int cw = vc->vc_font.width;
+ unsigned int ch = vc->vc_font.height;
+ unsigned int rw = info->var.xres - (vc->vc_cols*cw);
+ unsigned int bh = info->var.yres - (vc->vc_rows*ch);
+ struct fb_fillrect region;
+ int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
+
+ region.color = attr_bgcol_ec(bgshift,vc);
+ region.rop = ROP_COPY;
+
+ if (rw && !bottom_only) {
+ region.dy = 0;
+ region.dx = info->var.xoffset;
+ region.width = rw;
+ region.height = info->var.yres_virtual;
+ info->fbops->fb_fillrect(info, &region);
+ }
+
+ if (bh) {
+ region.dy = info->var.yoffset;
+ region.dx = info->var.xoffset;
+ region.height = bh;
+ region.width = info->var.xres;
+ info->fbops->fb_fillrect(info, &region);
+ }
+}
+
+static void ud_cursor(struct vc_data *vc, struct fb_info *info,
+ struct display *p, int mode, int softback_lines,
+ int fg, int bg)
+{
+ struct fb_cursor cursor;
+ struct fbcon_ops *ops = (struct fbcon_ops *) info->fbcon_par;
+ unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+ int w = (vc->vc_font.width + 7) >> 3, c;
+ int y = real_y(p, vc->vc_y);
+ int attribute, use_sw = (vc->vc_cursor_type & 0x10);
+ int err = 1, dx, dy;
+ char *src;
+ u32 vyres = GETVYRES(p->scrollmode, info);
+ u32 vxres = GETVXRES(p->scrollmode, info);
+
+ if (!ops->fontbuffer)
+ return;
+
+ cursor.set = 0;
+
+ if (softback_lines) {
+ if (y + softback_lines >= vc->vc_rows) {
+ mode = CM_ERASE;
+ ops->cursor_flash = 0;
+ return;
+ } else
+ y += softback_lines;
+ }
+
+ c = scr_readw((u16 *) vc->vc_pos);
+ attribute = get_attribute(info, c);
+ src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height));
+
+ if (ops->cursor_state.image.data != src ||
+ ops->cursor_reset) {
+ ops->cursor_state.image.data = src;
+ cursor.set |= FB_CUR_SETIMAGE;
+ }
+
+ if (attribute) {
+ u8 *dst;
+
+ dst = kmalloc(w * vc->vc_font.height, GFP_ATOMIC);
+ if (!dst)
+ return;
+ kfree(ops->cursor_data);
+ ops->cursor_data = dst;
+ ud_update_attr(dst, src, attribute, vc);
+ src = dst;
+ }
+
+ if (ops->cursor_state.image.fg_color != fg ||
+ ops->cursor_state.image.bg_color != bg ||
+ ops->cursor_reset) {
+ ops->cursor_state.image.fg_color = fg;
+ ops->cursor_state.image.bg_color = bg;
+ cursor.set |= FB_CUR_SETCMAP;
+ }
+
+ if (ops->cursor_state.image.height != vc->vc_font.height ||
+ ops->cursor_state.image.width != vc->vc_font.width ||
+ ops->cursor_reset) {
+ ops->cursor_state.image.height = vc->vc_font.height;
+ ops->cursor_state.image.width = vc->vc_font.width;
+ cursor.set |= FB_CUR_SETSIZE;
+ }
+
+ dy = vyres - ((y * vc->vc_font.height) + vc->vc_font.height);
+ dx = vxres - ((vc->vc_x * vc->vc_font.width) + vc->vc_font.width);
+
+ if (ops->cursor_state.image.dx != dx ||
+ ops->cursor_state.image.dy != dy ||
+ ops->cursor_reset) {
+ ops->cursor_state.image.dx = dx;
+ ops->cursor_state.image.dy = dy;
+ cursor.set |= FB_CUR_SETPOS;
+ }
+
+ if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
+ ops->cursor_reset) {
+ ops->cursor_state.hot.x = cursor.hot.y = 0;
+ cursor.set |= FB_CUR_SETHOT;
+ }
+
+ if (cursor.set & FB_CUR_SETSIZE ||
+ vc->vc_cursor_type != p->cursor_shape ||
+ ops->cursor_state.mask == NULL ||
+ ops->cursor_reset) {
+ char *mask = kmalloc(w*vc->vc_font.height, GFP_ATOMIC);
+ int cur_height, size, i = 0;
+ u8 msk = 0xff;
+
+ if (!mask)
+ return;
+
+ kfree(ops->cursor_state.mask);
+ ops->cursor_state.mask = mask;
+
+ p->cursor_shape = vc->vc_cursor_type;
+ cursor.set |= FB_CUR_SETSHAPE;
+
+ switch (p->cursor_shape & CUR_HWMASK) {
+ case CUR_NONE:
+ cur_height = 0;
+ break;
+ case CUR_UNDERLINE:
+ cur_height = (vc->vc_font.height < 10) ? 1 : 2;
+ break;
+ case CUR_LOWER_THIRD:
+ cur_height = vc->vc_font.height/3;
+ break;
+ case CUR_LOWER_HALF:
+ cur_height = vc->vc_font.height >> 1;
+ break;
+ case CUR_TWO_THIRDS:
+ cur_height = (vc->vc_font.height << 1)/3;
+ break;
+ case CUR_BLOCK:
+ default:
+ cur_height = vc->vc_font.height;
+ break;
+ }
+
+ size = cur_height * w;
+
+ while (size--)
+ mask[i++] = msk;
+
+ size = (vc->vc_font.height - cur_height) * w;
+
+ while (size--)
+ mask[i++] = ~msk;
+ }
+
+ switch (mode) {
+ case CM_ERASE:
+ ops->cursor_state.enable = 0;
+ break;
+ case CM_DRAW:
+ case CM_MOVE:
+ default:
+ ops->cursor_state.enable = (use_sw) ? 0 : 1;
+ break;
+ }
+
+ cursor.image.data = src;
+ cursor.image.fg_color = ops->cursor_state.image.fg_color;
+ cursor.image.bg_color = ops->cursor_state.image.bg_color;
+ cursor.image.dx = ops->cursor_state.image.dx;
+ cursor.image.dy = ops->cursor_state.image.dy;
+ cursor.image.height = ops->cursor_state.image.height;
+ cursor.image.width = ops->cursor_state.image.width;
+ cursor.hot.x = ops->cursor_state.hot.x;
+ cursor.hot.y = ops->cursor_state.hot.y;
+ cursor.mask = ops->cursor_state.mask;
+ cursor.enable = ops->cursor_state.enable;
+ cursor.image.depth = 1;
+ cursor.rop = ROP_XOR;
+
+ if (info->fbops->fb_cursor)
+ err = info->fbops->fb_cursor(info, &cursor);
+
+ if (err)
+ soft_cursor(info, &cursor);
+
+ ops->cursor_reset = 0;
+}
+
+int ud_update_start(struct fb_info *info)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+ struct display *p = &fb_display[ops->currcon];
+ u32 xoffset, yoffset;
+ u32 vyres = GETVYRES(p->scrollmode, info);
+ u32 vxres = GETVXRES(p->scrollmode, info);
+ int err;
+
+ xoffset = (vxres - info->var.xres) - ops->var.xoffset;
+ yoffset = (vyres - info->var.yres) - ops->var.yoffset;
+ ops->var.xoffset = xoffset;
+ ops->var.yoffset = yoffset;
+ err = fb_pan_display(info, &ops->var);
+ ops->var.xoffset = info->var.xoffset;
+ ops->var.yoffset = info->var.yoffset;
+ ops->var.vmode = info->var.vmode;
+ return err;
+}
+
+void fbcon_rotate_ud(struct fbcon_ops *ops)
+{
+ ops->bmove = ud_bmove;
+ ops->clear = ud_clear;
+ ops->putcs = ud_putcs;
+ ops->clear_margins = ud_clear_margins;
+ ops->cursor = ud_cursor;
+ ops->update_start = ud_update_start;
+}
+EXPORT_SYMBOL(fbcon_rotate_ud);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Console Rotation (180 degrees) Support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/tileblit.c b/drivers/video/console/tileblit.c
index 7f76e2c6a4a..cb25324a563 100644
--- a/drivers/video/console/tileblit.c
+++ b/drivers/video/console/tileblit.c
@@ -118,6 +118,18 @@ static void tile_cursor(struct vc_data *vc, struct fb_info *info,
info->tileops->fb_tilecursor(info, &cursor);
}
+static int tile_update_start(struct fb_info *info)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+ int err;
+
+ err = fb_pan_display(info, &ops->var);
+ ops->var.xoffset = info->var.xoffset;
+ ops->var.yoffset = info->var.yoffset;
+ ops->var.vmode = info->var.vmode;
+ return err;
+}
+
void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info,
struct display *p, struct fbcon_ops *ops)
{
@@ -128,6 +140,7 @@ void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info,
ops->putcs = tile_putcs;
ops->clear_margins = tile_clear_margins;
ops->cursor = tile_cursor;
+ ops->update_start = tile_update_start;
if (p) {
map.width = vc->vc_font.width;
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index e2667ddab3f..9f180096c89 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -14,6 +14,7 @@
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/compat.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sched.h>
@@ -323,9 +324,103 @@ static struct logo_data {
const struct linux_logo *logo;
} fb_logo;
-int fb_prepare_logo(struct fb_info *info)
+static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height)
+{
+ u32 size = width * height, i;
+
+ out += size - 1;
+
+ for (i = size; i--; )
+ *out-- = *in++;
+}
+
+static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height)
+{
+ int i, j, w = width - 1;
+
+ for (i = 0; i < height; i++)
+ for (j = 0; j < width; j++)
+ out[height * j + w - i] = *in++;
+}
+
+static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height)
+{
+ int i, j, w = width - 1;
+
+ for (i = 0; i < height; i++)
+ for (j = 0; j < width; j++)
+ out[height * (w - j) + i] = *in++;
+}
+
+static void fb_rotate_logo(struct fb_info *info, u8 *dst,
+ struct fb_image *image, int rotate)
+{
+ u32 tmp;
+
+ if (rotate == FB_ROTATE_UD) {
+ image->dx = info->var.xres - image->width;
+ image->dy = info->var.yres - image->height;
+ fb_rotate_logo_ud(image->data, dst, image->width,
+ image->height);
+ } else if (rotate == FB_ROTATE_CW) {
+ tmp = image->width;
+ image->width = image->height;
+ image->height = tmp;
+ image->dx = info->var.xres - image->height;
+ fb_rotate_logo_cw(image->data, dst, image->width,
+ image->height);
+ } else if (rotate == FB_ROTATE_CCW) {
+ tmp = image->width;
+ image->width = image->height;
+ image->height = tmp;
+ image->dy = info->var.yres - image->width;
+ fb_rotate_logo_ccw(image->data, dst, image->width,
+ image->height);
+ }
+
+ image->data = dst;
+}
+
+static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
+ int rotate)
+{
+ int x;
+
+ if (rotate == FB_ROTATE_UR) {
+ for (x = 0; x < num_online_cpus() &&
+ x * (fb_logo.logo->width + 8) <=
+ info->var.xres - fb_logo.logo->width; x++) {
+ info->fbops->fb_imageblit(info, image);
+ image->dx += fb_logo.logo->width + 8;
+ }
+ } else if (rotate == FB_ROTATE_UD) {
+ for (x = 0; x < num_online_cpus() &&
+ x * (fb_logo.logo->width + 8) <=
+ info->var.xres - fb_logo.logo->width; x++) {
+ info->fbops->fb_imageblit(info, image);
+ image->dx -= fb_logo.logo->width + 8;
+ }
+ } else if (rotate == FB_ROTATE_CW) {
+ for (x = 0; x < num_online_cpus() &&
+ x * (fb_logo.logo->width + 8) <=
+ info->var.yres - fb_logo.logo->width; x++) {
+ info->fbops->fb_imageblit(info, image);
+ image->dy += fb_logo.logo->width + 8;
+ }
+ } else if (rotate == FB_ROTATE_CCW) {
+ for (x = 0; x < num_online_cpus() &&
+ x * (fb_logo.logo->width + 8) <=
+ info->var.yres - fb_logo.logo->width; x++) {
+ info->fbops->fb_imageblit(info, image);
+ image->dy -= fb_logo.logo->width + 8;
+ }
+ }
+}
+
+int fb_prepare_logo(struct fb_info *info, int rotate)
{
int depth = fb_get_color_depth(&info->var, &info->fix);
+ int yres;
memset(&fb_logo, 0, sizeof(struct logo_data));
@@ -358,10 +453,16 @@ int fb_prepare_logo(struct fb_info *info)
/* Return if no suitable logo was found */
fb_logo.logo = fb_find_logo(depth);
- if (!fb_logo.logo || fb_logo.logo->height > info->var.yres) {
+ if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD)
+ yres = info->var.yres;
+ else
+ yres = info->var.xres;
+
+ if (fb_logo.logo && fb_logo.logo->height > yres) {
fb_logo.logo = NULL;
return 0;
}
+
/* What depth we asked for might be different from what we get */
if (fb_logo.logo->type == LINUX_LOGO_CLUT224)
fb_logo.depth = 8;
@@ -372,12 +473,11 @@ int fb_prepare_logo(struct fb_info *info)
return fb_logo.logo->height;
}
-int fb_show_logo(struct fb_info *info)
+int fb_show_logo(struct fb_info *info, int rotate)
{
u32 *palette = NULL, *saved_pseudo_palette = NULL;
- unsigned char *logo_new = NULL;
+ unsigned char *logo_new = NULL, *logo_rotate = NULL;
struct fb_image image;
- int x;
/* Return if the frame buffer is not mapped or suspended */
if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING)
@@ -417,25 +517,30 @@ int fb_show_logo(struct fb_info *info)
fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth);
}
+ image.dx = 0;
+ image.dy = 0;
image.width = fb_logo.logo->width;
image.height = fb_logo.logo->height;
- image.dy = 0;
- for (x = 0; x < num_online_cpus() * (fb_logo.logo->width + 8) &&
- x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) {
- image.dx = x;
- info->fbops->fb_imageblit(info, &image);
+ if (rotate) {
+ logo_rotate = kmalloc(fb_logo.logo->width *
+ fb_logo.logo->height, GFP_KERNEL);
+ if (logo_rotate)
+ fb_rotate_logo(info, logo_rotate, &image, rotate);
}
-
+
+ fb_do_show_logo(info, &image, rotate);
+
kfree(palette);
if (saved_pseudo_palette != NULL)
info->pseudo_palette = saved_pseudo_palette;
kfree(logo_new);
+ kfree(logo_rotate);
return fb_logo.logo->height;
}
#else
-int fb_prepare_logo(struct fb_info *info) { return 0; }
-int fb_show_logo(struct fb_info *info) { return 0; }
+int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; }
+int fb_show_logo(struct fb_info *info, int rotate) { return 0; }
#endif /* CONFIG_LOGO */
static int fbmem_read_proc(char *buf, char **start, off_t offset,
@@ -829,18 +934,154 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
}
#ifdef CONFIG_COMPAT
+struct fb_fix_screeninfo32 {
+ char id[16];
+ compat_caddr_t smem_start;
+ u32 smem_len;
+ u32 type;
+ u32 type_aux;
+ u32 visual;
+ u16 xpanstep;
+ u16 ypanstep;
+ u16 ywrapstep;
+ u32 line_length;
+ compat_caddr_t mmio_start;
+ u32 mmio_len;
+ u32 accel;
+ u16 reserved[3];
+};
+
+struct fb_cmap32 {
+ u32 start;
+ u32 len;
+ compat_caddr_t red;
+ compat_caddr_t green;
+ compat_caddr_t blue;
+ compat_caddr_t transp;
+};
+
+static int fb_getput_cmap(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct fb_cmap_user __user *cmap;
+ struct fb_cmap32 __user *cmap32;
+ __u32 data;
+ int err;
+
+ cmap = compat_alloc_user_space(sizeof(*cmap));
+ cmap32 = compat_ptr(arg);
+
+ if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32)))
+ return -EFAULT;
+
+ if (get_user(data, &cmap32->red) ||
+ put_user(compat_ptr(data), &cmap->red) ||
+ get_user(data, &cmap32->green) ||
+ put_user(compat_ptr(data), &cmap->green) ||
+ get_user(data, &cmap32->blue) ||
+ put_user(compat_ptr(data), &cmap->blue) ||
+ get_user(data, &cmap32->transp) ||
+ put_user(compat_ptr(data), &cmap->transp))
+ return -EFAULT;
+
+ err = fb_ioctl(inode, file, cmd, (unsigned long) cmap);
+
+ if (!err) {
+ if (copy_in_user(&cmap32->start,
+ &cmap->start,
+ 2 * sizeof(__u32)))
+ err = -EFAULT;
+ }
+ return err;
+}
+
+static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix,
+ struct fb_fix_screeninfo32 __user *fix32)
+{
+ __u32 data;
+ int err;
+
+ err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id));
+
+ data = (__u32) (unsigned long) fix->smem_start;
+ err |= put_user(data, &fix32->smem_start);
+
+ err |= put_user(fix->smem_len, &fix32->smem_len);
+ err |= put_user(fix->type, &fix32->type);
+ err |= put_user(fix->type_aux, &fix32->type_aux);
+ err |= put_user(fix->visual, &fix32->visual);
+ err |= put_user(fix->xpanstep, &fix32->xpanstep);
+ err |= put_user(fix->ypanstep, &fix32->ypanstep);
+ err |= put_user(fix->ywrapstep, &fix32->ywrapstep);
+ err |= put_user(fix->line_length, &fix32->line_length);
+
+ data = (__u32) (unsigned long) fix->mmio_start;
+ err |= put_user(data, &fix32->mmio_start);
+
+ err |= put_user(fix->mmio_len, &fix32->mmio_len);
+ err |= put_user(fix->accel, &fix32->accel);
+ err |= copy_to_user(fix32->reserved, fix->reserved,
+ sizeof(fix->reserved));
+
+ return err;
+}
+
+static int fb_get_fscreeninfo(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ mm_segment_t old_fs;
+ struct fb_fix_screeninfo fix;
+ struct fb_fix_screeninfo32 __user *fix32;
+ int err;
+
+ fix32 = compat_ptr(arg);
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ err = fb_ioctl(inode, file, cmd, (unsigned long) &fix);
+ set_fs(old_fs);
+
+ if (!err)
+ err = do_fscreeninfo_to_user(&fix, fix32);
+
+ return err;
+}
+
static long
fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- int fbidx = iminor(file->f_dentry->d_inode);
+ struct inode *inode = file->f_dentry->d_inode;
+ int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
struct fb_ops *fb = info->fbops;
- long ret;
+ long ret = -ENOIOCTLCMD;
- if (fb->fb_compat_ioctl == NULL)
- return -ENOIOCTLCMD;
lock_kernel();
- ret = fb->fb_compat_ioctl(file, cmd, arg, info);
+ switch(cmd) {
+ case FBIOGET_VSCREENINFO:
+ case FBIOPUT_VSCREENINFO:
+ case FBIOPAN_DISPLAY:
+ case FBIOGET_CON2FBMAP:
+ case FBIOPUT_CON2FBMAP:
+ arg = (unsigned long) compat_ptr(arg);
+ case FBIOBLANK:
+ ret = fb_ioctl(inode, file, cmd, arg);
+ break;
+
+ case FBIOGET_FSCREENINFO:
+ ret = fb_get_fscreeninfo(inode, file, cmd, arg);
+ break;
+
+ case FBIOGETCMAP:
+ case FBIOPUTCMAP:
+ ret = fb_getput_cmap(inode, file, cmd, arg);
+ break;
+
+ default:
+ if (fb->fb_compat_ioctl)
+ ret = fb->fb_compat_ioctl(file, cmd, arg, info);
+ break;
+ }
unlock_kernel();
return ret;
}
@@ -1215,6 +1456,28 @@ int fb_new_modelist(struct fb_info *info)
return err;
}
+/**
+ * fb_con_duit - user<->fbcon passthrough
+ * @info: struct fb_info
+ * @event: notification event to be passed to fbcon
+ * @data: private data
+ *
+ * DESCRIPTION
+ * This function is an fbcon-user event passing channel
+ * which bypasses fbdev. This is hopefully temporary
+ * until a user interface for fbcon is created
+ */
+int fb_con_duit(struct fb_info *info, int event, void *data)
+{
+ struct fb_event evnt;
+
+ evnt.info = info;
+ evnt.data = data;
+
+ return notifier_call_chain(&fb_notifier_list, event, &evnt);
+}
+EXPORT_SYMBOL(fb_con_duit);
+
static char *video_options[FB_MAX];
static int ofonly;
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 007c8e9b2b3..08dac9580d1 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -213,6 +213,70 @@ static ssize_t show_bpp(struct class_device *class_device, char *buf)
return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.bits_per_pixel);
}
+static ssize_t store_rotate(struct class_device *class_device, const char *buf,
+ size_t count)
+{
+ struct fb_info *fb_info = class_get_devdata(class_device);
+ struct fb_var_screeninfo var;
+ char **last = NULL;
+ int err;
+
+ var = fb_info->var;
+ var.rotate = simple_strtoul(buf, last, 0);
+
+ if ((err = activate(fb_info, &var)))
+ return err;
+
+ return count;
+}
+
+
+static ssize_t show_rotate(struct class_device *class_device, char *buf)
+{
+ struct fb_info *fb_info = class_get_devdata(class_device);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->var.rotate);
+}
+
+static ssize_t store_con_rotate(struct class_device *class_device,
+ const char *buf, size_t count)
+{
+ struct fb_info *fb_info = class_get_devdata(class_device);
+ int rotate;
+ char **last = NULL;
+
+ acquire_console_sem();
+ rotate = simple_strtoul(buf, last, 0);
+ fb_con_duit(fb_info, FB_EVENT_SET_CON_ROTATE, &rotate);
+ release_console_sem();
+ return count;
+}
+
+static ssize_t store_con_rotate_all(struct class_device *class_device,
+ const char *buf, size_t count)
+{
+ struct fb_info *fb_info = class_get_devdata(class_device);
+ int rotate;
+ char **last = NULL;
+
+ acquire_console_sem();
+ rotate = simple_strtoul(buf, last, 0);
+ fb_con_duit(fb_info, FB_EVENT_SET_CON_ROTATE_ALL, &rotate);
+ release_console_sem();
+ return count;
+}
+
+static ssize_t show_con_rotate(struct class_device *class_device, char *buf)
+{
+ struct fb_info *fb_info = class_get_devdata(class_device);
+ int rotate;
+
+ acquire_console_sem();
+ rotate = fb_con_duit(fb_info, FB_EVENT_GET_CON_ROTATE, NULL);
+ release_console_sem();
+ return snprintf(buf, PAGE_SIZE, "%d\n", rotate);
+}
+
static ssize_t store_virtual(struct class_device *class_device,
const char * buf, size_t count)
{
@@ -440,6 +504,9 @@ static struct class_device_attribute class_device_attrs[] = {
__ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),
__ATTR(name, S_IRUGO, show_name, NULL),
__ATTR(stride, S_IRUGO, show_stride, NULL),
+ __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
+ __ATTR(con_rotate, S_IRUGO|S_IWUSR, show_con_rotate, store_con_rotate),
+ __ATTR(con_rotate_all, S_IWUSR, NULL, store_con_rotate_all),
};
int fb_init_class_device(struct fb_info *fb_info)
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 0799b999b31..427689e584d 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -122,7 +122,6 @@
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
-#include <linux/version.h>
#include <asm/io.h>
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index ac94c2e5ff8..624c4bc96f0 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -34,7 +34,6 @@
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
-#include <linux/version.h>
#include <asm/io.h>
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 1789a52d776..1da2f84bdc2 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -251,6 +251,10 @@ static const struct fb_videomode modedb[] = {
NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED
+ }, {
+ /* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */
+ NULL, 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6,
+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
},
};
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index f0dfb35e319..09e2f284190 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -1315,10 +1315,14 @@ static void savagefb_set_fix(struct fb_info *info)
info->fix.line_length = info->var.xres_virtual *
info->var.bits_per_pixel / 8;
- if (info->var.bits_per_pixel == 8)
+ if (info->var.bits_per_pixel == 8) {
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
- else
+ info->fix.xpanstep = 4;
+ } else {
info->fix.visual = FB_VISUAL_TRUECOLOR;
+ info->fix.xpanstep = 2;
+ }
+
}
#if defined(CONFIG_FB_SAVAGE_ACCEL)
@@ -1363,7 +1367,6 @@ static int savagefb_set_par (struct fb_info *info)
par->minClock = 10000;
savagefb_set_par_int (par);
- savagefb_update_start (par, var);
fb_set_cmap (&info->cmap, info);
savagefb_set_fix(info);
savagefb_set_clip(info);
@@ -1873,7 +1876,6 @@ static int __devinit savage_init_fb_info (struct fb_info *info,
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.type_aux = 0;
- info->fix.xpanstep = 2;
info->fix.ypanstep = 1;
info->fix.ywrapstep = 0;
info->fix.accel = id->driver_data;
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index 690bb6fe828..226ae8a8848 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -21,6 +21,7 @@
#include <linux/fb.h>
#include <linux/ioport.h>
#include <linux/init.h>
+#include <linux/platform_device.h>
#include <asm/io.h>
#include <video/vga.h>
@@ -51,35 +52,33 @@
* card parameters
*/
-static struct fb_info vga16fb;
-
-static struct vga16fb_par {
+struct vga16fb_par {
/* structure holding original VGA register settings when the
screen is blanked */
struct {
- unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
- unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
- unsigned char CrtMiscIO; /* Miscellaneous register */
- unsigned char HorizontalTotal; /* CRT-Controller:00h */
- unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
- unsigned char StartHorizRetrace; /* CRT-Controller:04h */
- unsigned char EndHorizRetrace; /* CRT-Controller:05h */
- unsigned char Overflow; /* CRT-Controller:07h */
- unsigned char StartVertRetrace; /* CRT-Controller:10h */
- unsigned char EndVertRetrace; /* CRT-Controller:11h */
- unsigned char ModeControl; /* CRT-Controller:17h */
- unsigned char ClockingMode; /* Seq-Controller:01h */
+ unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
+ unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
+ unsigned char CrtMiscIO; /* Miscellaneous register */
+ unsigned char HorizontalTotal; /* CRT-Controller:00h */
+ unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
+ unsigned char StartHorizRetrace;/* CRT-Controller:04h */
+ unsigned char EndHorizRetrace; /* CRT-Controller:05h */
+ unsigned char Overflow; /* CRT-Controller:07h */
+ unsigned char StartVertRetrace; /* CRT-Controller:10h */
+ unsigned char EndVertRetrace; /* CRT-Controller:11h */
+ unsigned char ModeControl; /* CRT-Controller:17h */
+ unsigned char ClockingMode; /* Seq-Controller:01h */
} vga_state;
struct vgastate state;
atomic_t ref_count;
int palette_blanked, vesa_blanked, mode, isVGA;
u8 misc, pel_msk, vss, clkdiv;
u8 crtc[VGA_CRT_C];
-} vga16_par;
+};
/* --------------------------------------------------------------------- */
-static struct fb_var_screeninfo vga16fb_defined = {
+static struct fb_var_screeninfo vga16fb_defined __initdata = {
.xres = 640,
.yres = 480,
.xres_virtual = 640,
@@ -205,7 +204,7 @@ static inline void setindex(int index)
static void vga16fb_pan_var(struct fb_info *info,
struct fb_var_screeninfo *var)
{
- struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+ struct vga16fb_par *par = info->par;
u32 xoffset, pos;
xoffset = var->xoffset;
@@ -300,7 +299,7 @@ static void vga16fb_clock_chip(struct vga16fb_par *par,
static int vga16fb_open(struct fb_info *info, int user)
{
- struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+ struct vga16fb_par *par = info->par;
int cnt = atomic_read(&par->ref_count);
if (!cnt) {
@@ -315,7 +314,7 @@ static int vga16fb_open(struct fb_info *info, int user)
static int vga16fb_release(struct fb_info *info, int user)
{
- struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+ struct vga16fb_par *par = info->par;
int cnt = atomic_read(&par->ref_count);
if (!cnt)
@@ -330,7 +329,7 @@ static int vga16fb_release(struct fb_info *info, int user)
static int vga16fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
- struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+ struct vga16fb_par *par = info->par;
u32 xres, right, hslen, left, xtotal;
u32 yres, lower, vslen, upper, ytotal;
u32 vxres, xoffset, vyres, yoffset;
@@ -535,7 +534,7 @@ static int vga16fb_check_var(struct fb_var_screeninfo *var,
static int vga16fb_set_par(struct fb_info *info)
{
- struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+ struct vga16fb_par *par = info->par;
u8 gdc[VGA_GFX_C];
u8 seq[VGA_SEQ_C];
u8 atc[VGA_ATT_C];
@@ -677,7 +676,7 @@ static int vga16fb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
{
- struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+ struct vga16fb_par *par = info->par;
int gray;
/*
@@ -850,7 +849,7 @@ static void vga_pal_blank(void)
/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
static int vga16fb_blank(int blank, struct fb_info *info)
{
- struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+ struct vga16fb_par *par = info->par;
switch (blank) {
case FB_BLANK_UNBLANK: /* Unblank */
@@ -1201,7 +1200,7 @@ static void vga_imageblit_expand(struct fb_info *info, const struct fb_image *im
{
char __iomem *where = info->screen_base + (image->dx/8) +
image->dy * info->fix.line_length;
- struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+ struct vga16fb_par *par = info->par;
char *cdat = (char *) image->data;
char __iomem *dst;
int x, y;
@@ -1266,7 +1265,7 @@ static void vga_imageblit_color(struct fb_info *info, const struct fb_image *ima
/*
* Draw logo
*/
- struct vga16fb_par *par = (struct vga16fb_par *) info->par;
+ struct vga16fb_par *par = info->par;
char __iomem *where =
info->screen_base + image->dy * info->fix.line_length +
image->dx/8;
@@ -1343,89 +1342,141 @@ static int vga16fb_setup(char *options)
}
#endif
-static int __init vga16fb_init(void)
+static int __init vga16fb_probe(struct device *device)
{
+ struct platform_device *dev = to_platform_device(device);
+ struct fb_info *info;
+ struct vga16fb_par *par;
int i;
- int ret;
-#ifndef MODULE
- char *option = NULL;
+ int ret = 0;
- if (fb_get_options("vga16fb", &option))
- return -ENODEV;
-
- vga16fb_setup(option);
-#endif
printk(KERN_DEBUG "vga16fb: initializing\n");
+ info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev);
+
+ if (!info) {
+ ret = -ENOMEM;
+ goto err_fb_alloc;
+ }
/* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
+ info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS);
- vga16fb.screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS);
- if (!vga16fb.screen_base) {
+ if (!info->screen_base) {
printk(KERN_ERR "vga16fb: unable to map device\n");
ret = -ENOMEM;
goto err_ioremap;
}
- printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.screen_base);
- vga16_par.isVGA = ORIG_VIDEO_ISVGA;
- vga16_par.palette_blanked = 0;
- vga16_par.vesa_blanked = 0;
+ printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
+ par = info->par;
- i = vga16_par.isVGA? 6 : 2;
+ par->isVGA = ORIG_VIDEO_ISVGA;
+ par->palette_blanked = 0;
+ par->vesa_blanked = 0;
+
+ i = par->isVGA? 6 : 2;
vga16fb_defined.red.length = i;
vga16fb_defined.green.length = i;
vga16fb_defined.blue.length = i;
/* name should not depend on EGA/VGA */
- vga16fb.fbops = &vga16fb_ops;
- vga16fb.var = vga16fb_defined;
- vga16fb.fix = vga16fb_fix;
- vga16fb.par = &vga16_par;
- vga16fb.flags = FBINFO_FLAG_DEFAULT |
+ info->fbops = &vga16fb_ops;
+ info->var = vga16fb_defined;
+ info->fix = vga16fb_fix;
+ info->flags = FBINFO_FLAG_DEFAULT |
FBINFO_HWACCEL_YPAN;
- i = (vga16fb_defined.bits_per_pixel == 8) ? 256 : 16;
- ret = fb_alloc_cmap(&vga16fb.cmap, i, 0);
+ i = (info->var.bits_per_pixel == 8) ? 256 : 16;
+ ret = fb_alloc_cmap(&info->cmap, i, 0);
if (ret) {
printk(KERN_ERR "vga16fb: unable to allocate colormap\n");
ret = -ENOMEM;
goto err_alloc_cmap;
}
- if (vga16fb_check_var(&vga16fb.var, &vga16fb)) {
+ if (vga16fb_check_var(&info->var, info)) {
printk(KERN_ERR "vga16fb: unable to validate variable\n");
ret = -EINVAL;
goto err_check_var;
}
- vga16fb_update_fix(&vga16fb);
+ vga16fb_update_fix(info);
- if (register_framebuffer(&vga16fb) < 0) {
+ if (register_framebuffer(info) < 0) {
printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
ret = -EINVAL;
goto err_check_var;
}
printk(KERN_INFO "fb%d: %s frame buffer device\n",
- vga16fb.node, vga16fb.fix.id);
+ info->node, info->fix.id);
+ dev_set_drvdata(device, info);
return 0;
err_check_var:
- fb_dealloc_cmap(&vga16fb.cmap);
+ fb_dealloc_cmap(&info->cmap);
err_alloc_cmap:
- iounmap(vga16fb.screen_base);
+ iounmap(info->screen_base);
err_ioremap:
+ framebuffer_release(info);
+ err_fb_alloc:
+ return ret;
+}
+
+static int vga16fb_remove(struct device *device)
+{
+ struct fb_info *info = dev_get_drvdata(device);
+
+ if (info) {
+ unregister_framebuffer(info);
+ iounmap(info->screen_base);
+ fb_dealloc_cmap(&info->cmap);
+ /* XXX unshare VGA regions */
+ framebuffer_release(info);
+ }
+
+ return 0;
+}
+
+static struct device_driver vga16fb_driver = {
+ .name = "vga16fb",
+ .bus = &platform_bus_type,
+ .probe = vga16fb_probe,
+ .remove = vga16fb_remove,
+};
+
+static struct platform_device vga16fb_device = {
+ .name = "vga16fb",
+};
+
+static int __init vga16fb_init(void)
+{
+ int ret;
+#ifndef MODULE
+ char *option = NULL;
+
+ if (fb_get_options("vga16fb", &option))
+ return -ENODEV;
+
+ vga16fb_setup(option);
+#endif
+ ret = driver_register(&vga16fb_driver);
+
+ if (!ret) {
+ ret = platform_device_register(&vga16fb_device);
+ if (ret)
+ driver_unregister(&vga16fb_driver);
+ }
+
return ret;
}
static void __exit vga16fb_exit(void)
{
- unregister_framebuffer(&vga16fb);
- iounmap(vga16fb.screen_base);
- fb_dealloc_cmap(&vga16fb.cmap);
- /* XXX unshare VGA regions */
+ platform_device_unregister(&vga16fb_device);
+ driver_unregister(&vga16fb_driver);
}
MODULE_LICENSE("GPL");
diff --git a/drivers/video/vgastate.c b/drivers/video/vgastate.c
index ca92940f394..d9e01daee63 100644
--- a/drivers/video/vgastate.c
+++ b/drivers/video/vgastate.c
@@ -485,11 +485,6 @@ int restore_vga (struct vgastate *state)
return 0;
}
-#ifdef MODULE
-int init_module(void) { return 0; };
-void cleanup_module(void) {};
-#endif
-
EXPORT_SYMBOL(save_vga);
EXPORT_SYMBOL(restore_vga);